En ce qui concerne l'entrée et la sortie de python <-> fortran, il est difficile de trouver une description cohérente sur Internet, j'ai donc décidé de la résumer pour autant que je sache.
En passant, «np.savez» et «np.load» sont recommandés pour l'entrée / sortie de données entre les pythons.
Données de sortie selon la procédure suivante
reshape
tofile
Exemple de code python qui produit des nombres réels 3D double précision avec petit boutien
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')
Pour lire ceci avec fortran, procédez comme suit. Supposons que l'ordinateur que vous utilisez soit un peu endian. ʻOpen dans fortran requiert ʻ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
Si vous souhaitez échanger des données big endian, utilisez du code python
endian='>'
Vous pouvez le changer en. Cette variable ʻendian contrôle comment convertir en binaire avec ʻas type
Dans le code fortran
open(newunit=idf, file='test.dat',form='unformatted',access='stream',convert='big_endian')
Et. Si vous voulez sortir / entrer avec une précision unique, réécrivez le code python comme suit
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')
Modification des parties de np.ones
et de ʻas type` pour gérer la simple précision.
Le code fortran correspondant ressemble à ceci:
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
Seule la partie de real (KIND (0.e0))
a été modifiée.
Si vous souhaitez générer plusieurs tableaux dans un fichier, suivez les étapes ci-dessous.
np.array
reshape
pour créer un tableau unidimensionnel.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')
Le code fortran à lire est
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
Devrait être
D'autre part, lors de la sortie de tableaux de tailles différentes
reshape
pour créer un tableau unidimensionnelnp.concatenate
pour organiser le tableau
Il vous suffit de suivre la procédureLe code python ressemble à ceci
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')
Lors de la lecture de fortran, c'est la même chose qu'avant, mais procédez comme suit.
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
La méthode ci-dessus est plus simple pour le code python, mais si vous n'utilisez pas ʻaccess = 'stream'dans fortran, vous devrez éditer vous-même l'en-tête de données. C'est
scipy.io.FortranFile` qui ajuste bien cette partie.
Le code Python ressemble à ceci
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()
Le code Fortran pour la lecture est
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
Ca devrait être fait.
La sortie de plusieurs tableaux est plus facile que d'utiliser 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()
Et ajoutez-le simplement à l'argument de write_record
.
Code de lecture Fortran
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
Tout ce que vous avez à faire est de disposer les tableaux côte à côte.
Cependant, si vous regardez le site Web scipy
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.
c'est écrit comme ça. Le format fortran semble être fortement dépendant du compilateur, et la méthode utilisant numpy semble être recommandée.
Afin de lire les données fortran avec numpy, il est recommandé de sortir avec ʻaccess = 'stream'` (ce n'est pas essentiel car vous pouvez ajuster vous-même l'en-tête, etc.).
Définir un tableau avec fortran et sortie
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
Le moyen le plus simple de le charger avec python est d'utiliser 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()
Même si vous utilisez np.fromfile
, vous pouvez utiliser np.dtype
pour une lecture plus polyvalente. Par exemple, procédez comme suit
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()
Il est plus pratique d'utiliser np.dtype
pour traiter plusieurs tableaux.
Tout d'abord, fortran génère plusieurs tableaux dans un fichier, comme illustré ci-dessous.
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
Pour charger ceci avec 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()
Il est facile d'utiliser scipy.io.FortranFile
pour lire les données fortran sans ʻaccess = 'stream'`.
La sortie de fortran est la suivante
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
Le code python pour lire ceci ressemble à ceci
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()
Il peut également être lu en utilisant np.dtype
comme suit:
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