significado programacion lenguaje ejemplos fortran binaryfiles gfortran intel-fortran

programacion - fortran significado



Lectura escribiendo fortran acceso directo archivos no formateados con diferentes compiladores (1)

Ifort y gfortran no usan el mismo tamaño de bloque para la longitud de registro por defecto. En ifort, el valor de recl en su instrucción open está en bloques de 4 bytes, por lo que la longitud de su registro no es de 985.600 bytes, sino de 3.942.400 bytes. Eso significa que los registros se escriben a intervalos de 3.9 millones de bytes.

gfortran usa un tamaño de bloque recl de 1 byte y su longitud de registro es 985,600 byes. Cuando lee el primer registro, todo funciona, pero cuando lee el segundo registro observa 985,600 bytes en el archivo, pero los datos están en 3,942,400 bytes en el archivo. Esto también significa que está desperdiciando una tonelada de datos en el archivo, ya que solo está usando 1/4 de su tamaño.

Hay un par de formas de solucionar esto:

  • En ifort, especifique recl en bloques de 4 bytes, p 320*385*2 Ej. 320*385*2 lugar de *8
  • En ifort, utilice el indicador de compilación -assume byterecl para tener valores recl interpretados como bytes.
  • En gfortran, compense el tamaño y use recl=320*385*32 para que sus lecturas estén colocadas correctamente.

Sin embargo, una mejor manera es diseñar agnosticismo en el tamaño de la unidad recl . Puede usar inquire para descubrir el recl de una matriz. Por ejemplo:

real(kind=wp), allocatable, dimension(:,:) :: recltest integer :: reclen allocate(recltest(320,385)) inquire(iolength=reclen) recltest deallocate(recltest) ... open (53, file=filename, form=''unformatted'', status=''unknown'', & access=''direct'',action=''write'',recl=reclen) ... OPEN(53, FILE=fname, form="unformatted", status="unknown", & access="direct", action="read", recl=reclen)

Esto configurará reclen al valor necesario para almacenar una matriz de 320x385 basada en la unidad base de ese compilador para la longitud de registro. Si usa esto cuando tanto la escritura como la lectura de su código funcionarán con ambos compiladores sin tener que usar indicadores de tiempo de compilación en ifort o compensar con diferencias recl codificadas entre compiladores.

Un ejemplo ilustrativo

Testcase 1

program test use iso_fortran_env implicit none integer(kind=int64), dimension(5) :: array integer :: io_output, reclen, i reclen = 5*8 ! 5 elements of 8 byte integers. open(newunit=io_output, file=''output'', form=''unformatted'', status=''new'', & access=''direct'', action=''write'', recl=reclen) array = [(i,i=1,5)] write (io_output, rec=1) array array = [(i,i=101,105)] write (io_output, rec=2) array array = [(i,i=1001,1005)] write (io_output, rec=3) array close(io_output) end program test

Este programa escribe una matriz de 5 enteros de 8 bytes 3 veces en el archivo en los registros 1, 2 y 3. La matriz tiene 5 * 8 bytes y he codificado ese número como el valor recl.

Testcase 1 con gfortran 5.2

Recopilé este caso de prueba con la línea de comando:

gfortran -o write-gfortran write.f90

Esto produce el archivo de salida (interpretado con od -A d -t d8 ):

0000000 1 2 0000016 3 4 0000032 5 101 0000048 102 103 0000064 104 105 0000080 1001 1002 0000096 1003 1004 0000112 1005 0000120

Las matrices de elementos de 5 8 bye están empaquetadas contiguamente en el archivo y el número de registro 2 ( 101 ... 105 ) comienza donde esperaríamos que esté en offset 40, que es el valor recl en el archivo 5*8 .

Testcase 1 con ifort 16

Esto se compila de manera similar:

ifort -o write-ifort write.f90

Y esto, para el mismo código exacto, produce el archivo de salida (interpretado con od -A d -t d8 ):

0000000 1 2 0000016 3 4 0000032 5 0 0000048 0 0 * 0000160 101 102 0000176 103 104 0000192 105 0 0000208 0 0 * 0000320 1001 1002 0000336 1003 1004 0000352 1005 0 0000368 0 0 * 0000480

Los datos están todos allí, pero el archivo está lleno de 0 elementos valiosos. Las líneas que comienzan con * indican que cada línea entre los desplazamientos es 0. El número de registro 2 comienza en el desplazamiento 160 en lugar de 40. Observe que 160 es 40 * 4, donde 40 es nuestro recl especificado de 5*8 . Por defecto, ifort usa bloques de 4 bytes, por lo que un recl de 40 significa un tamaño de registro físico de 160 bytes.

Si el código compilado con gfortran fuera a leer esto, los registros 2,3 y 4 contendrían los 0 elementos y una lectura del registro 5 leería correctamente la matriz escrita como registro 2 por ifort. Una alternativa para que gfortran lea el registro 2 donde se encuentra en el archivo sería usar recl=160 (4 * 5 * 4) para que el tamaño del registro físico coincida con lo que escribió ifort.

Otra consecuencia de esto es el espacio desperdiciado. Si especifica demasiado el recl, significa que está usando 4 veces el espacio de disco necesario para almacenar sus registros.

Testcase 1 con ifort 16 y -assume byterecl

Esto fue compilado como:

ifort -assume byterecl -o write-ifort write.f90

Y produce el archivo de salida:

0000000 1 2 0000016 3 4 0000032 5 101 0000048 102 103 0000064 104 105 0000080 1001 1002 0000096 1003 1004 0000112 1005 0000120

Esto produce el archivo como se esperaba. El argumento de la línea de comando -assume byterecl le dice a ifort que interprete cualquier valor recl como bytes en lugar de palabras dobles (bloques de 4 bytes). Esto producirá escrituras y lecturas que coinciden con el código compilado con gfortran.

Testcase 2

program test use iso_fortran_env implicit none integer(kind=int64), dimension(5) :: array integer :: io_output, reclen, i inquire(iolength=reclen) array print *,''Using recl='',reclen open(newunit=io_output, file=''output'', form=''unformatted'', status=''new'', & access=''direct'', action=''write'', recl=reclen) array = [(i,i=1,5)] write (io_output, rec=1) array array = [(i,i=101,105)] write (io_output, rec=2) array array = [(i,i=1001,1005)] write (io_output, rec=3) array close(io_output) end program test

La única diferencia en este caso de prueba es que estoy investigando el recl apropiado para representar mi arreglo de 40 bytes (5 enteros de 8 bytes).

La salida

gfortran 5.2:

Using recl= 40

ifort 16, sin opciones:

Using recl= 10

ifort 16, -assume byterecl :

Using recl= 40

Vemos que para los bloques de 1 byte utilizados por gfortran e ifort con la suposición byterecl de que recl es 40 , lo que equivale a nuestra matriz de 40 bytes. También vemos que, de forma predeterminada, ifort usa un recl de 10, lo que significa 10 bloques de 4 bytes o 10 palabras dobles, los cuales significan 40 bytes. Las tres cajas de prueba producen una salida de archivo idéntica y las lecturas / escrituras de cualquiera de los compiladores funcionarán correctamente.

Resumen

Para que los datos directos no formateados y basados ​​en registros sean portátiles entre ifort y gfort, la opción más fácil es simplemente agregar -assume byterecl a los indicadores utilizados por ifort. Deberías haber hecho esto ya que estás especificando longitudes de registro en bytes, por lo que este sería un cambio directo que probablemente no tenga consecuencias para ti.

La otra alternativa es no preocuparse por la opción y utilizar la inquire intrínseca para consultar la iolength de su matriz.

Tengo una sección en un programa que escribe un archivo binario de acceso directo de la siguiente manera:

open (53, file=filename, form=''unformatted'', status=''unknown'', & access=''direct'',action=''write'',recl=320*385*8) write (53,rec=1) ulat write (53,rec=2) ulng close(53)

Este programa está compilado con ifort. Sin embargo, no puedo reconstruir los datos correctamente si leo el archivo de datos de un programa diferente compilado con gfortran. Si el programa que lee los datos también se compila en ifort, entonces puedo reconstruir correctamente los datos. Aquí está el código que lee el archivo de datos:

OPEN(53, FILE=fname, form="unformatted", status="unknown", access="direct", action="read", recl=320*385*8) READ(53,REC=2) DAT

No entiendo por qué está pasando esto? Puedo leer el primer registro correctamente con ambos compiladores, es el segundo registro que no puedo reconstruir correctamente si mezclo los compiladores.