HDF5 — удобный формат для хранения и использования данных вычислительных экспериментов. Он может использоваться с языками C/C++, Fortran-90 и свежее, Python; доступен для использования в среде Matlab; отображать данные, хранящиеся в данном формате может MathGL.
В этой заметке я хочу постепенно описать работу с HDF5 в Fortran. Основная информация почёрпнута с сайта The HDF group.
Общая информация
Как следует из названия (Hierarchical Data Format), формат предусматривает размещение данных в иерархическом виде по принципу файловой системы. Файл данных инкапсулирует такие объекты, как группы (groups — аналог каталогов) и данные (dataset). Каждый объект может быть помечен произвольными атрибутами, описывающими его. Допускаются вложенные группы. Вся структура начинается с корневой группы, которая присутствует по умолчанию в hdf-файле и её не требуется создавать.
Библиотека и программы
Рабочая среда HDF5 с точки зрения Fortran состоит из ряда модулей, основным из которых является hdf5 и некоторых вспомогательных утилит. Начинать следует с использования hdfview (http://www.hdfgroup.org/hdf-java-html/hdfview/index.html), написанной на Java программы для просмотра hdf5-файлов. На этапе освоения и отладки программ она позволит контролировать правильность создаваемых файлов.
Сама библиотека может быть взята с официального сайта и собрана, либо, в случае Linux, есть большая вероятность, что она присутствует в дистрибутиве. У меня на ALT Linux последовательная библиотека (существует также и параллельный вариант) ставится командой
apt-get install libhdf5-6-seq libhdf5-devel
Для компиляции программы, содержащей hdf5-инструкции, если соответствующие пути не прописаны, необходимо указывать пути к модулям (-I инструкция), библиотеке (-L) и саму библиотеку (-l). Таким образом типичная команда компиляции будет иметь вид
gfortran myhdf5.f90 -I /usr/lib/hdf5-seq/include/ -L /usr/lib/hdf5-seq/lib/ -l hdf5_fortran
Подключение HDF5
Как уже было сказано, процедуры и константы, обеспечивающие работу с HDF5-файлами, описываются в соответствующих модулях. Однако подключать достаточно один модуль hdf5, на остальные он ссылается сам. Сама работа с hdf начинается с инициализации hdf-режима и заканчивается выходом из указанного режима. Данные действия осуществляются процедурами h5open_f и h5close_f:
program testHDF5 use hdf5 implicit none integer :: ierr ! Начинаем работу с HDF5 call h5open_f(ierr) ! Действия с HDF5 ! Завершаем работу с HDF5 call h5close_f(ierr) end
Замечание. Все записанные в этом примере операторы обязательно присутствуют в любой программе, поэтому в примерах ниже я часто буду их пропускать и записывать только описания необходимых переменных и код для раздела «Действия с HDF5».
Открытие HDF5 файла
Открытие файла на чтение или запись осуществляется процедурами h5fcreate_f или h5fopen_f; закрытие — h5fclose_f.
Следует отметить, что именование процедур для работы с HDF5 следует жёстким правилам. Так, префикс h5 (HDF5) и суффикс _f (Fortran) присутствуют в обязательном порядке в именах всех процедур. Второй префикс определяет объект, с которым работает данная процедура: f означает файл. В предыдущем разделе описаны функции, относящиеся ко всей работе с HDF5 без выделения конкретного объекта, потому в их именах второй префикс отсутствует.
Рассмотрим подробнее функции работы с файлами.
h5fcreate_f(filename, mode, file_id, ierr)
Здесь filename — символьная переменная или константа, задающая имя файла;
mode — предопределённая константа, определяющая режим создания и открытия файла;
file_id — файловый дескриптор, который используется остальными процедурами, который представляет собой целую переменную разновидности hid_t (Hdf IDentifier Type);
ierr — целая переменная для возвращения кода ошибки, присутствует во всех процедурах.
Эта процедура создаёт и открывает файл.
В ней предусмотрены два режима создания файла: h5f_acc_trunc (_acc — третий суффикс (access)) говорит о том, что если файл с таким именем уже существует, он будет удалён и на его месте создан новый (truncate); h5f_acc_excl остановит работу и вернёт ошибку, если файл уже существует (exclusive).
Работу с уже существующими файлами, данные из которых требуется читать или куда будем дописывать данные следует начинать с процедуры
h5fopen_f(filename, mode, file_id, ierr)
Параметры процедуры те же, что и для предыдущей, но режимы открытия файла могут принимать иные значения:
h5f_acc_rdonly (ReaD only) — файл открывается только на чтение или h5f_acc_rdwr (Read and WRite) — файл открывается для чтения и записи.
По завершении работы с файлом его следует закрыть:
h5fclose_f(file_id, ierr)
Таким образом, типичная работа с новым файлом может выглядеть как
integer (hid_t) :: file_id character (15) :: fname="my_hdf5_file.h5" call h5fcreate_f(fname, h5f_acc_trunc, file_id, ierr) ! Действия с HDF5 данными call h5fclose_f(file_id, ierr)
Работа с группами
Группы в HDF5 выполняют ту же роль, что и каталоги в файловой системе. Это означает, что объекты данных располагаются внутри групп, сами группы могут быть вложенными, по умолчанию присутствует никак не называемая корневая группа.
Рассмотрим следующие функции работы с группами: h5gcreate_f, h5gopen_f, h5gclose_f, h5gget_info_f, h5gget_info_by_idx_f, h5gget_info_by_name_f.
Работа с данными. Выделение места
Сложность внутренней структуры HDF5 файла приводит к необходимости двухэтапной работы по размещению данных в нём. Вначале выделяется место под данные (dataspace) указанного типа, после чего данные могут быть размещены.
Выделение места (или пространства — Space) под данные производится рядом процедур, из которых рассмотрим h5screate_f, h5scopy_f, h5screate_simple_f, h5sclose_f.
h5screate_f отвечает в первую очередь за выделение и открытие для записи пространства под скаляр:
h5screate_f(classtype, space_id, ierr)
где classtype — константа, определяющая класс выделяемого пространства, принимает значение h5s_scalar_f для скаляра; space_id — возвращаемый дескриптор пространства данных, он имеет целый тип класс hid_t.
h5screate_simple_f выделяет и открывает для записи пространство под массив простого типа.
h5screate_simple_f(rank, dims, space_id, ierr)
параметры: rank — константа, переменная и или арифметическое выражение целого типа, задающие ранг массива, под который выделяется место; dims — одномерный массив целого типа класса hsize_t, описывающий конфигурацию массива, для которого выделяется пространство.
h5scopy_f выделяет новое пространство того же размера, что уже задано и возвращает новый дескриптор:
h5scopy_f(space_id, new_space_id, ierr)
Здесь space_id — дескриптор существующего пространства; new_space_id — возвращаемый дескриптор вновь выделенного пространства. Дескрипторы сохраняются в переменные целого типа класса hid_t.
По окончании работы с вновь созданным пространством, его следует закрыть:
h5sclose_f(space_id, ierr)
Работа с данными. Запись и чтение
h5dcreate_f, h5dopen_f, h5dclose_f, h5dread_f, h5dwrite_f.
h5dcreate_f(file_id, name, classtype, space_id, data_id, ierr)
h5dopen_f(file_id, name, data_id, ierr)
h5dclose_f(data_id, ierr)
h5dwrite_f(data_id, mem_type_id, buf, dims, ierr)
h5dread_f(data_id, mem_type_id, buf, dims, ierr)