Search code examples
c++stldatasetallocationhdf5

How to write out struct containing multiple std::vector<float> to HDF5 using variable length type?


I am trying to write a c-struct (that describes a dummy "event") to HDF5 format. The struct contains 4 vectors of floats, that will have different length for each event (the events will be grouped together in the HDF5 file) and hence should be written to file using a variable length type. However, after writing the data using a "buffer-struct", only every other vector is written to the file (1 and 3 in the code below). The others are None. What am I doing wrong?

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include "H5Cpp.h"

const char * FILE_NAME = "test.h5";

const double HI   =  300.0;
const double LO   = -20.0;

typedef struct
{
    int ID;
    float energy;
    std::vector<float> v1, v2, v3, v4;
} event_struct;

typedef struct
{
    int ID;
    float energy;
    hvl_t v1Handle, v2Handle, v3Handle, v4Handle;
} event_struct_buffer;

int main(void)
{
    event_struct* event = new event_struct();

    event_struct_buffer* event_buffer = new event_struct_buffer();

    event->ID = 5;
    event->energy = 23.45;

    int n1 = 10;
    int n2 = 8;
    int n3 = 4;
    int n4 = 2;

    for( int i = 0;  i < n1; ++i ){
        float x = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));
        event->v1.push_back(x);
        std::cout << x << ' ';
        if( i < n2 ){
            event->v2.push_back(x/2);
            if( i < n3 ){
                event->v3.push_back(x/3);
                if( i < n4 ){
                    event->v4.push_back(x/5);
                }
            }
        }
    }// end for loop
    std::cout << std::endl;

    hid_t      event_tid;                          /* File datatype identifier */
    hid_t      file, dataset, space, vlen_tid;  /* Handles */
    hsize_t    dim[] = {1};                /* Dataspace dimensions */

    int rank = sizeof(dim) / sizeof(hsize_t);
    std::cout << "Rank = " << rank << std::endl;

    space = H5Screate_simple(rank, dim, NULL);

    file = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

    vlen_tid = H5Tvlen_create(H5T_NATIVE_FLOAT);

    event_tid = H5Tcreate( H5T_COMPOUND, sizeof(event_struct_buffer) );
    H5Tinsert(event_tid, "Event_ID", HOFFSET(event_struct_buffer, ID), H5T_NATIVE_INT);
    H5Tinsert(event_tid, "Energy", HOFFSET(event_struct_buffer, energy), H5T_NATIVE_FLOAT);
    H5Tinsert(event_tid, "Image1", HOFFSET(event_struct_buffer, v1Handle), vlen_tid);
    H5Tinsert(event_tid, "Image2", HOFFSET(event_struct_buffer, v2Handle), vlen_tid);
    H5Tinsert(event_tid, "Image3", HOFFSET(event_struct_buffer, v3Handle), vlen_tid);
    H5Tinsert(event_tid, "Image4", HOFFSET(event_struct_buffer, v4Handle), vlen_tid);

    dataset = H5Dcreate(file, "/Events_List", event_tid, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

    event_buffer->ID = event->ID;
    event_buffer->energy = event->energy;
    event_buffer->v1Handle.len = event->v1.size();
    event_buffer->v1Handle.p = event->v1.data();
    event_buffer->v2Handle.len = event->v2.size();
    event_buffer->v2Handle.p = event->v2.data();
    event_buffer->v3Handle.len = event->v3.size();
    event_buffer->v3Handle.p = event->v3.data();
    event_buffer->v4Handle.len = event->v4.size();
    event_buffer->v4Handle.p = event->v4.data();

    H5Dwrite(dataset, event_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, event_buffer);

    H5Tclose(event_tid);
    H5Tclose(vlen_tid);
    H5Sclose(space);
    H5Dclose(dataset);
    H5Fclose(file);
    return 0;
}

The pseudo-rand list of numbers is:

-19.9975 22.0921 221.794 126.768 150.486 50.0669 -4.94572 197.237 197.375 279.102

and the output I get when reading the HDF5 file with h5py is:

[ (5, 23.450000762939453, [-19.997495651245117, 22.09209442138672, 221.793701171875, 
126.76803588867188, 150.4855194091797, 50.06694030761719, -4.945722579956055, 
197.23670959472656, 197.37486267089844, 279.1017150878906],
[-6.665832042694092, 7.3640313148498535, 73.93123626708984, 42.256011962890625], None, None)]

Thanks for your help.


Solution

  • The problem was actually reading the h5 file with h5py (and also with tables). When running h5dump test.h5, the data structure and the values in all vectors and all events (I write eventually a vector of event_struct's with 4 variable length std::vector in each event) are filled in correctly. I also use only one struct and added the hvl_t handles to the event_struct.