Я пытаюсь сохранить данные моделирования из C ++ в HDF5 (позже я проанализирую эти данные в Python + Pandas). Моя цель - попытаться правильно организовать все данные в C ++, так что позже мне останется только прочитать их.
Моя проблема заключается в попытке сохранить динамический массив в разных столбцах HDF5: я использую H5 :: VarLenType для хранения массива. Я добился успеха, но я получаю массив в одном столбце, и это мне не удобно: мне нужно каждое значение в одном столбце.
Я могу сделать это, если бы использовал массивы фиксированного размера, но не использовал временный буфер с типом данных hvl_t
. Если я использую тот же подход (перебирая цикл, вычисляя смещения вручную и добавляя тип данных) с массивом переменной длины, я получаю данные мусора.
Я изучил этот подход в этом SO-ответе
Это мое доказательство концепции, позже я добавлю его в свой проект.
#include <stddef.h>
#include <cstring>
#include <string>
#include <sstream>
#include <iostream>
#include "H5Cpp.h"
const int MAX_NAME_LENGTH = 32;
const int N_PLACES = 3;
const int N_ROWS = 3;
const std::string FileName("SimulationResults-test.h5");
const std::string DatasetName("SimulationData");
const std::string member_simulation("Simulation");
const std::string member_iteration("Iteration");
const std::string member_time_elapsed("Time_elapsed");
const std::string member_place_states("States");
const std::string member_fired_transition("Fired_transition");
typedef struct {
int simulation;
int iteration;
double time_elapsed;
char fired_transition[MAX_NAME_LENGTH];
int * place_states;
} SimulationData;
typedef struct {
int simulation;
int iteration;
double time_elapsed;
char fired_transition[MAX_NAME_LENGTH]; // MAX_NAME_LENGTH
hvl_t place_states; // N_PLACES
} SimulationData_buffer;
int main(void) {
// Data to write
SimulationData states_simulation[N_ROWS];
SimulationData_buffer states_simulation_buffer[N_ROWS];
// {
// { 1, 0, 0.0, {0, 0, 0}, "T1" },
// { 1, 1, 1.0, {0, 1, 0}, "T2" },
// { 1, 2, 5.0, {0, 0, 1}, "T1" }
// };
for (int i = 0; i< N_ROWS; i++) {
states_simulation[i].simulation = 1;
states_simulation[i].iteration = 0;
states_simulation[i].time_elapsed = 0.0;
// states_simulation[i].fired_transition = "T1";
strncpy(states_simulation[i].fired_transition, "T1",
sizeof(states_simulation[i].fired_transition) - 1);
states_simulation[i].fired_transition[sizeof(states_simulation[i].fired_transition) - 1] = 0;
states_simulation[i].place_states = new int[N_PLACES];
states_simulation[i].place_states[0] = 0;
states_simulation[i].place_states[1] = 10;
states_simulation[i].place_states[2] = 20;
}
// Number of rows
hsize_t dim[] = {sizeof(states_simulation) / sizeof(SimulationData)};
// Dimension of each row
int rank = sizeof(dim) / sizeof(hsize_t);
// defining the datatype to pass HDF5
H5::CompType mtype(sizeof(SimulationData_buffer));
mtype.insertMember(member_simulation,
HOFFSET(SimulationData, simulation),
H5::PredType::NATIVE_INT);
mtype.insertMember(member_iteration,
HOFFSET(SimulationData, iteration),
H5::PredType::NATIVE_INT);
mtype.insertMember(member_time_elapsed,
HOFFSET(SimulationData, time_elapsed),
H5::PredType::NATIVE_DOUBLE);
mtype.insertMember(member_fired_transition,
HOFFSET(SimulationData, fired_transition),
H5::StrType(H5::PredType::C_S1, MAX_NAME_LENGTH));
auto vlen_id_places = H5::VarLenType(H5::PredType::NATIVE_INT);
// Set different columns for the array <-------------------------
// auto offset = HOFFSET(SimulationData, place_states);
// for (int i = 0; i < N_PLACES; i++) {
// std::stringstream ss;
// ss << "Place_" << i+1;
// auto new_offset = offset + i*sizeof(int);
// std::cout << offset << " -> " << new_offset << std::endl;
// mtype.insertMember(ss.str(),
// new_offset,
// H5::PredType::NATIVE_INT);
// }
// Set the column as an array <-----------------------------------
mtype.insertMember("Places", HOFFSET(SimulationData, place_states), vlen_id_places);
// Filling buffer
for (int i = 0; i < N_ROWS; ++i) {
states_simulation_buffer[i].simulation = states_simulation[i].simulation;
states_simulation_buffer[i].iteration = states_simulation[i].iteration;
states_simulation_buffer[i].time_elapsed = states_simulation[i].time_elapsed;
strncpy(states_simulation_buffer[i].fired_transition,
states_simulation[i].fired_transition,
MAX_NAME_LENGTH);
states_simulation_buffer[i].place_states.len = N_PLACES;
states_simulation_buffer[i].place_states.p = states_simulation[i].place_states;
}
// preparation of a dataset and a file.
H5::DataSpace space(rank, dim);
H5::H5File *file = new H5::H5File(FileName, H5F_ACC_TRUNC);
H5::DataSet *dataset = new H5::DataSet(file->createDataSet(DatasetName,
mtype,
space));
H5::DataSet *dataset2 = new H5::DataSet(file->createDataSet("Prueba2",
mtype,
space));
// Write
dataset->write(states_simulation_buffer, mtype);
dataset2->write(states_simulation_buffer, mtype);
delete dataset;
delete file;
return 0;
}
Может быть скомпилировано с g++ h5-test-dynamic.cpp -lhdf5 -lhdf5_cpp -o h5-test-dynamic
.
Как уже говорилось, мне нужно один столбец на значение, а не массив в одном столбце. Я не знаю, почему это не работает, поскольку я правильно установил указатели и смещения для переменной hvl_t
. Если я переключаюсь на блок кода, который обрабатывает смещения и типы данных вручную, и выключаю один сразу же после этого, я получаю значения мусора.
Вот что я получаю
[(1, 0, 0., b'T1', 3, 0, -971058832),
(1, 0, 0., b'T1', 3, 0, -971058800),
(1, 0, 0., b'T1', 3, 0, -971058768)]
И это лучшее, что я могу получить
[(1, 0, 0., b'T1', array([ 0, 10, 20], dtype=int32)),
(1, 0, 0., b'T1', array([ 0, 10, 20], dtype=int32)),
(1, 0, 0., b'T1', array([ 0, 10, 20], dtype=int32))]