Python读取未格式化的直接访问Fortran 90提供了错误的输出

时间:2015-09-02 19:57:03

标签: python file io fortran fortran90

以下是数据的写入方式(浮点数的2-D矩阵。我不确定大小)。

open(unit=51,file='rmsd/'//nn_output,form='unformatted',access='direct',status='replace',&
     recl=Npoints*sizeofreal)

!a bunch of code omitted 

    write(51,rec=idx-nstart+1) (real(dist(jdx)),jdx=1,Npoints)

以下是我尝试阅读该文件的方式,灵感来自对这些类似问题的回答:12

   f = open(inputfilename,'rb')
   field = np.fromfile(f,dtype='float64')

但结果不正确。矩阵的对角线应该是0(或非常接近),因为它是相似矩阵。我尝试了不同的dtype但我仍然无法得到正确的结果。

编辑:这是我得到的输出

array([  1.17610188e+01,   2.45736970e+02,   7.79741823e+02, ...,
         9.52930627e+05,   8.93743127e+05,   7.64186127e+05])

我还没有为重塑而烦恼,因为值的范围应该在0到20之间。

编辑2:这是指向文件前100行的链接: https://drive.google.com/file/d/0B2Mz7CoRS5g5SmRxTUg5X19saGs/view?usp=sharing

编辑3:文件顶部的声明

integer,parameter :: real_kind=8
!valuables for MPI
integer :: comm, nproc, myid, ierr

integer,allocatable :: idneigh(:)
real :: tmp
real,allocatable :: traj(:,:)
real(real_kind),allocatable :: dist(:)
real(real_kind),allocatable :: xx(:,:),yy(:,:),rot(:),weight(:)
character(200) :: nn_traj, nn_output, nn_neigh
integer,parameter :: sizeofreal=4,sizeofinteger=4

1 个答案:

答案 0 :(得分:8)

未格式化的Fortran二进制文件编码记录长度以分隔记录。通常,记录长度将在每个记录之前和之后写入,但是如果内存服务的细节与处理器有关(如果记录没有以这种方式分隔,请参见帖子的后半部分)。查看您发布的文件,如果将前4个字节解释为整数,将剩余字节解释为32位浮点值,则可以得到:

0000000        881505604    7.302916e+00    8.723415e+00    6.914254e+00
0000020     9.826199e+00    7.044637e+00    8.601265e+00    6.629045e+00
0000040     6.103047e+00    9.476192e+00    9.326468e+00    6.535160e+00
0000060     8.904651e+00    4.710213e+00    6.534080e+00    1.156603e+01
0000100     1.046533e+01    9.343380e+00    8.574672e+00    7.498291e+00
0000120     1.071538e+01    7.138038e+00    5.898036e+00    6.182026e+00
0000140     7.037515e+00    6.418780e+00    6.294755e+00    8.327971e+00
0000160     6.796582e+00    7.397069e+00    6.493272e+00    1.126087e+01
0000200     6.467663e+00    7.178994e+00    7.867798e+00    5.921878e+00

如果您寻求超过此记录长度字段,您可以将记录的其余部分读取为python变量。您将需要指定正确的字节数,因为在记录末尾将有另一个记录长度,并且将以错误的值读入数组。 881505604暗示您的NPoints是220376401(如果不是这样,那么请看帖子的后半部分,这可能是数据而不是记录长度。)

您可以使用以下命令在python中读取此数据:

f = open('fortran_output', 'rb')
recl = np.fromfile(f, dtype='int32', count=1)
f.seek(4)
field = np.fromfile(f, dtype='float32')

print('Record length=',recl)
print(field)

这将读取记录长度,向前搜索4个字节,并将文件的其余部分读入float32数组。如前所述,您将希望为读取指定适当的count=以不进入结束记录字段。

此程序为您的输入文件输出以下内容:

Record length= [881505604]
[ 7.30291557  8.72341537  6.91425419 ...,  6.4588294   6.53710747
  6.01582813]

数组中的所有32位实数都在0到20之间,因为您建议适合您的数据,所以这看起来就像你想要的那样。

但是,如果您的编译器在为未格式化的直接访问文件分隔记录时不编码记录长度,则输出将被解释为32位浮点数:

0000000    2.583639e-07       7.3029156        8.723415        6.914254
0000020        9.826199        7.044637        8.601265        6.629045
0000040        6.103047       9.4761915        9.326468       6.5351596
0000060        8.904651        4.710213         6.53408       11.566033
0000100       10.465328         9.34338        8.574672        7.498291
0000120       10.715377        7.138038       5.8980355        6.182026
0000140       7.0375147         6.41878       6.2947555       8.3279705
0000160       6.7965817       7.3970685       6.4932723       11.260868
0000200        6.467663        7.178994        7.867798       5.9218783
0000220        6.710998         5.71757       6.1372333        5.809089

其中第一个值朝零变小,这可能是合适的,因为你说矩阵对角线应该是0。

要阅读本文,您可以像尝试一样在python中进行读取,但如果文件中有多个记录,则使用count=只读取正确的记录长度是明智的。

使用python代码:

f = open('fortran_output', 'rb')
field = np.fromfile(f, dtype='float32')

print(field)

产生输出

[  2.58363912e-07   7.30291557e+00   8.72341537e+00 ...,   6.45882940e+00
   6.53710747e+00   6.01582813e+00]

匹配解释为32位浮点数的文件输出。

当使用各种gfortran和ifort版本进行测试时,写入的细节通常没有这种输出的记录分隔符,但可能像帖子的前半部分或其他编译器的不同。

我还想重新考虑这个解决方案没有100%置信度的警告,因为我们没有你写入这个文件的数据来验证。您确实拥有该信息,您应该验证生成的数据是否正确。在使用默认标志进行编译时,值得注意的是,ifort记录长度为4字节字,而gfortran为1字节单位。这不会导致输出问题,但如果在ifort中没有得到补偿,那么您的文件将比所需的文件大4倍。您可以使用带有ifort的-assume byterecl来获得以字节为单位的记录长度。

相关问题