Как решить «Ошибка времени выполнения Fortran: ввод-вывод после конца записи в неформатированном файле»?

Теперь у меня есть один массив размером 1024 * 1024 * 1024, dtype которого равен float32. Сначала я сохраняю этот массив в один файл в формате «.bigfile». Затем я конвертирую этот большой файл в неформатированный файл Fortran, запустив код, как показано ниже.

with bigfile.File('filename.bigfile') as bf:
    shape = bf['Field'].attrs['ndarray.shape']
    data = bf['Field'][:].reshape(shape)
    np.asfortranarray(data).tofile('filename.dat')

Затем для тестирования этого двоичного файла, т. е. «filename.dat», я прочитал этот файл с помощью Python и Fortran95 соответственно. Код Python работает нормально, фрагмент кода показан ниже.

field = np.fromfile('filename.dat', 
                   dtype='float32', count=1024*1024*1024)
density_field = field.reshape(1024, 1024, 1024)

Однако Fortran runtime error произошло, когда я запускаю код чтения Fortran:

 Program readout00
  Implicit None
  Integer, Parameter :: Ng = 1024
  Real, Allocatable, Dimension(:,:,:) :: dens
  Integer :: istat, ix, iy, iz
  ! -------------------------------------------------------------------------
  ! Allocate the arrays for the original simulation data
  ! -------------------------------------------------------------------------
  Allocate(dens(0:Ng-1, 0:Ng-1, 0:Ng-1), STAT=istat)
  If( istat/=0 ) Stop "Wrong Allocation-1"
  ! -------------------------------------------------------------------------
  Open(10, file="filename.dat", status="old", form="unformatted")
  Read(10) dens
  Close(10)
  Write(*,*) "read-in finished"
  ! -------------------------------------------------------------------------
  Do ix = 0, 1
    Do iy = 0, 1
      Do iz = 0, 1
        Write(*,*) "ix, iy, iz, rho=", ix, iy, iz, dens(ix, iy, iz)
     EndDo
    EndDo
  EndDo
  !--------------------------------------------------------------------------
End Program readout00

Сообщение об ошибке:

At line 13 of file readout00.f90 (unit = 10, file = 'filename.dat')
Fortran runtime error: I/O past end of record on unformatted file



Error termination. Backtrace:
#0  0x7f7d8aff8e3a
#1  0x7f7d8aff9985
#2  0x7f7d8affa13c
#3  0x7f7d8b0c96e0
#4  0x7f7d8b0c59a6
#5  0x400d24
#6  0x400fe1
#7  0x7f7d8a4db730
#8  0x400a58
#9  0xffffffffffffffff

Я не понимаю, почему появляются эти ошибки.

Примечание: вся операция выполняется на удаленном сервере LINUX.



После неоднократного изменения оператора read я обнаружил, что код на Фортране работает нормально, если ix<=632, iy<=632, iz<=632. Если они больше 632, появится runtime error. Как мне исправить эту ошибку, чтобы dens мог прочитать все 1024 ^ 3 элемента?

Read(10) (((dens(ix, iy, iz), ix=0,632), iy=0,632), iz=0,632)


Дополнительно:

Сегодня я добавил один пункт acccess=stream в ведомость open и read(10) header перед read(10) dens, т.е.

Integer :: header
......
Open(10, file="filename.dat", status="old",    &
         form="unformatted", access='stream')
Read(10) header
Read(10) dens

После модификации код Fortran readout00.f95 прочитал массив 1024 * 1024 * 1024, т.е. dens успешно.

Почему исходный 'readout00.f95' не читается в dens?


person Stephen Wong    schedule 13.09.2020    source источник
comment
@HighPerformanceMark Итак, как читать массив по частям? Не могли бы вы разъяснить этот вопрос более подробно?   -  person Stephen Wong    schedule 13.09.2020
comment
Пожалуйста, используйте тег fortran для всех вопросов по Fortran.   -  person Vladimir F    schedule 13.09.2020
comment
Numpy вряд ли будет записывать метаданные необходимой длины записи. Возможный дубликат stackoverflow.com/a/8751662/1234550 или множество подобных вопросов.   -  person IanH    schedule 14.09.2020
comment
Пожалуйста, объясните, почему связанный ответ в предыдущем комментарии не является ответом на ваш вопрос.   -  person IanH    schedule 17.09.2020
comment
@StephenWong Обратите внимание, что numpy.ndarray.tofile всегда сохраняет данные в Порядок «C», как указано в документах.   -  person a_guest    schedule 17.09.2020


Ответы (1)


@IanH правильно ответил на ваш вопрос в комментариях или, точнее, указал на правильный ответ в другом вопросе.

«Неформатированный» формат просто означает, что файл не интерпретируется как удобочитаемый для человека, но данные в файле должны быть расположены определенным образом. Хотя конкретный формат не определен и зависит от компилятора и системы, обычно каждая запись имеет свой собственный верхний и нижний колонтитулы, отображающие длину данных.

numpy.asfortanarray вообще не влияет на макет файла, он только гарантирует, что макет массива в памяти такой же, как в Fortran (основной столбец или первый индекс меняется быстрее всего), в отличие от обычного (основной ряд, или последний индекс меняется быстрее всего).

См. этот пример:

Я создал одни и те же данные (тип int16, значения от 0 до 11) в Python и Fortran и сохранил их в двух файлах: версию Python с np.asfortranarray.tofile и в Fortran с неформатированной записью. Вот результаты:

С Питоном:

0000000 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00
0000010 08 00 09 00 0a 00 0b 00

С Фортраном:

0000000 18 00 00 00 00 00 01 00 02 00 03 00 04 00 05 00
0000010 06 00 07 00 08 00 09 00 0a 00 0b 00 18 00 00 00

В файле Python «данные» начинаются сразу (00 00 для 0, затем 01 00 для 1 и так далее, до 0b 00 для 11), но в Фортране есть 4-байтовый заголовок: 18 00 00 00 или 24, который является число байтов данных, и это значение затем повторяется в конце.

Когда вы пытаетесь прочитать файл на Фортране, используя form='unformatted', программа ожидает найти именно такие данные, но это не те данные, которые у вас есть.

Решение именно то, что вы сделали: используйте поток. В потоке программа ожидает, что данные будут поступать непрерывно без каких-либо заголовков или метаданных.

person chw21    schedule 17.09.2020