如何解决“ Fortran运行时错误:I / O在未格式化文件上的记录结束”?

问题描述

现在我有一个1024 * 1024 * 1024数组,其dtype为float32。首先,我将该数组以“ .bigfile”格式保存到一个文件中。然后,通过运行以下代码,将此大文件转换为Fortran无格式文件

with bigfile.File('filename.bigfile') as bf:
    shape = bf['Field'].attrs['ndarray.shape']
    data = bf['Field'][:].reshape(shape)
    np.asfortranarray(data).tofile('filename.dat')

接下来要测试此二进制文件(即“ filename.dat”),我分别通过Python和fortran95读取此文件。 Python代码运行良好,代码段如下所示。

field = np.fromfile('filename.dat',dtype='float32',count=1024*1024*1024)
density_field = field.reshape(1024,1024,1024)

但是,当我运行Fortran读取代码时,发生了Fortran runtime error

 Program readout00
  Implicit None
  Integer,Parameter :: Ng = 1024
  Real,Allocatable,Dimension(:,:,:) :: dens
  Integer :: istat,ix,iy,iz
  ! -------------------------------------------------------------------------
  ! Allocate the arrays for the original simulation data
  ! -------------------------------------------------------------------------
  Allocate(dens(0:Ng-1,0:Ng-1,0:Ng-1),STAT=istat)
  If( istat/=0 ) Stop "Wrong Allocation-1"
  ! -------------------------------------------------------------------------
  Open(10,file="filename.dat",status="old",form="unformatted")
  Read(10) dens
  Close(10)
  Write(*,*) "read-in finished"
  ! -------------------------------------------------------------------------
  Do ix = 0,1
    Do iy = 0,1
      Do iz = 0,1
        Write(*,*) "ix,iz,rho=",dens(ix,iz)
     EndDo
    EndDo
  EndDo
  !--------------------------------------------------------------------------
End Program readout00

错误消息:

At line 13 of file readout00.f90 (unit = 10,file = 'filename.dat')
Fortran runtime error: I/O past end of record on unformatted file



Error termination. Backtrace:
#0  0x7f7d8aff8e3a
#1  0x7f7d8aff9985
#2  0x7f7d8affa13c
#3  0x7f7d8b0c96e0
#4  0x7f7d8b0c59a6
#5  0x400d24
#6  0x400fe1
#7  0x7f7d8a4db730
#8  0x400a58
#9  0xffffffffffffffff

我不明白为什么会出现这些错误

注意:整体操作在LINUX远程服务器中处理。



在反复修改read语句后,我发现如果ix<=632iy<=632iz<=632,则Fortran代码可以正常运行。如果它们大于632,将显示runtime error。我应该如何纠正此错误,以便dens可以读取所有1024 ^ 3个元素?

Read(10) (((dens(ix,iz),ix=0,632),iy=0,iz=0,632)


补充

今天,我在acccess=stream语句中添加一个子句open,在read(10) header之前添加read(10) dens,即

Integer :: header
......
Open(10,&
         form="unformatted",access='stream')
Read(10) header
Read(10) dens

修改后,Fortran代码'readout00.f95'成功读取1024 * 1024 * 1024数组,即dens

为什么原始的'readout00.f95'无法读入dens

解决方法

@IanH已在评论中正确回答了您的问题,或更准确地指出了其他问题中的正确答案。

“无格式”格式仅表示该文件不会被解释为人类可读的文件,但是文件中的数据需要以特定方式进行布局。虽然具体格式不确定,并且取决于编译器和系统,但通常每个记录都有其自己的页眉和页脚,以显示数据的长度。

numpy.asfortanarray根本不影响文件布局,它仅确保数组在内存中的布局与Fortran相同(列主要或第一个索引更改最快),而不是通常(行主要或最后索引更改最快)。

请参见以下示例:

我在python和fortran中创建了相同的数据(类型int16,值0到11),并将其存储在两个文件中,一个是np.asfortranarray.tofile的python版本,另一个是未格式化的Fortran。这些是结果:

使用Python:

0000000 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00
0000010 08 00 09 00 0a 00 0b 00

使用Fortran:

0000000 18 00 00 00 00 00 01 00 02 00 03 00 04 00 05 00
0000010 06 00 07 00 08 00 09 00 0a 00 0b 00 18 00 00 00

在python文件中,“数据”立即开始({00 00代表0,然后01 00代表1,依此类推,直到0b 00代表11),但是在Fortran中,有一个4字节的标头:18 00 00 00或24,它是数据的字节数,然后在末尾重复此值。

当您尝试使用form='unformatted'使用Fortran读取文件时,这是程序希望找到的那种数据,但是那不是您拥有的数据。

解决方案正是您要做的事情:使用流。在流中,程序希望数据连续输入而没有任何标题或元数据。