In Bezug auf die Eingabe und Ausgabe von Python <-> fortran ist es schwierig, eine zusammenhängende Beschreibung im Internet zu finden, daher habe ich beschlossen, sie meines Wissens zusammenzufassen.
Abgesehen davon werden "np.savez" und "np.load" für die Dateneingabe / -ausgabe zwischen Pythons empfohlen.
Daten wie folgt ausgeben
astype in binär konvertierentofileBeispiel für Python-Code, der reelle 3D-Zahlen mit doppelter Genauigkeit und Little Endian ausgibt
import numpy as np
ix, jx, kx = 3, 4, 5
endian='<'
a = np.ones((ix,jx,kx))
a.reshape([ix*jx*kx],order='F').astype(endian+'d').tofile('test.dat')
Um dies mit fortran zu lesen, gehen Sie wie folgt vor. Angenommen, der von Ihnen verwendete Computer ist ein kleines Endian. Open in fortran erfordert access = 'stream'
program test
  implicit none
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a
  open(newunit=idf, file='test.dat',form='unformatted',access='stream')
  read(idf) a
  close(idf)
  
  stop
end program test
Wenn Sie Big-Endian-Daten austauschen möchten, verwenden Sie Python-Code
endian='>'
Sie können es in ändern. Diese "endian" -Variable steuert, wie mit "astype" in eine Binärdatei konvertiert wird
Im fortran Code
  open(newunit=idf, file='test.dat',form='unformatted',access='stream',convert='big_endian')
Und. Wenn Sie mit einfacher Genauigkeit ausgeben / eingeben möchten, schreiben Sie den Python-Code wie folgt neu
import numpy as np
ix, jx, kx = 3, 4, 5
endian='<'
a = np.ones((ix,jx,kx),dtype=np.float32)
a.reshape([ix*jx*kx],order='F').astype(endian+'f').tofile('test.dat')
Die Teile von "np.ones" und "astype" wurden geändert, um eine einfache Genauigkeit zu erzielen.
Der entsprechende fortran-Code sieht folgendermaßen aus:
program test
  implicit none
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.e0)), dimension(ix,jx,kx) :: a
  open(newunit=idf, file='test.dat',form='unformatted',access='stream')
  read(idf) a
  close(idf)
  
  stop
end program test
Nur der Teil von "real (KIND (0.e0))" wurde geändert.
Wenn Sie mehrere Arrays in eine Datei ausgeben möchten, führen Sie die folgenden Schritte aus.
np.arrayT aus.import numpy as np
ix, jx, kx = 3, 4, 5
endian='<'
a = np.ones((ix,jx,kx),dtype=np.float32)
b = np.ones((ix,jx,kx),dtype=np.float32)*2
c = np.ones((ix,jx,kx),dtype=np.float32)*3
np.array([a,b,c]).T.reshape([3*ix*jx*kx],order='F').astype(endian+'f').tofile('test.dat')
Der zu lesende fortran-Code lautet
program test
  implicit none
  integer :: i,j,k
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.e0)), dimension(ix,jx,kx) :: a,b,c
  open(newunit=idf, file='test.dat',form='unformatted',access='stream')
  read(idf) a,b,c
  close(idf)
  
  stop
end program test
Sollte sein
Zum anderen bei der Ausgabe von Arrays unterschiedlicher Größe
np.concatenate, um das Array zu organisieren
Sie müssen nur die Prozedur befolgenDer Python-Code sieht so aus
import numpy as np
ix, jx, kx = 3, 4, 5
lx, mx = 2, 4
endian='<'
a = np.ones((ix,jx,kx))
b = np.ones((lx,mx))*2
a1 = a.reshape([ix*jx*kx],order='F')
b1 = b.reshape([lx*mx],order='F')
np.concatenate([a1,b1]).astype(endian+'d').tofile('test.dat')
Beim Lesen aus fortran ist es dasselbe wie zuvor, aber gehen Sie wie folgt vor.
program test
  implicit none
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  integer, parameter :: lx = 2, mx = 4
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a
  real(KIND(0.d0)), dimension(lx,mx) :: b
  open(newunit=idf, file='test.dat',form='unformatted',access='stream')
  read(idf) a,b
  close(idf)
  
  stop
end program test
Die obige Methode ist für Python-Code einfacher, aber wenn Sie in fortran nicht "access =" stream "" verwenden, müssen Sie den Datenheader selbst bearbeiten.
Es ist scipy.io.FortranFile, das diesen Teil gut anpasst.
Python-Code sieht so aus
import numpy as np
from scipy.io import FortranFile
ix, jx, kx = 3, 4, 5
endian='<'
a = np.ones((ix,jx,kx))
f = FortranFile('test.dat','w')
f.write_record(a)
f.close()
Der Fortran-Code zum Lesen lautet
program test
  implicit none
  integer :: i,j,k
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a
  open(newunit=idf, file='test.dat',form='unformatted')
  read(idf) a
  close(idf)
  
  stop
end program test
Es sollte getan werden.
Die Ausgabe mehrerer Arrays ist einfacher als die Verwendung von Numpy
a = np.ones((ix,jx,kx))
b = np.ones((ix,jx,kx))*2
f = FortranFile('test.dat','w')
f.write_record(a,b)
f.close()
Und fügen Sie es einfach dem Argument "write_record" hinzu. Fortran liest Code
program test
  implicit none
  integer :: i,j,k
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a,b
  open(newunit=idf, file='test.dat',form='unformatted')
  read(idf) a,b
  close(idf)
  
  stop
end program test
Sie müssen lediglich die Arrays so anordnen, dass sie nebeneinander gelesen werden.
Wenn Sie sich jedoch die [scipy-Website] ansehen (https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.FortranFile.html)
Since this is a non-standard file format, whose contents depend on the compiler and the endianness of the machine, caution is advised. Files from gfortran 4.8.0 and gfortran 4.1.2 on x86_64 are known to work.
Consider using Fortran direct-access files or files from the newer Stream I/O, which can be easily read by numpy.fromfile.
es ist so geschrieben. Das fortran-Format scheint stark vom Compiler abhängig zu sein, und die Methode mit numpy scheint empfohlen zu werden.
Um fortran-Daten mit numpy zu lesen, wird empfohlen, mit access = 'stream' auszugeben (dies ist nicht unbedingt erforderlich, da Sie den Header usw. selbst anpassen können).
Definieren Sie ein Array mit fortran und output
program test
  implicit none
  integer :: i,j,k
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a
  a = 1.d0
  
  open(newunit=idf, file='test.dat',form='unformatted',access='stream')
  write(idf) a
  close(idf)
  
  stop
end program test
Der einfachste Weg, es mit Python zu laden, ist die Verwendung von "np.fromfile".
import numpy as np
ix, jx, kx = 3, 4, 5
endian='<'
f = open('test.dat','rb')
a = np.fromfile(f,endian+'d',ix*jx*kx)
a = a.reshape((ix,jx,kx),order='F')
f.close()
Selbst wenn Sie "np.fromfile" verwenden, können Sie "np.dtype" für ein vielseitigeres Lesen verwenden. Gehen Sie beispielsweise wie folgt vor
import numpy as np
ix, jx, kx = 3, 4, 5
endian='<'
f = open('test.dat','rb')
dtype = np.dtype([('a',endian+str(ix*jx*kx)+'d')])
a = np.fromfile(f,dtype=dtype)['a']
a = a.reshape((ix,jx,kx),order='F')
f.close()
Es ist bequemer, "np.dtype" zu verwenden, wenn Sie mit mehreren Arrays arbeiten. Zunächst gibt fortran mehrere Arrays in eine Datei aus, wie unten gezeigt.
program test
  implicit none
  integer :: i,j,k
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a,b
  a = 1.d0
  b = 2.d0
  
  open(newunit=idf, file='test.dat',form='unformatted',access='stream')
  write(idf) a,b
  close(idf)
  
  stop
end program test
So laden Sie dies mit Python:
import numpy as np
ix, jx, kx = 3, 4, 5
endian='<'
f = open('test.dat','rb')
dtype = np.dtype([('a',endian+str(ix*jx*kx)+'d'),('b',endian+str(ix*jx*kx)+'d')])
data = np.fromfile(f,dtype=dtype)
a = data['a'].reshape((ix,jx,kx),order='F')
b = data['b'].reshape((ix,jx,kx),order='F')
f.close()
Es ist einfach, "scipy.io.FortranFile" zu verwenden, um fortran-Daten zu lesen, die "access =" stream "" nicht verwenden.
Die Ausgabe von fortran ist wie folgt
program test
  implicit none
  integer :: i,j,k
  integer :: idf
  integer, parameter :: ix = 3, jx = 4, kx = 5
  real(KIND(0.d0)), dimension(ix,jx,kx) :: a
  a = 1.d0
  
  open(newunit=idf, file='test.dat',form='unformatted')
  write(idf) a
  close(idf)
  
  stop
end program test
Der Python-Code zum Lesen sieht folgendermaßen aus
import numpy as np
from scipy.io import FortranFile
ix, jx, kx = 3, 4, 5
endian='<'
a = np.ones((ix,jx,kx))
b = np.ones((ix,jx,kx))*2
f = FortranFile('test.dat','r')
a = f.read_record(endian+'('+str(ix)+','+str(jx)+','+str(kx)+')d')
f.close()
Es kann auch mit np.dtype wie folgt gelesen werden:
import numpy as np
from scipy.io import FortranFile
ix, jx, kx = 3, 4, 5
endian='<'
a = np.ones((ix,jx,kx))
b = np.ones((ix,jx,kx))*2
f = FortranFile('test.dat','r')
dtype = np.dtype([('a',endian+str(ix*jx*kx)+'d')])
a = f.read_record(dtype=dtype)
a = a['a'].reshape(ix,jx,kx,order='F')
f.close()
Recommended Posts