Можно ли хранить элементы из динамических массивов в разных столбцах в HDF5? - PullRequest
0 голосов
/ 21 января 2019

Я пытаюсь сохранить данные моделирования из 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))]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...