读取由Python代码创建的Fortran中的二进制文件

时间:2015-10-26 23:45:52

标签: python fortran binaryfiles

我有一个使用Python代码创建的二进制文件。此代码主要编写一系列任务来预处理一组数据文件。我现在想在Fortran中读取这个二进制文件。二进制文件的内容是简单格式的点坐标,例如:点数,x0,y0,z0,x1,y1,z1,....

这些二进制文件是使用numpy中的'tofile'函数创建的。到目前为止,我在Fortran中有以下代码:

integer:: intValue
double precision:: dblValue
integer:: counter
integer:: check
open(unit=10, file='file.bin', form='unformatted', status='old', access='stream')

counter = 1

do 

  if ( counter == 1 ) then
    read(unit=10, iostat=check) intValue
    if ( check < 0 ) then
      print*,"End Of File"
      stop
    else if ( check > 0 ) then
      print*, "Error Detected"
      stop
    else if ( check == 0 ) then
      counter = counter + 1
      print*, intValue
    end if
  else if ( counter > 1 ) then
    read(unit=10, iostat=check) dblValue
    if ( check < 0 ) then
      print*,"End Of File"
      stop
    else if ( check > 0 ) then
      print*, "Error Detected"
      stop
    else if ( check == 0 ) then
      counter = counter + 1
      print*,dblValue
    end if
  end if

end do

close(unit=10)

遗憾的是,这不起作用,我得到了垃圾数字(例如6.4731191026611484E + 212,2.2844499004808491E-279等)。有人可以指出如何正确地做到这一点吗? 在Python和Fortran之间交换编写和读取二进制文件的好方法也是如此 - 因为这似乎是我的应用程序的要求之一。

谢谢

2 个答案:

答案 0 :(得分:1)

这是一个简单的例子,说明如何将以numpy生成的数据以二进制方式传递给Fortran。

我在sin上计算了[0,2π)的360个值,

#!/usr/bin/env python3
import numpy as np

with open('sin.dat', 'wb') as outfile:
    np.sin(np.arange(0., 2*np.pi, np.pi/180.,
                     dtype=np.float32)).tofile(outfile)

tofile导出到二进制文件'sin.dat',其大小为1440 bytes (360 * sizeof(float32)),使用此Fortran95(gfortran -O3 -Wall -pedantic)程序读取该文件,该程序输出{ {1}}对于[0,2π)中的x,

1. - (val**2 + cos(x)**2)

因此,如果program numpy_import integer, parameter :: REAL_KIND = 4 integer, parameter :: UNIT = 10 integer, parameter :: SAMPLE_LENGTH = 360 real(REAL_KIND), parameter :: PI = acos(-1.) real(REAL_KIND), parameter :: DPHI = PI/180. real(REAL_KIND), dimension(0:SAMPLE_LENGTH-1) :: arr real(REAL_KIND) :: r integer :: i open(UNIT, file="sin.dat", form='unformatted',& access='direct', recl=4) do i = 0,ubound(arr, 1) read(UNIT, rec=i+1, err=100) arr(i) end do do i = 0,ubound(arr, 1) r = 1. - (arr(i)**2. + cos(real(i*DPHI, REAL_KIND))**2) write(*, '(F6.4, " ")', advance='no')& real(int(r*1E6+1)/1E6, REAL_KIND) end do 100 close(UNIT) write(*,*) end program numpy_import ,则数值结果必须以良好的近似值消失为float32类型。

确实:

输出

val == sin(x)

答案 1 :(得分:1)

感谢这个伟大的社区,从我得到的所有建议,以及一点点修修补补,我想我找到了解决这个问题的稳定解决方案,我想与大家分享这些答案。我将在这里提供一个最小的例子,我想从Python将一个可变大小的数组写入二进制文件,并使用Fortran读取它。我假设行数numRows和列数numCols也与完整数组datatArray一起写入。以下Python脚本writeBin.py写入文件:

import numpy as np
# Read in the numRows and numCols value 
# Read in the array values
numRowArr = np.array([numRows], dtype=np.float32)
numColArr = np.array([numCols], dtype=np.float32)
fileObj   = open('pybin.bin', 'wb')
numRowArr.tofile(fileObj)
numColArr.tofile(fileObj)
for i in range(numRows):
    lineArr = dataArray[i,:]
    lineArr.tofile(fileObj)
fileObj.close()

在此之后,从文件中读取数组的fortran代码可以编程如下:

program readBin

    use iso_fortran_env

    implicit none

    integer:: nR, nC, i

    real(kind=real32):: numRowVal, numColVal
    real(kind=real32), dimension(:), allocatable:: rowData
    real(kind=real32), dimension(:,:), allocatable:: fullData

    open(unit=10,file='pybin.bin',form='unformatted',status='old',access='stream')

    read(unit=10) numRowVal
    nR = int(numRowVal)

    read(unit=10) numColVal
    nC = int(numColVal)

    allocate(rowData(nC))
    allocate(fullData(nR,nC))

    do i = 1, nR

        read(unit=10) rowData
        fullData(i,:) = rowData(:)

    end do

    close(unit=10)

end program readBin

我从这个线程的讨论中收集到的主要观点是尽可能地匹配读取和写入,要读取的数据类型的精确规范,它们的编写方式等等。您可能会注意到,这是一个例子,所以可能有些东西在这里和那里都不完美。但是,我现在用它来编写有限元程序,并且网格数据是我使用这个二进制读/写的地方 - 它运行得非常好。

P.S:如果你发现了一些拼写错误,请告诉我,我会马上编辑。

非常感谢。