Fortran的未格式化输入/输出

时间:2013-04-04 22:41:39

标签: python fortran

我正在尝试使用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

任何想法可能会发生什么?

谢谢!

2 个答案:

答案 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',因为它不是预期的浮点数。