2011-09-14 19 views
8

2B dizi veri kümesi dosyalarını yazmak için HDF5 C++ API kullanıyorum. HDF Grubu, gereksinimlerimi karşılamak için değiştirdiğim statik olarak tanımlanmış bir dizi boyutundan an example to create bir HDF5 dosyasına sahiptir. Ancak, dinamik bir diziye ihtiyacım var, burada hem NX hem de NY çalışma zamanında belirlendi. Dinamik bir dizi oluşturmaya yardımcı olmak için another solution to create 2D arrays using the "new" keyword buldum.HDF5 C++ arabirimi: dinamik 2B dizilerini yazma

#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; 
} 

sonuç dosyası Ancak beklenmediği (hdf5dump çıktısı):

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 
     } 
    } 
} 
} 

sorun 2D array nasıl oluşturulduğuna geri sapları (bu yana İşte ne var örnek bir statik dizi yöntemi ile iyi çalışıyor). Ben this email thread anladığımız gibi:

HDF5 kütüphane elemanlarının bitişik bir dizide beklediğini, alt boyutlarda elemanlarına değil işaretçileri

C++/HDF5 oldukça yeni olduğum için, ben Bitişik bir dizi eleman olan çalışma zamanında dinamik olarak boyutlandırılmış bir dizinin nasıl oluşturulacağından emin değilsiniz. Çok karmaşık göründüğünden, e-posta dizisinde açıklanan daha karmaşık "hiperslab" yöntemini yapmak istemiyorum. Herhangi bir yardım takdir edilir.

cevap

7

HDF5 hakkında bir şey bilmiyorum, ancak C + 'da bitişik bir arabelleğe sahip dinamik 2D dizileri, 0Dboyutunda bir 1D dizisi kullanılarak simüle edilebilir.

Tahsisi:

double *data = new double[NX*NY]; 

Eleman erişimi: Büyük bir 1D dizi olarak çok boyutlu diziler temsil etmek yaygındır

data[j*NY + i] 

bilimsel programlamada

+1

Bu çözüm uygulamak kolaydır ve (Ben de gerçekten ölçekler 21.9M elemanları ile dizi boyutları kullanarak). Sonuç, HDF5 dosya çıkışında mükemmel bir şekilde doğrulanır. –

+0

Bir çekicilik gibi çalışır. Teşekkür ederim. – CuriousCase

+0

Bunun çok eski olduğunu biliyorum, ama sanırım son cümlede bir hata var. Olması gereken: (yerine [i] [j] ') –

2

(yerine data[j][i] arasında) ve Örnek Daha sonra, çok boyutlu endekslerden karşılık gelen ofsetin hesaplanması, örn. Doc Brown'un cevabında görüldüğü gibi.

Alternatif olarak, 1D dizisiyle desteklenen çok boyutlu göstergelerin kullanımına izin veren bir arabirim sağlamak için alt simge işlecini (operator[]()) aşırı yükleyebilirsiniz. Veya daha iyisi, Boost multi_array gibi bir kütüphane kullanın. Veya 2D dizileriniz matrisler ise, Eigen gibi güzel bir C++ lineer cebir kitaplığı kullanabilirsiniz. İşte

5

O boostmulti_array sınıfını kullanmak çok daha iyidir HDF5 formatında

N boyut diziler yazmak için nasıl. Bu, ham diziler yerine std::vector kullanmanın eşdeğeridir: Bu sizin için tüm bellek yönetimini yapar ve tanıdık aboneliği kullanarak öğelere ham diziler kadar verimli şekilde erişebilirsiniz (ör.

#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); 

son satır herhangi bir boyut ve herhangi bir standart numarası (ints, chars, floats vb) multi_array s bilgileri bir işlevini çağırır: data[12][13] = 46)

Burada kısa bir örnektir.

write_hdf5() için kod burada.

Öncelikle, HDF5 türlerine C++ tiplerini (H5 C++ API itibaren) map gerekir:

#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 }; }; 

Sonra çıkışa doğru türde bir işlev yapmak için sihirli iletme şablonun biraz kullanabilirsiniz bizim veri. Bu şablon kodu olduğundan, programınızda birden fazla kaynak dosyaları çıktı HDF5 diziler olacak eğer bir başlık dosyasında yaşamak gerekir:

//!_______________________________________________________________________________________ 
//!  
//!  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); 
}