我正在尝试使用FortranFile来获取我可以在我用F95编写的模拟代码中使用的输出。我遇到了让fortranfile正常工作的麻烦。也许是因为我不明白它是如何运作的。这是我的问题:
如果我想使用FortranFile编写一维数组,它可以正常工作:
nx = 128
bxo = np.zeros(nx, dtype=float)
bxo = something
import fortranfile as fofi
bxf=fofi.FortranFile('Fbx.dat',mode='w')
bxf.writeReals(bxo,prec='d')
bxf.close()
上面的1D版本就像一个魅力。一旦我尝试为2D阵列做这件事,我就会遇到问题
nx = 128; ny = 128
bxo = np.zeros((nx,ny), dtype=float)
bxo = something
import fortranfile as fofi
bxf=fofi.FortranFile('Fbx.dat',mode='w')
bxf.writeReals(bxo,prec='d')
bxf.close()
当我尝试这样做时,我收到以下错误:
---------------------------------------------------------------------------
error Traceback (most recent call last)
/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/site-packages/IPython/utils/py3compat.py in execfile(fname, *where)
173 else:
174 filename = fname
--> 175 __builtin__.execfile(filename, *where)
/Users/parashar/Dropbox/sandbox/test2d.py in <module>()
130 vyf=fofi.FortranFile('Fvy.dat',mode='w')
131 vzf=fofi.FortranFile('Fvz.dat',mode='w')
--> 132 bxf.writeReals(bxo,prec='d')
133 byf.writeReals(byo,prec='d')
134 bzf.writeReals(bzo,prec='d')
/Users/parashar/Dropbox/sandbox/fortranfile.py in writeReals(self, reals, prec)
215 _fmt = self.ENDIAN + prec
216 for r in reals:
--> 217 self.write(struct.pack(_fmt,r))
218 self._write_check(length_bytes)
219
error: required argument is not a float
任何想法可能会发生什么?
谢谢!
答案 0 :(得分:1)
我喜欢Emmet的建议,但鉴于我对python的了解非常基础,对于一个短暂的目标来说,这需要付出很多努力。我刚刚意识到我可以稍微不同的方式处理这种情况。
Fortran中的直接访问文件没有通常未格式化的fortran文件所做的不必要的前导/尾随信息。因此,处理Fortran和Python之间交换的无格式数据的最简单方法是将文件视为Fortran中的直接访问。以下是我们如何将数据用于/来自python / fortran的示例。
Python代码:
import numpy as np
nx=128; ny=128;
bxo=np.zeros((nx,ny),dtype=float)
bxo=something
bxf=open('Fbx.dat',mode='wb')
np.transpose(bxo).tofile(bxf) # We transpose the array to map indices
# from python to fortran properly
bxo.close()
Fortran代码:
program test
implicit none
double precision, dimension(128,128) :: bx
integer :: NNN, i, j
inquire(iolength=NNN) bx
open(unit=23,file='Fbx.dat',form='unformatted',status='old',&
access='direct',recl=NNN)
read(23,rec=1) bx
close(23)
! Write it out to a text file to test it
! by plotting in gnuplot
do i=1,128; do j=1,128
write(23,*) i,j,bx(i,j)
enddo; enddo
end
因为我们使用标准二进制格式来读/写数据,所以与FortranFile方法不同,此方法适用于任何大小的数组。
我已经意识到,通过坚持使用Fortran中的直接访问文件,我们可以与其他语言实现更广泛的兼容性,例如Python,IDL等。这样我们就不必担心奇怪的前导跟踪标记,endian-ness等。
我希望在我的情况下这也可以帮助别人。
答案 1 :(得分:0)
我从来没有同时使用Fortran和Python做任何事情,并且对fortranfile.py一无所知,但我最好的猜测是fortranfile不是numpy-aware。
当您使用1D numpy数组或Python数组,列表等时,堆栈跟踪的最后部分中的迭代表明它期望可迭代的数字(“for r in reals”),而当您尝试序列化一个2D numpy数组,我不确定它得到了什么(即“r”到底是什么),可能是迭代器的迭代,或者是一维迭代的1D数组。简而言之,'r'不仅仅是预期的数字(“必需参数不是浮点数”),而是其他东西(如1D数组,列表等)。
我会试一试看看fortranfile中是否有替换writeReals()的方法,如果没有,那么可以使用一些copypasta来处理2D数组。
我首先在“self.write()”行(217)之前输入诊断打印,告诉你实际上是什么'r',因为它不是预期的浮点数。