【问题标题】:How to solve 'Fortran runtime error: I/O past end of record on unformatted file'?如何解决“Fortran 运行时错误:未格式化文件上的 I/O 超过记录结尾”?
【发布时间】:2020-09-13 08:18:25
【问题描述】:

现在我有一个 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代码运行良好,代码sn-p如下所示。

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

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

 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, iy, iz, rho=", ix, iy, iz, dens(ix, iy, 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, iy, iz), ix=0,632), iy=0,632), iz=0,632)


补充

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

Integer :: header
......
Open(10, file="filename.dat", status="old",    &
         form="unformatted", access='stream')
Read(10) header
Read(10) dens

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

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

【问题讨论】:

  • @HighPerformanceMark 那么如何分块读取数组呢?你能更详细地澄清这个问题吗?
  • 对于所有 Fortran 问题,请使用标签 fortran
  • Numpy 不太可能写出必要的记录长度元数据。 stackoverflow.com/a/8751662/1234550 的可能重复项,或无数类似问题。
  • 请解释为什么上一条评论中的链接答案不是您的问题的答案。
  • @StephenWong 请注意,numpy.ndarray.tofile 始终按“C”顺序保存数据,如文档中所述。

标签: python fortran runtime-error binaryfiles allocatable-array


【解决方案1】:

@IanH 在 cmets 中正确回答了您的问题,或者更准确地指出了另一个问题中的正确答案。

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

numpy.asfortanarray 根本不影响文件布局,它只确保内存中数组的布局与 Fortran 相同(列优先,或第一个索引变化最快),而不是通常的(Row-Major 或最后一个索引变化最快)。

看这个例子:

我在 python 和 fortran 中创建了相同的数据(类型 int16,值 0 到 11),并将其存储在两个文件中,python 版本带有 np.asfortranarray.tofile,而 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 读取文件时,这是程序期望找到的数据类型,但不是您拥有的数据。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-11
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 2023-04-05
    • 2016-02-09
    • 1970-01-01
    • 2018-12-16
    相关资源
    最近更新 更多