python file io fortran fortran90

Python lee acceso directo sin formato Fortran 90 da salida incorrecta



file io (1)

Así es como se escriben los datos (es una matriz 2-D de flotadores. No estoy seguro del tamaño).

open(unit=51,file=''rmsd/''//nn_output,form=''unformatted'',access=''direct'',status=''replace'',& recl=Npoints*sizeofreal) !a bunch of code omitted write(51,rec=idx-nstart+1) (real(dist(jdx)),jdx=1,Npoints)

Así es como estoy tratando de leer el archivo, inspirado en la respuesta a estas preguntas similares: 1 , 2 .

f = open(inputfilename,''rb'') field = np.fromfile(f,dtype=''float64'')

Pero el resultado no es correcto. La diagonal de la matriz debe ser 0 (o muy cercana) ya que es una matriz de similitud. dtype diferentes dtype pero aún así no pude obtener un resultado correcto.

EDITAR: aquí está la salida que obtengo

array([ 1.17610188e+01, 2.45736970e+02, 7.79741823e+02, ..., 9.52930627e+05, 8.93743127e+05, 7.64186127e+05])

No me he molestado con la remodelación todavía, ya que los valores deberían oscilar entre 0 y ~ 20.

EDIT 2: Aquí hay un enlace a las primeras 100 líneas del archivo: https://drive.google.com/file/d/0B2Mz7CoRS5g5SmRxTUg5X19saGs/view?usp=sharing

EDIT 3: declaraciones en la parte superior del archivo

integer,parameter :: real_kind=8 !valuables for MPI integer :: comm, nproc, myid, ierr integer,allocatable :: idneigh(:) real :: tmp real,allocatable :: traj(:,:) real(real_kind),allocatable :: dist(:) real(real_kind),allocatable :: xx(:,:),yy(:,:),rot(:),weight(:) character(200) :: nn_traj, nn_output, nn_neigh integer,parameter :: sizeofreal=4,sizeofinteger=4


Los archivos binarios Fortran no formateados codifican la longitud del registro para delimitar los registros. En general, la longitud del registro se escribirá tanto antes como después de cada registro, aunque si la memoria sirve para los detalles de eso dependen del procesador (consulte la segunda mitad de la publicación si los registros no están delimitados de esta manera). Mirando el archivo que publicaste, si interpretas los primeros 4 bytes como un entero y los bytes restantes como valores de punto flotante de 32 bits obtienes:

0000000 881505604 7.302916e+00 8.723415e+00 6.914254e+00 0000020 9.826199e+00 7.044637e+00 8.601265e+00 6.629045e+00 0000040 6.103047e+00 9.476192e+00 9.326468e+00 6.535160e+00 0000060 8.904651e+00 4.710213e+00 6.534080e+00 1.156603e+01 0000100 1.046533e+01 9.343380e+00 8.574672e+00 7.498291e+00 0000120 1.071538e+01 7.138038e+00 5.898036e+00 6.182026e+00 0000140 7.037515e+00 6.418780e+00 6.294755e+00 8.327971e+00 0000160 6.796582e+00 7.397069e+00 6.493272e+00 1.126087e+01 0000200 6.467663e+00 7.178994e+00 7.867798e+00 5.921878e+00

Si busca más allá de este campo de longitud de registro, puede leer el resto del registro en una variable de Python. Deberá especificar la cantidad correcta de bytes porque habrá otra longitud de registro al final del registro y se leerá como un valor incorrecto en su matriz. 881505604 implica que sus NPoints son 220376401 (si esto no es cierto, entonces vea la segunda mitad de la publicación, esto puede ser datos y no una longitud de registro).

Puede leer esta información en python con:

f = open(''fortran_output'', ''rb'') recl = np.fromfile(f, dtype=''int32'', count=1) f.seek(4) field = np.fromfile(f, dtype=''float32'') print(''Record length='',recl) print(field)

Esto lee la longitud del registro, busca 4 bytes hacia adelante y lee el resto del archivo en una matriz float32. Querrá, como se mencionó antes, especificar un count= adecuado count= a la lectura para no ingresar el campo de registro final.

Este programa genera lo siguiente para su archivo de entrada:

Record length= [881505604] [ 7.30291557 8.72341537 6.91425419 ..., 6.4588294 6.53710747 6.01582813]

Todos los reales de 32 bits en la matriz están entre 0 y 20, ya que sugiere que es adecuado para sus datos, por lo que se ve como lo que desea.

Sin embargo, si su compilador no codifica la longitud de registro al delimitar registros para archivos de acceso directo sin formato, entonces la salida se interpreta en cambio como flotantes de 32 bits:

0000000 2.583639e-07 7.3029156 8.723415 6.914254 0000020 9.826199 7.044637 8.601265 6.629045 0000040 6.103047 9.4761915 9.326468 6.5351596 0000060 8.904651 4.710213 6.53408 11.566033 0000100 10.465328 9.34338 8.574672 7.498291 0000120 10.715377 7.138038 5.8980355 6.182026 0000140 7.0375147 6.41878 6.2947555 8.3279705 0000160 6.7965817 7.3970685 6.4932723 11.260868 0000200 6.467663 7.178994 7.867798 5.9218783 0000220 6.710998 5.71757 6.1372333 5.809089

donde el primer valor es mucho más pequeño hacia cero, lo cual puede ser apropiado dado que la diagonal de la matriz debería ser 0.

Para leer esto puede hacer la lectura en python tal como lo intentaba, aunque sería prudente usar count= para leer solo en la longitud de registro adecuada si hay más de un registro en el archivo.

Usando el código python:

f = open(''fortran_output'', ''rb'') field = np.fromfile(f, dtype=''float32'') print(field)

produce la salida

[ 2.58363912e-07 7.30291557e+00 8.72341537e+00 ..., 6.45882940e+00 6.53710747e+00 6.01582813e+00]

que coincide con la salida del archivo interpretada como flotantes de 32 bits.

Las particularidades de la escritura generalmente no tienen ningún delimitador de registro para este tipo de salida cuando se prueban con varias versiones de gfortran e ifort, pero pueden ser como la primera mitad de la publicación o algo diferente para otros compiladores.

También quiero reiterar la advertencia de que esta solución no es 100% confiable ya que no tenemos los datos que escribió en este archivo para verificar. Sin embargo, usted tiene esa información y debe verificar que los datos producidos sean los adecuados. También vale la pena señalar al compilar con indicadores predeterminados, las longitudes de registros ifort están en palabras de 4 bytes, mientras que gfortran está en unidades de 1 byte. Esto no causará problemas en la salida, pero si no se compensa en ifort, tus archivos serán 4 veces más grandes de lo necesario. Puede obtener longitudes de registro en unidades de bytes utilizando -assume byterecl con ifort.