Письмо & amp; Добавление массивов с плавающей точкой к единственному набору данных в файле hdf5 в переполнении стека

Я обрабатываю количество файлов, каждая обработка файла будет выводить несколько тысяч массивов с плавающей точкой, и я буду хранить данные всех файлов в одном огромном наборе данных в одном hdf5 для дальнейшей обработки.

В настоящее время я не совсем понимаю, как добавить свои данные в файл hdf5. (комментарий в коде выше) В 2 для циклов выше, как вы можете видеть, я хочу добавлять одномерный массив float в hdf5 за раз, а не как целое. Мои данные в терабайтах, и мы можем только добавить данные в файл.

Есть несколько вопросов:

  1. Как добавить данные в этом случае? Какую функцию я должен использовать?
  2. Прямо сейчас у меня есть fdim [0] = 928347543, я пытался вставить флаг бесконечности HDF5, но выполнение во время выполнения жалуется. Есть ли способ сделать это? Я не хочу вычислять данные, которые у меня есть каждый раз; Есть ли способ просто продолжать добавлять данные, не заботясь о значении fdim?

Или это невозможно?

РЕДАКТИРОВАТЬ:

Я следовал совету Саймона, и сейчас вот мой обновленный код:

hid_t desFi5;
hid_t fid1;
hid_t propList;
hsize_t fdim[2];

desFi5 = H5Fcreate(saveFilePath, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

fdim[0] = 3;
fdim[1] = 1;//H5S_UNLIMITED;

fid1 = H5Screate_simple(2, fdim, NULL);

cout << "----------------------------------Space done\n";

propList = H5Pcreate( H5P_DATASET_CREATE);

H5Pset_layout( propList, H5D_CHUNKED );

int ndims = 2;
hsize_t chunk_dims[2];
chunk_dims[0] = 3;
chunk_dims[1] = 1;

H5Pset_chunk( propList, ndims, chunk_dims );

cout << "----------------------------------Property done\n";

hid_t dataset1 = H5Dcreate( desFi5, "des", H5T_NATIVE_FLOAT, fid1, H5P_DEFAULT, propList, H5P_DEFAULT);

cout << "----------------------------------Dataset done\n";

bufi = new float*[1];
bufi[0] = new float[3];
bufi[0][0] = 0;
bufi[0][1] = 1;
bufi[0][2] = 2;

//hyperslab
hsize_t start[2] = {0,0};
hsize_t stride[2] = {1,1};
hsize_t count[2] = {1,1};
hsize_t block[2] = {1,3};

H5Sselect_hyperslab( fid1, H5S_SELECT_OR, start, stride, count, block);
cout << "----------------------------------hyperslab done\n";

H5Dwrite(dataset1, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, *bufi);

fdim[0] = 3;
fdim[1] = H5S_UNLIMITED;    // COMPLAINS HERE
H5Dset_extent( dataset1, fdim );

cout << "----------------------------------extent done\n";

//hyperslab2
hsize_t start2[2] = {1,0};
hsize_t stride2[2] = {1,1};
hsize_t count2[2] = {1,1};
hsize_t block2[2] = {1,3};

H5Sselect_hyperslab( fid1, H5S_SELECT_OR, start2, stride2, count2, block2);
cout << "----------------------------------hyperslab2 done\n";

H5Dwrite(dataset1, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, *bufi);

cout << "----------------------------------H5Dwrite done\n";
H5Dclose(dataset1);
cout << "----------------------------------dataset closed\n";
H5Pclose( propList );
cout << "----------------------------------property list closed\n";
H5Sclose(fid1);
cout << "----------------------------------dataspace fid1 closed\n";
H5Fclose(desFi5);
cout << "----------------------------------desFi5 closed\n";

Мой текущий вывод:

bash-3.2$ ./hdf5AppendTest.out
----------------------------------Space done
----------------------------------Property done
----------------------------------Dataset done
----------------------------------hyperslab done
HDF5-DIAG: Error detected in HDF5 (1.8.10) thread 0:
#000: /home/hdftest/snapshots-bin-hdf5_1_8_10/current/src/H5D.c line 1103 in H5Dset_extent(): unable to set extend dataset
major: Dataset
minor: Unable to initialize object
#001: /home/hdftest/snapshots-bin-hdf5_1_8_10/current/src/H5Dint.c line 2179 in H5D__set_extent(): unable to modify size of data space
major: Dataset
minor: Unable to initialize object
#002: /home/hdftest/snapshots-bin-hdf5_1_8_10/current/src/H5S.c line 1874 in H5S_set_extent(): dimension cannot exceed the existing maximal size (new: 18446744073709551615 max: 1)
major: Dataspace
minor: Bad value
----------------------------------extent done
----------------------------------hyperslab2 done
----------------------------------H5Dwrite done
----------------------------------dataset closed
----------------------------------property list closed
----------------------------------dataspace fid1 closed
----------------------------------desFi5 closed

В настоящее время я вижу, что установка неограниченного количества с помощью H5Dset_extent все еще вызывает проблемы во время выполнения. (проблемная функция отмечена //COMPLAINS HERE в приведенном выше коде.) Я уже получил данные чанка, как указано Саймоном, так в чем здесь проблема?

С другой стороны, без H5Dset_extent я могу написать тестовый массив из [0, 1, 2] просто отлично, но как мы можем сделать код выше выходного тестового массива в файл следующим образом:

[0, 1, 2]
[0, 1, 2]
[0, 1, 2]
[0, 1, 2]
...
...

Напомним: это всего лишь тестовый массив, реальные данные больше, и я не могу хранить все это в ОЗУ, поэтому я должен помещать данные по частям по одной за раз.

РЕДАКТИРОВАТЬ 2:

Я больше следовал совету Саймона. Вот критическая часть:

hsize_t n = 3, p = 1;
float *bufi_data = new float[n * p];
float ** bufi = new float*[n];
for (hsize_t i = 0; i < n; ++i){
bufi[i] = &bufi_data[i * n];
}

bufi[0][0] = 0.1;
bufi[0][1] = 0.2;
bufi[0][2] = 0.3;

//hyperslab
hsize_t start[2] = {0,0};
hsize_t count[2] = {3,1};

H5Sselect_hyperslab( fid1, H5S_SELECT_SET, start, NULL, count, NULL);
cout << "----------------------------------hyperslab done\n";

H5Dwrite(dataset1, H5T_NATIVE_FLOAT, H5S_ALL, fid1, H5P_DEFAULT, *bufi);

bufi[0][0] = 0.4;
bufi[0][1] = 0.5;
bufi[0][2] = 0.6;

hsize_t fdimNew[2];
fdimNew[0] = 3;
fdimNew[1] = 2;
H5Dset_extent( dataset1, fdimNew );

cout << "----------------------------------extent done\n";

//hyperslab2
hsize_t start2[2] = {0,0}; //PROBLEM
hsize_t count2[2] = {3,1};

H5Sselect_hyperslab( fid1, H5S_SELECT_SET, start2, NULL, count2, NULL);
cout << "----------------------------------hyperslab2 done\n";

H5Dwrite(dataset1, H5T_NATIVE_FLOAT, H5S_ALL, fid1, H5P_DEFAULT, *bufi);

Исходя из вышесказанного, я получил следующий вывод для hdf5:

0.4 0.5 0.6
0   0   0

После дальнейшего эксперимента с start2 а также count2Я вижу, что эти переменные влияют только на начальный индекс и индекс приращения для bufi, Он вообще не меняет положение индекса записи моего набора данных.

Напомним: окончательный результат должен быть:

0.1 0.2 0.3
0.4 0.5 0.6

Кроме того, это должно быть bufi вместо *bufi за H5DwriteСаймон, потому что bufi дает мне совершенно случайные числа.

ОБНОВЛЕНИЕ 3:

Для части выбора, предложенной Саймоном:

hsize_t start[2] = {0, 0};
hsize_t count[2] = {1, 3};

hsize_t start[2] = {1, 0};
hsize_t count[2] = {1, 3};

Это выдаст следующую ошибку:

HDF5-DIAG: Error detected in HDF5 (1.8.10) thread 0:
#000: /home/hdftest/snapshots-bin-hdf5_1_8_10/current/src/H5Dio.c line 245 in H5Dwrite(): file selection+offset not within extent
major: Dataspace
minor: Out of range

count[2] должно быть {3,1}, скорее, чем {1,3}, Я полагаю? И для start[2]если я не установлю это как {0,0}, он всегда выкрикнет ошибку выше.

Вы уверены, что это правильно?

16

Решение

Как добавить данные в этом случае? Какую функцию я должен использовать?

Вы должны использовать hyperslabs. Это то, что вам нужно, чтобы написать только часть набора данных.
Функция для этого H5Sselect_hyperslab. Используйте это на fd1 и использовать fd1 как ваше пространство данных файла в вашем H5Dwrite вызов.

Я попытался вставить флаг бесконечности HDF5, но выполнение во время выполнения жалуется.

Вам нужно создать набор данных по частям чтобы иметь возможность установить его максимальный размер в бесконечность. Создать список свойств создания набора данных и использовать H5Pset_layout сделать это кусками. использование H5Pset_chunk установить размер куска. Затем создайте свой набор данных, используя этот список свойств.

Я не хочу вычислять данные, которые у меня есть каждый раз; Есть ли способ просто продолжать добавлять данные, не заботясь о значении fdim?

Вы можете сделать две вещи:

  1. Предварительно вычислите окончательный размер, чтобы вы могли создать достаточно большой набор данных. Похоже, это то, что вы делаете.

  2. Расширьте свой набор данных по мере использования H5Dset_extent. Для этого вам нужно установить максимальные размеры в бесконечность, поэтому вам нужен набор данных по частям (см. Выше).

В обоих случаях вам нужно выбрать гиперсписку в файловом пространстве данных в вашем H5Dwrite позвоните (см. выше).

Прохождение рабочий код

#include <iostream>
#include <hdf5.h>

// Constants
const char saveFilePath[] = "test.h5";
const hsize_t ndims = 2;
const hsize_t ncols = 3;

int main()
{

Сначала создайте файл hdf5.

    hid_t file = H5Fcreate(saveFilePath, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
std::cout << "- File created" << std::endl;

Затем создайте 2D-пространство данных.
Размер первого измерения не ограничен. Первоначально мы установили его на 0, чтобы показать, как вы можете расширять набор данных на каждом шаге. Например, вы можете установить размер первого буфера, который вы собираетесь записать.
Размер второго измерения фиксирован.

    hsize_t dims[ndims] = {0, ncols};
hsize_t max_dims[ndims] = {H5S_UNLIMITED, ncols};
hid_t file_space = H5Screate_simple(ndims, dims, max_dims);
std::cout << "- Dataspace created" << std::endl;

Затем создайте список свойств создания набора данных.
Компоновка набора данных должна быть разбита на части при использовании неограниченных размеров.
Выбор размера чанка влияет на производительность как во времени, так и на дисковом пространстве. Если куски очень маленькие, у вас будет много накладных расходов. Если они слишком велики, вы можете выделить ненужное место, и ваши файлы могут оказаться слишком большими.
Это игрушечный пример, поэтому мы выберем куски одной строки.

    hid_t plist = H5Pcreate(H5P_DATASET_CREATE);
H5Pset_layout(plist, H5D_CHUNKED);
hsize_t chunk_dims[ndims] = {2, ncols};
H5Pset_chunk(plist, ndims, chunk_dims);
std::cout << "- Property list created" << std::endl;

Создайте набор данных.

    hid_t dset = H5Dcreate(file, "dset1", H5T_NATIVE_FLOAT, file_space, H5P_DEFAULT, plist, H5P_DEFAULT);
std::cout << "- Dataset 'dset1' created" << std::endl;

Закрыть ресурсы. Набор данных создан, поэтому нам больше не нужен список свойств.
Нам больше не нужно файловое пространство данных, потому что, когда набор данных будет расширен, он станет недействительным, так как он все еще будет содержать предыдущий экстент.
Так что нам все равно придется получить обновленное файловое пространство данных.

    H5Pclose(plist);
H5Sclose(file_space);

Теперь мы добавим два буфера в конец набора данных.
Первый будет длиной в две строки.
Второй будет длиной в три строки.

Первый буфер

Мы создаем 2D-буфер (непрерывный в памяти, основной порядок строк).
Мы выделим достаточно памяти для хранения 3 строк, чтобы мы могли повторно использовать буфер.
Давайте создадим массив указателей, чтобы мы могли использовать b[i][j] обозначение
вместо buffer[i * ncols + j], Это чисто эстетично.

    hsize_t nlines = 3;
float *buffer = new float[nlines * ncols];
float **b = new float*[nlines];
for (hsize_t i = 0; i < nlines; ++i){
b[i] = &buffer[i * ncols];
}

Начальные значения в буфере для записи в набор данных:

    b[0][0] = 0.1;
b[0][1] = 0.2;
b[0][2] = 0.3;
b[1][0] = 0.4;
b[1][1] = 0.5;
b[1][2] = 0.6;

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

    dims[0] = 2;
dims[1] = ncols;
hid_t mem_space = H5Screate_simple(ndims, dims, NULL);
std::cout << "- Memory dataspace created" << std::endl;

Теперь нам нужно расширить набор данных.
Мы устанавливаем начальный размер набора данных в 0x3, поэтому нам нужно сначала его расширить.
Обратите внимание, что мы расширяем сам набор данных, а не его пространство данных.
Помните, что первый буфер имеет длину только две строки.

    dims[0] = 2;
dims[1] = ncols;
H5Dset_extent(dset, dims);
std::cout << "- Dataset extended" << std::endl;

Выберите HyperSlab в наборе файлов данных.

    file_space = H5Dget_space(dset);
hsize_t start[2] = {0, 0};
hsize_t count[2] = {2, ncols};
H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL);
std::cout << "- First hyperslab selected" << std::endl;

Записать буфер в набор данных.
mem_space а также file_space теперь должно иметь такое же количество выбранных элементов.
Обратите внимание, что buffer а также &b[0][0] эквивалентны.

    H5Dwrite(dset, H5T_NATIVE_FLOAT, mem_space, file_space, H5P_DEFAULT, buffer);
std::cout << "- First buffer written" << std::endl;

Теперь мы можем закрыть пространство данных файла.
Теперь мы можем закрыть пространство данных памяти и создать новое для второго буфера,
но мы просто обновим его размер.

    H5Sclose(file_space);

Второй буфер

Новые значения в буфере, которые будут добавлены в набор данных:

    b[0][0] = 1.1;
b[0][1] = 1.2;
b[0][2] = 1.3;
b[1][0] = 1.4;
b[1][1] = 1.5;
b[1][2] = 1.6;
b[2][0] = 1.7;
b[2][1] = 1.8;
b[2][2] = 1.9;

Измените размер пространства памяти, чтобы указать новый размер нашего буфера.
Второй буфер длиной три строки.

    dims[0] = 3;
dims[1] = ncols;
H5Sset_extent_simple(mem_space, ndims, dims, NULL);
std::cout << "- Memory dataspace resized" << std::endl;

Расширить набор данных.
Обратите внимание, что в этом простом примере мы знаем, что 2 + 3 = 5.
В общем, вы можете прочитать текущий экстент из пространства данных файла.
и добавить желаемое количество строк к нему.

    dims[0] = 5;
dims[1] = ncols;
H5Dset_extent(dset, dims);
std::cout << "- Dataset extended" << std::endl;

Выберите HyperSlab в наборе файлов данных.
Опять же в этом простом примере мы знаем, что 0 + 2 = 2.
В общем, вы можете прочитать текущий экстент из файлового пространства данных.
Второй буфер длиной три строки.

    file_space = H5Dget_space(dset);
start[0] = 2;
start[1] = 0;
count[0] = 3;
count[1] = ncols;
H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL);
std::cout << "- Second hyperslab selected" << std::endl;

Добавить буфер в набор данных

    H5Dwrite(dset, H5T_NATIVE_FLOAT, mem_space, file_space, H5P_DEFAULT, buffer);
std::cout << "- Second buffer written" << std::endl;

Конец: давайте закроем все ресурсы:

    delete[] b;
delete[] buffer;
H5Sclose(file_space);
H5Sclose(mem_space);
H5Dclose(dset);
H5Fclose(file);
std::cout << "- Resources released" << std::endl;
}

NB: Я удалил предыдущие обновления, потому что ответ был слишком длинным. Если вы заинтересованы, просмотрите историю.

34

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]