Mik*_*e T 11 c++ dynamic-data hdf5 multidimensional-array
我正在使用HDF5 C++ API编写2D数组数据集文件.HDF小组有一个例子来创建一个静态定义的数组大小的HDF5文件,我已经修改过以满足下面的需求.然而,我需要动态阵列,其中两个NX和NY在运行时确定.我找到了另一种使用"new"关键字创建2D数组的解决方案,以帮助创建动态数组.这是我有的:
#include "StdAfx.h"
#include "H5Cpp.h"
using namespace H5;
const H5std_string FILE_NAME("C:\\SDS.h5");
const H5std_string DATASET_NAME("FloatArray");
const int NX = 5; // dataset dimensions
const int NY = 6;
int main (void)
{
// Create a 2D array using "new" method
double **data = new double*[NX];
for (int j = 0; j < NX; j++) // 0 1 2 3 4 5
{ // 1 2 3 4 5 6
data[j] = new double[NY]; // 2 3 4 5 6 7
for (int i = 0; i < NY; i++) // 3 4 5 6 7 8
data[j][i] = (float)(i + j); // 4 5 6 7 8 9
}
// Create HDF5 file and dataset
H5File file(FILE_NAME, H5F_ACC_TRUNC);
hsize_t dimsf[2] = {NX, NY};
DataSpace dataspace(2, dimsf);
DataSet dataset = file.createDataSet(DATASET_NAME, PredType::NATIVE_DOUBLE,
dataspace);
// Attempt to write data to HDF5 file
dataset.write(data, PredType::NATIVE_DOUBLE);
// Clean up
for(int j = 0; j < NX; j++)
delete [] data[j];
delete [] data;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,生成的文件不符合预期(输出hdf5dump):
HDF5 "SDS.h5" {
GROUP "/" {
DATASET "FloatArray" {
DATATYPE H5T_IEEE_F64LE
DATASPACE SIMPLE { ( 5, 6 ) / ( 5, 6 ) }
DATA {
(0,0): 4.76465e-307, 4.76541e-307, -7.84591e+298, -2.53017e-098, 0,
(0,5): 3.8981e-308,
(1,0): 4.76454e-307, 0, 2.122e-314, -7.84591e+298, 0, 1,
(2,0): 2, 3, 4, 5, -2.53017e-098, -2.65698e+303,
(3,0): 0, 3.89814e-308, 4.76492e-307, 0, 2.122e-314, -7.84591e+298,
(4,0): 1, 2, 3, 4, 5, 6
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题可以追溯到如何创建2D数组(因为这个示例使用静态数组方法可以正常工作).据我所知,从这个电子邮件主题:
HDF5库需要一个连续的元素数组,而不是指向较低维度元素的指针
由于我是C++/HDF5的新手,我不确定如何在运行时创建一个动态大小的数组,这是一个连续的元素数组.我不想做电子邮件主题中描述的更复杂的"hyperslab"方法,因为这看起来过于复杂.任何帮助表示赞赏.
好吧,我对HDF5一无所知,但可以使用一维大小的数组来模拟C++中带有连续缓冲区的动态二维数组NX * NY.例如:
分配:
double *data = new double[NX*NY];
Run Code Online (Sandbox Code Playgroud)
元素访问:
data[j*NY + i]
Run Code Online (Sandbox Code Playgroud)
(而不是data[j][i])
以下是如何以HDF5格式编写N维数组
使用boost multi_array类要好得多.这相当于使用std::vector而不是原始数组:它为您完成所有内存管理,您可以使用熟悉的下标(例如data[12][13] = 46)像原始数组一样高效地访问元素
这是一个简短的例子:
#include <algorithm>
#include <boost/multi_array.hpp>
using boost::multi_array;
using boost::extents;
// dataset dimensions set at run time
int NX = 5, NY = 6, NZ = 7;
// allocate array using the "extents" helper.
// This makes it easier to see how big the array is
multi_array<double, 3> float_data(extents[NX][NY][NZ]);
// use resize to change size when necessary
// float_data.resize(extents[NX + 5][NY + 4][NZ + 3]);
// This is how you would fill the entire array with a value (e.g. 3.0)
std::fill_n(float_data.data(), float_data.num_elements(), 3.0)
// initialise the array to some variables
for (int ii = 0; ii != NX; ii++)
for (int jj = 0; jj != NY; jj++)
for (int kk = 0; kk != NZ; kk++)
float_data[ii][jj][kk] = ii + jj + kk
// write to HDF5 format
H5::H5File file("SDS.h5", H5F_ACC_TRUNC);
write_hdf5(file, "doubleArray", float_data );
Run Code Online (Sandbox Code Playgroud)
最后一行调用可写的函数multi_array的任何尺寸和任何标准编号类型(第ints,chars,floats等等).
这是代码write_hdf5().
首先,我们必须将c ++类型映射到HDF5类型(来自H5c ++ api):
#include <cstdint>
//!_______________________________________________________________________________________
//!
//! map types to HDF5 types
//!
//!
//! \author lg (04 March 2013)
//!_______________________________________________________________________________________
template<typename T> struct get_hdf5_data_type
{ static H5::PredType type()
{
//static_assert(false, "Unknown HDF5 data type");
return H5::PredType::NATIVE_DOUBLE;
}
};
template<> struct get_hdf5_data_type<char> { H5::IntType type { H5::PredType::NATIVE_CHAR }; };
//template<> struct get_hdf5_data_type<unsigned char> { H5::IntType type { H5::PredType::NATIVE_UCHAR }; };
//template<> struct get_hdf5_data_type<short> { H5::IntType type { H5::PredType::NATIVE_SHORT }; };
//template<> struct get_hdf5_data_type<unsigned short> { H5::IntType type { H5::PredType::NATIVE_USHORT }; };
//template<> struct get_hdf5_data_type<int> { H5::IntType type { H5::PredType::NATIVE_INT }; };
//template<> struct get_hdf5_data_type<unsigned int> { H5::IntType type { H5::PredType::NATIVE_UINT }; };
//template<> struct get_hdf5_data_type<long> { H5::IntType type { H5::PredType::NATIVE_LONG }; };
//template<> struct get_hdf5_data_type<unsigned long> { H5::IntType type { H5::PredType::NATIVE_ULONG }; };
template<> struct get_hdf5_data_type<long long> { H5::IntType type { H5::PredType::NATIVE_LLONG }; };
template<> struct get_hdf5_data_type<unsigned long long> { H5::IntType type { H5::PredType::NATIVE_ULLONG }; };
template<> struct get_hdf5_data_type<int8_t> { H5::IntType type { H5::PredType::NATIVE_INT8 }; };
template<> struct get_hdf5_data_type<uint8_t> { H5::IntType type { H5::PredType::NATIVE_UINT8 }; };
template<> struct get_hdf5_data_type<int16_t> { H5::IntType type { H5::PredType::NATIVE_INT16 }; };
template<> struct get_hdf5_data_type<uint16_t> { H5::IntType type { H5::PredType::NATIVE_UINT16 }; };
template<> struct get_hdf5_data_type<int32_t> { H5::IntType type { H5::PredType::NATIVE_INT32 }; };
template<> struct get_hdf5_data_type<uint32_t> { H5::IntType type { H5::PredType::NATIVE_UINT32 }; };
template<> struct get_hdf5_data_type<int64_t> { H5::IntType type { H5::PredType::NATIVE_INT64 }; };
template<> struct get_hdf5_data_type<uint64_t> { H5::IntType type { H5::PredType::NATIVE_UINT64 }; };
template<> struct get_hdf5_data_type<float> { H5::FloatType type { H5::PredType::NATIVE_FLOAT }; };
template<> struct get_hdf5_data_type<double> { H5::FloatType type { H5::PredType::NATIVE_DOUBLE }; };
template<> struct get_hdf5_data_type<long double> { H5::FloatType type { H5::PredType::NATIVE_LDOUBLE }; };
Run Code Online (Sandbox Code Playgroud)
然后我们可以使用一些模板转发魔术来生成正确类型的函数来输出我们的数据.由于这是模板代码,如果要从程序中的多个源文件输出HDF5数组,它需要存在于头文件中:
//!_______________________________________________________________________________________
//!
//! write_hdf5 multi_array
//!
//! \author leo Goodstadt (04 March 2013)
//!
//!_______________________________________________________________________________________
template<typename T, std::size_t DIMENSIONS, typename hdf5_data_type>
void do_write_hdf5(H5::H5File file, const std::string& data_set_name, const boost::multi_array<T, DIMENSIONS>& data, hdf5_data_type& datatype)
{
// Little endian for x86
//FloatType datatype(get_hdf5_data_type<T>::type());
datatype.setOrder(H5T_ORDER_LE);
vector<hsize_t> dimensions(data.shape(), data.shape() + DIMENSIONS);
H5::DataSpace dataspace(DIMENSIONS, dimensions.data());
H5::DataSet dataset = file.createDataSet(data_set_name, datatype, dataspace);
dataset.write(data.data(), datatype);
}
template<typename T, std::size_t DIMENSIONS>
void write_hdf5(H5::H5File file, const std::string& data_set_name, const boost::multi_array<T, DIMENSIONS>& data )
{
get_hdf5_data_type<T> hdf_data_type;
do_write_hdf5(file, data_set_name, data, hdf_data_type.type);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9287 次 |
| 最近记录: |