0

现在我有一个 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 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语句后,发现 Fortran 代码运行良好 if ix<=632, iy<=632, iz<=632. 如果它们大于 632,runtime error就会出现。我应该如何纠正这个错误,以便dens可以读取所有 1024^3 元素?

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


补充

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

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

4

1 回答 1

1

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

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

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

看这个例子:

我在 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,它是字节数数据,然后在最后重复该值。

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

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

于 2020-09-17T01:39:21.563 回答