LoginSignup
1
0

More than 1 year has passed since last update.

HDF5をC++で使う:(その3)複合データ型

Posted at

データセットに格納できるデータ型は一種類だけなのか?

これまでの説明(その1)(その2)では、データセットに格納するデータ型はH5::PredType::STD_I32LEに限定していました。/usr/include/hdf5/serial/H5PredType.hを見ると他にも色々(例えばfloat型に相当するIEEE_F32BE/IEEE_F32LE、double型に相当するIEEE_F64BE/IEEE_F64LEなど)あるのですが、元のデータがある構造体の場合には、これを要素とした配列をそのまま格納したくなります。

この場合、Predefinedな型ではなく自分で複合型H5::CompTypeを定義することができます。

複合型のデータ配列書き出しサンプル

次のようなサンプルプログラムを作ってみました。

#include <iostream>
#include <H5Cpp.h>

#define DATASET_NAME "/dataset"

struct cdata_t{
  int    i_data;
  float  f_data;
  double d_data;
};

#define MEMBER1 "int_data"
#define MEMBER2 "float_data"
#define MEMBER3 "double_data"

#define N 5

int main(int argc, char *argv[])
{
  H5::Exception::dontPrint();
  H5::H5File file( argv[1], H5F_ACC_TRUNC );

  hsize_t dims[] = { N };
  H5::DataSpace dataspace( sizeof(dims) / sizeof(hsize_t), dims );
  H5::CompType comptype( sizeof(cdata_t) );
  comptype.insertMember( MEMBER1, HOFFSET(cdata_t,i_data), H5::PredType::NATIVE_INT );
  comptype.insertMember( MEMBER2, HOFFSET(cdata_t,f_data), H5::PredType::NATIVE_FLOAT );
  comptype.insertMember( MEMBER3, HOFFSET(cdata_t,d_data), H5::PredType::NATIVE_DOUBLE );
  H5::DataSet dataset = file.createDataSet( DATASET_NAME, comptype, dataspace );

  cdata_t *data = new cdata_t [dims[0]];
  for(int i=0; i<static_cast<int>(dims[0]); i++ ){
    data[i].i_data = i;
    data[i].f_data = i * i;
    data[i].d_data = 1.0 / (i+1);
  }
  dataset.write( data, comptype );
  delete data;
  dataset.close();

  file.close();
  return 0;
}

例によって処理を追っていきましょう。最初に構造体cdata_tを定義し、それぞれのメンバに対応する文字列を決めています。

struct cdata_t{
  int    i_data;
  float  f_data;
  double d_data;
};

#define MEMBER1 "int_data"
#define MEMBER2 "float_data"
#define MEMBER3 "double_data"

main()関数最初のファイルオープンは横着しています。

  H5::Exception::dontPrint();
  H5::H5File file( argv[1], H5F_ACC_TRUNC );

データスペース作成はこれまでと同様です。

  hsize_t dims[] = { N };
  H5::DataSpace dataspace( sizeof(dims) / sizeof(hsize_t), dims );

次が複合データ型を定義している部分になります。

  H5::CompType comptype( sizeof(cdata_t) );
  comptype.insertMember( MEMBER1, HOFFSET(cdata_t,i_data), H5::PredType::NATIVE_INT );
  comptype.insertMember( MEMBER2, HOFFSET(cdata_t,f_data), H5::PredType::NATIVE_FLOAT );
  comptype.insertMember( MEMBER3, HOFFSET(cdata_t,d_data), H5::PredType::NATIVE_DOUBLE );

何をしているかはおおよそご想像頂けると思います。コンストラクタにsizeof( cdata_t )を与えることで、これから定義する型のメモリサイズを指定し、その後にinsertMember()メソッドを使ってメンバーを一つ一つ登録しています。

HOFFSET()は構造体の各メンバーの相対アドレスを返すマクロで、H5Cpp.hに定義されています。標準のoffsetof()を使っても構いません。それぞれのメンバーが具体的にどの型であるのかを第3引数で指定しています。ここを自動判別させるのは難しいようです。

データセット作成時には、定義したcomptypeをそのままH5::DataTypeインスタンスとして与えられます。

  H5::DataSet dataset = file.createDataSet( DATASET_NAME, comptype, dataspace );

続くforループで適当にデータを作成し、

  dataset.write( data, comptype );

として書き出します。最後にデータセットとファイルを閉じて終了です。

  dataset.close();

  file.close();

複合データ型配列の例

上記のプログラムを実行し、test.h5を作成しました。これをh5dumpで見ると次のように出力されます。

HDF5 "test.h5" {
GROUP "/" {
   DATASET "dataset" {
      DATATYPE  H5T_COMPOUND {
         H5T_STD_I32LE "int_data";
         H5T_IEEE_F32LE "float_data";
         H5T_IEEE_F64LE "double_data";
      }
      DATASPACE  SIMPLE { ( 5 ) / ( 5 ) }
      DATA {
      (0): {
            0,
            0,
            1
         },
      (1): {
            1,
            1,
            0.5
         },
      (2): {
            2,
            4,
            0.333333
         },
      (3): {
            3,
            9,
            0.25
         },
      (4): {
            4,
            16,
            0.2
         }
      }
   }
}
}

データ型自体はH5T_COMPOUNDと表現されています。そしてそれが、

  H5T_STD_I32LE "int_data";
  H5T_IEEE_F32LE "float_data";
  H5T_IEEE_F64LE "double_data";

という3つの型(と対応する文字列)を持つことが見て取れます。定義時にはNATIVE_INT、NATIVE_FLOAT、NATIVE_DOUBLEとしたものが、それぞれSTD_I32LE、IEEE_F32LE、IEEE_F64LEと解釈されていることにご注意下さい。これは実行したCPUに依存します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0