Чтение двоичного файла Фортрана в Python - PullRequest
0 голосов
/ 05 декабря 2018

У меня проблемы с чтением неформатированного двоичного файла F77 в Python.Я пробовал метод SciPy.io.FortraFile и метод NumPy.fromfile, но оба безрезультатно.Я также прочитал файл в IDL, который работает, поэтому у меня есть эталон того, как должны выглядеть данные.Я надеюсь, что кто-то может указать на глупую ошибку с моей стороны - нет ничего лучше, чем иметь идиотский момент и затем вымыть руки ...

Данные, bcube1, имеют размеры 101x101x101x3,и г * 8 типа.Всего 3090903 записей.Они написаны с использованием следующего утверждения (не мой код, скопированный из источника).

open (unit=21, file=bendnm, status='new'
.     ,form='unformatted')
write (21) bcube1
close (unit=21)

Я могу успешно прочитать его в IDL, используя следующее (также не мой код, скопированный с коллеги):

bcube=dblarr(101,101,101,3)
openr,lun,'bcube.0000000',/get_lun,/f77_unformatted,/swap_if_little_endian
readu,lun,bcube
free_lun,lun

Возвращенные данные (bcube) имеют двойную точность, с размерами 101x101x101x3, поэтому информация заголовка для файла учитывает его размеры (не плоская).

Теперь я пытаюсь получить то же самоеэффект с помощью Python, но не повезло.Я пробовал следующие методы.

In [30]: f = scipy.io.FortranFile('bcube.0000000', header_dtype='uint32')
In [31]: b = f.read_record(dtype='float64')

, который возвращает ошибку Size obtained (3092150529) is not a multiple of the dtypes given (8).Изменение dtype изменяет полученный размер, но он остается неделимым на 8.

Альтернативно, использование fromfile не приводит к ошибкам, но возвращает еще одно значение, которое находится в массиве (возможно, в нижнем колонтитуле?) И отдельном массивезначения в корне неверны (все должны быть порядка единицы).

In [38]: f = np.fromfile('bcube.0000000')
In [39]: f.shape
Out[39]: (3090904,)
In [42]: f
Out[42]: array([ -3.09179121e-030,   4.97284231e-020,  -1.06514594e+299, ...,
         8.97359707e-029,   6.79921640e-316,  -1.79102266e-037])

Я пытался использовать byteswap, чтобы увидеть, делает ли это значения с плавающей запятой более разумными, но это не так.

Мне кажется, что метод np.fromfile очень близок к работе, но должно быть что-то не так с тем, как он читает информацию заголовка.Может кто-нибудь предложить, как я могу выяснить, что должно быть в заголовочном файле, который позволяет IDL знать о размерах массива и типе данных?Есть ли способ передать информацию заголовка в fromfile, чтобы он знал, как обрабатывать ведущую запись?

1 Ответ

0 голосов
/ 06 декабря 2018

Я немного поиграл с этим, и мне кажется, у меня есть идея.

То, как Фортран хранит неформатированные данные, не стандартизировано, поэтому вам придется немного поэкспериментировать с этим, но вам нужно три частиинформации:

  1. Формат данных.Вы предполагаете, что это 64-битные реалы или 'f8' в python.
  2. Тип заголовка.Это целое число без знака, но вам нужна длина в байтах.Если не уверены, попробуйте 4.

    Заголовок обычно хранит длину записи в байтах и ​​повторяется в конце.

    Опять же, он не стандартизирован, поэтому никаких гарантий.

  3. Порядковый, маленький или большой.

    Технически для заголовка и значений, но я предполагаю, что они одинаковы.

    Python по умолчанию имеет младший порядок байтов, поэтому, если бы это были правильные настройки для ваших данных, я думаю, вы бы уже решили это.

Когда вы открываете файлс scipy.io.FortranFile необходимо указать тип данных заголовка .Поэтому, если данные хранятся в big_endian, и у вас есть 4-байтовый целочисленный заголовок без знака, вам нужно это:

from scipy.io import FortranFile
ff = FortranFile('data.dat', 'r', '>u4')

Когда вы читаете данные, вам нужен тип данных значений.Опять же, предполагая big_endian, вы хотите ввести >f8:

vals = ff.read_reals('>f8')

Посмотрите здесь описание синтаксиса типа данных.

Если у вас есть контрольнад программой, которая записывает данные, я настоятельно рекомендую вам записать их в потоки данных, которые могут быть легко прочитаны Python.

...