File indexing completed on 2024-12-22 04:17:15
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2007 The University of Toronto * 0004 * netterfield@astro.utoronto.ca * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 ***************************************************************************/ 0012 0013 #include "hdf5.h" 0014 0015 #include <QXmlStreamWriter> 0016 #include <QImageReader> 0017 #include <qcolor.h> 0018 0019 using namespace Kst; 0020 0021 /********************** 0022 HDF5Source::Config - This class defines the config widget that will be added to the 0023 Dialog Config Button for configuring the plugin. This is only needed for special handling required 0024 by the plugin. Many plugins will not require configuration. See plugins/sampleplugin for additional 0025 details. 0026 0027 ***********************/ 0028 class HDF5Source::Config { 0029 public: 0030 Config() { 0031 } 0032 0033 void read(QSettings *cfg, const QString& fileName = QString()) { 0034 Q_UNUSED(fileName); 0035 cfg->beginGroup("HDF5"); 0036 cfg->endGroup(); 0037 } 0038 0039 void save(QXmlStreamWriter& s) { 0040 Q_UNUSED(s); 0041 } 0042 0043 void load(const QDomElement& e) { 0044 Q_UNUSED(e); 0045 } 0046 }; 0047 0048 // 0049 // Vector Interface 0050 // 0051 0052 class DataInterfaceHDF5Vector : public DataSource::DataInterface < DataVector > { 0053 0054 public: 0055 DataInterfaceHDF5Vector(HDF5Source& s) : hdf(s) {} 0056 0057 //read one element 0058 int read(const QString&, DataVector::ReadInfo&); 0059 0060 //Named Elements 0061 QStringList list() const { return hdf._vectorList; } 0062 bool isListComplete() const { return true; } 0063 bool isValid(const QString& field) const { return hdf._fieldList.contains( field ); } 0064 0065 const DataVector::DataInfo dataInfo(const QString&, int frame = 0) const; 0066 void setDataInfo(const QString&, const DataVector::DataInfo&) {} 0067 0068 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0069 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0070 0071 HDF5Source& hdf; 0072 }; 0073 0074 const DataVector::DataInfo DataInterfaceHDF5Vector::dataInfo(const QString &field, int frame) const { 0075 Q_UNUSED(frame) 0076 0077 if(!isValid(field)){ 0078 return DataVector::DataInfo(); 0079 }else{ 0080 return DataVector::DataInfo(hdf.frameCount(field), hdf.samplesPerFrame(field)); 0081 } 0082 } 0083 0084 int DataInterfaceHDF5Vector::read(const QString& field, DataVector::ReadInfo& p){ 0085 return hdf.readField(p.data, field, p.startingFrame, p.numberOfFrames); 0086 } 0087 0088 0089 // 0090 // Matrix Interface 0091 // 0092 0093 class DataInterfaceHDF5Matrix : public DataSource::DataInterface<DataMatrix>{ 0094 public: 0095 DataInterfaceHDF5Matrix(HDF5Source& s) : hdf(s) {} 0096 0097 //read one element 0098 int read(const QString&, DataMatrix::ReadInfo&); 0099 0100 //named elements 0101 QStringList list() const { return hdf._matrixList; } 0102 bool isListComplete() const { return true; } 0103 bool isValid(const QString& field) const { return hdf._matrixList.contains( field ); } 0104 0105 // T Specific: still don't know what that means 0106 const DataMatrix::DataInfo dataInfo(const QString&, int frame = 0) const; 0107 void setDataInfo(const QString&, const DataMatrix::DataInfo&) {} 0108 0109 // meta data 0110 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0111 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0112 0113 HDF5Source& hdf; 0114 }; 0115 0116 int DataInterfaceHDF5Matrix::read(const QString& field, DataMatrix::ReadInfo& p){ 0117 //TODO: figure this out 0118 return hdf.readMatrix(p, field); 0119 } 0120 0121 const DataMatrix::DataInfo DataInterfaceHDF5Matrix::dataInfo(const QString &field, int frame) const { 0122 0123 Q_UNUSED(frame) 0124 if (!isValid(field)){ 0125 return DataMatrix::DataInfo(); 0126 }else{//get x and y dimentions of the matrix 0127 //Debug::self()->log(QString("Getting data info for matrix ") + field); 0128 DataMatrix::DataInfo info; 0129 if(field.contains("->")){ 0130 QStringList list = field.split("->"); 0131 0132 QString fieldName = list[0]; 0133 QString attrName = list[list.size() -1]; 0134 H5::Attribute attr = hdf._hdfFile->openDataSet(qPrintable(fieldName)).openAttribute(qPrintable(attrName)); 0135 0136 hsize_t* sizes = new hsize_t[2]; 0137 attr.getSpace().getSimpleExtentDims(sizes, NULL); 0138 info.xSize = sizes[0]; 0139 info.ySize = sizes[1]; 0140 //Debug::self()->log(QString::number(sizes[0]) + QString(" is xsize in datainfo, y is ") + QString::number(sizes[1])); 0141 delete[] sizes; 0142 return info; 0143 0144 }else{ 0145 0146 H5::DataSet dataset = hdf._hdfFile->openDataSet(qPrintable(field)); 0147 hsize_t* sizes = new hsize_t[2]; 0148 dataset.getSpace().getSimpleExtentDims(sizes, NULL); 0149 info.xSize = sizes[0]; 0150 info.ySize = sizes[1]; 0151 //Debug::self()->log(QString::number(sizes[0]) + QString(" is xsize in datainfo, y is ") + QString::number(sizes[1])); 0152 0153 delete[] sizes; 0154 return info; 0155 } 0156 } 0157 } 0158 0159 // 0160 // Scalar Interface 0161 // 0162 0163 class DataInterfaceHDF5Scalar : public DataSource::DataInterface<DataScalar>{ 0164 public: 0165 DataInterfaceHDF5Scalar(HDF5Source & s) : hdf(s) {} 0166 0167 //read one element 0168 int read(const QString&, DataScalar::ReadInfo&); 0169 0170 //Named Elements 0171 QStringList list() const { return hdf._scalarList; } 0172 bool isListComplete() const { return true; } 0173 bool isValid(const QString& field) const { return hdf._scalarList.contains( field ); } 0174 0175 //T specific: not used for scalars 0176 const DataScalar::DataInfo dataInfo(const QString&, int frame=0) const {Q_UNUSED(frame) return DataScalar::DataInfo(); } 0177 void setDataInfo(const QString&, const DataScalar::DataInfo&) {} 0178 0179 //meta data 0180 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0181 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0182 0183 0184 HDF5Source& hdf; 0185 }; 0186 0187 int DataInterfaceHDF5Scalar::read(const QString& field, DataScalar::ReadInfo& p){ 0188 return hdf.readScalar(*p.value, field); 0189 } 0190 0191 // 0192 // String Interface 0193 // 0194 class DataInterfaceHDF5String : public DataSource::DataInterface<DataString> 0195 { 0196 public: 0197 DataInterfaceHDF5String(HDF5Source& s) : hdf(s) {} 0198 0199 // read one element 0200 int read(const QString&, DataString::ReadInfo&); 0201 0202 // named elements 0203 QStringList list() const { return hdf._stringList; } 0204 bool isListComplete() const { return true; } 0205 bool isValid(const QString& field) const { return hdf._stringList.contains( field ); } 0206 0207 // T specific: not used for Strings 0208 virtual const DataString::DataInfo dataInfo(const QString&name, int frame=0) const; 0209 void setDataInfo(const QString&, const DataString::DataInfo&) {} 0210 0211 // meta data 0212 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0213 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0214 0215 0216 HDF5Source& hdf; 0217 }; 0218 0219 int DataInterfaceHDF5String::read(const QString& field, DataString::ReadInfo& p) 0220 { 0221 return hdf.readString(*p.value, field); 0222 } 0223 0224 const DataString::DataInfo DataInterfaceHDF5String::dataInfo(const QString & name, int frame) const 0225 { 0226 Q_UNUSED(frame) 0227 //Debug::self()->log(QString("Getting data info for string ") + name); 0228 0229 DataString::DataInfo info; 0230 info.frameCount = 1; 0231 0232 return info; 0233 } 0234 0235 0236 /********************** 0237 HDF5Source - This class defines the main DataSource which derives from DataSource. 0238 The key functions that this class must provide is the ability to create the source, provide details about the source 0239 be able to process the data. 0240 0241 ***********************/ 0242 HDF5Source::HDF5Source(Kst::ObjectStore *store, QSettings *cfg, const QString& filename, const QString& type, const QDomElement& e) 0243 : Kst::DataSource(store, cfg, filename, type), _config(0L), 0244 iv(new DataInterfaceHDF5Vector(*this)), 0245 ix(new DataInterfaceHDF5Scalar(*this)), 0246 im(new DataInterfaceHDF5Matrix(*this)), 0247 is(new DataInterfaceHDF5String(*this)), _resetNeeded(false) 0248 { 0249 setInterface(iv); 0250 setInterface(ix); 0251 setInterface(im); 0252 setInterface(is); 0253 0254 startUpdating(None); 0255 0256 _valid = false; 0257 if (!type.isEmpty() && type != "HDF5") { 0258 return; 0259 } 0260 0261 _config = new HDF5Source::Config; 0262 _config->read(cfg, filename); 0263 if (!e.isNull()) { 0264 _config->load(e); 0265 } 0266 0267 _directoryName = filename; 0268 0269 if (init()) { 0270 _valid = true; 0271 } 0272 0273 registerChange(); 0274 } 0275 0276 HDF5Source::~HDF5Source() { 0277 delete _config; 0278 _config = NULL; 0279 if(_hdfFile != NULL){ 0280 delete _hdfFile; 0281 } 0282 _hdfFile = NULL; 0283 } 0284 0285 0286 void HDF5Source::reset() { 0287 if(_hdfFile){ 0288 delete _hdfFile; 0289 } 0290 if(_config){ 0291 delete _config; 0292 } 0293 0294 init(); 0295 Object::reset(); 0296 } 0297 0298 herr_t HDF5Source::visitFunc(hid_t id, const char* name, const H5L_info_t* info, void* opData){ 0299 0300 //Debug::self()->log(QString("Visiting ") + name); 0301 HDF5Source* h5Source = static_cast<HDF5Source*> (opData); 0302 0303 herr_t status; 0304 H5O_info_t infobuf; 0305 0306 if(QString(name).contains("->")){ 0307 Debug::self()->log(QString("Skipping dataset ") + name + QString(" because it contains reserved string ->")); 0308 return 0; 0309 } 0310 0311 #if H5_VERSION_GE(1,12,0) 0312 status = H5Oget_info_by_name(id, name, &infobuf, H5O_INFO_BASIC, H5P_DEFAULT); 0313 #else 0314 status = H5Oget_info_by_name(id, name, &infobuf, H5P_DEFAULT); 0315 #endif 0316 if(status == 0){ 0317 if(infobuf.type == H5O_TYPE_DATASET){ 0318 H5::DataSet dataset = h5Source->_hdfFile->openDataSet(name); 0319 H5::DataSpace space = dataset.getSpace(); 0320 //try{ 0321 H5::DataType type = dataset.getDataType(); 0322 /*}catch (H5::Exception e){ 0323 Debug::self()->log(QString("Caught exception ") + QString(e.getCDetailMsg())); 0324 0325 }*/ 0326 0327 //stick scalar, vector and matrix data into the respective lists 0328 h5Source->_fieldList.append(name); 0329 0330 int n_dims = space.getSimpleExtentNdims(); 0331 //Debug::self()->log(QString::number(n_dims) + QString(" is dataspace n dims")); 0332 if(n_dims == 0){ 0333 if(type.getClass() == H5T_STRING){//field is a string 0334 h5Source->_stringList.append(name); 0335 //Debug::self()->log(QString("Storing as string ") + name); 0336 }else if(type.getClass() == H5T_INTEGER || type.getClass() == H5T_FLOAT){ 0337 h5Source->_scalarList.append(name); 0338 }else{ 0339 Debug::self()->log(QString("Unknown scalar data type for field ") + name); 0340 h5Source->_fieldList.removeLast(); 0341 } 0342 }else if(n_dims == 1){ 0343 h5Source->_vectorList.append(name); 0344 0345 //get count of frames to see what index lengths we need 0346 unsigned len = h5Source->frameCount(name); 0347 //Debug::self()->log(QString("Length found to be ") + QString::number(len)); 0348 0349 if(!h5Source->lengths.contains(len) && len > 1){ 0350 h5Source->lengths.append(len); 0351 } 0352 if(len == 1){//len 1 vector ie. scalar 0353 h5Source->_vectorList.removeLast(); 0354 h5Source->_scalarList.append(name); 0355 } 0356 }else if(n_dims == 2){ 0357 //static matrix 0358 h5Source->_matrixList.append(name); 0359 }else if(n_dims == 3){ 0360 //matrix per frame 0361 h5Source->_mpfList.append(name); 0362 unsigned len = h5Source->frameCount(name); 0363 if(!h5Source->lengths.contains(len)){ 0364 h5Source->lengths.append(len); 0365 } 0366 }else{ 0367 //array is or too many dimentions to make sense, I guess do nothing? 0368 h5Source->_fieldList.removeLast(); 0369 Debug::self()->log(QString("4+ dimention array found with name ") + name); 0370 } 0371 //Debug::self()->log(QString("Looking for attributes of dataset ") + name); 0372 0373 //get attributes of the dataset as scalars 0374 hsize_t numAttr = 0; 0375 H5Aiterate(dataset.getId(), H5_INDEX_CRT_ORDER, H5_ITER_NATIVE, &numAttr, (H5A_operator2_t) HDF5Source::attrIterFunc, opData); 0376 //Debug::self()->log(QString::number(numAttr) + QString(" attributes found")); 0377 } 0378 } 0379 return 0; 0380 } 0381 0382 //this function should be called once per attribute 0383 herr_t HDF5Source::attrIterFunc(hid_t id, const char* name, const H5A_info_t* info, void* opData){ 0384 0385 HDF5Source* h5Source = static_cast<HDF5Source*> (opData); 0386 //Debug::self()->log(QString("iterating through attribute: ") + QString(name)); 0387 0388 size_t len = H5Iget_name(id, NULL, 0); 0389 char* buffer = new char[len+ 1]; 0390 H5Iget_name(id, buffer, len+1); 0391 0392 QString attrName = QString(buffer) + QString("->") + QString(name); 0393 0394 hid_t attrId = H5Aopen_name(id, name); 0395 hid_t type = H5Aget_type(attrId); 0396 H5S_class_t space = H5Sget_simple_extent_type(H5Aget_space(attrId)); 0397 0398 if(space == H5S_NULL || space == H5S_NO_CLASS){ 0399 Debug::self()->log(QString("No type found for: ") + QString(attrName)); 0400 }else{ 0401 h5Source->_fieldList.append(attrName); 0402 int rank = H5Sget_simple_extent_ndims(H5Aget_space(attrId)); 0403 0404 //Debug::self()->log(QString("Ndims is: ") + QString::number(rank) + QString(" type is ") + QString::number(type)); 0405 0406 if(space == H5S_SCALAR){//string or scalar 0407 if(H5Tget_class(type) == H5T_STRING){ 0408 h5Source->_stringList.append(attrName); 0409 //Debug::self()->log(QString("Storing attribute as string: ") + QString(attrName)); 0410 }else if(H5Tget_class(type) == H5T_FLOAT || H5Tget_class(type) == H5T_INTEGER){ 0411 //Debug::self()->log(QString("Storing attribute as scalar: ") + QString(attrName) + QString(" scalar list size ") + QString::number(h5Source->_scalarList.size())); 0412 h5Source->_fieldList.append(attrName); 0413 h5Source->_scalarList.append(attrName); 0414 }else{ 0415 Debug::self()->log(QString("Datatype does not match for attribute: ") + QString(attrName) + QString(" type " ) + QString::number(H5Tget_class(type))); 0416 } 0417 }else if(space == H5S_SIMPLE){//matrix or vector 0418 //determine rank 0419 if(rank == 1){ 0420 //Debug::self()->log(QString("Storing attribute as vector: ") + QString(attrName)); 0421 h5Source->_vectorList.append(attrName); 0422 0423 //get count of frames to see what index lengths we need 0424 unsigned len = h5Source->frameCount(attrName); 0425 //Debug::self()->log(QString("Length found to be ") + QString::number(len)); 0426 0427 if(!h5Source->lengths.contains(len) && len > 1){ 0428 h5Source->lengths.append(len); 0429 } 0430 if(len == 1){//len 1 vector ie. scalar 0431 h5Source->_vectorList.removeLast(); 0432 h5Source->_scalarList.append(attrName); 0433 } 0434 }else if(rank == 2){ 0435 //Debug::self()->log(QString("Storing attribute as matrix: ") + QString(attrName)); 0436 h5Source->_matrixList.append(attrName); 0437 }else{ 0438 Debug::self()->log(QString("Attribute ") + attrName +QString(" has unhandled data dimension: ") + QString::number(rank)); 0439 h5Source->_fieldList.removeLast(); 0440 } 0441 }else{ 0442 Debug::self()->log(QString("Attribute ") + attrName + QString(" has unknown dataspace: ") + QString::number(space)); 0443 h5Source->_fieldList.removeLast(); 0444 } 0445 } 0446 delete[] buffer; 0447 return 0; 0448 } 0449 0450 // If the datasource has any predefined fields they should be populated here. 0451 bool HDF5Source::init() { 0452 0453 _fieldList.clear(); 0454 _scalarList.clear(); 0455 _indexList.clear(); 0456 _matrixList.clear(); 0457 _stringList.clear(); 0458 _mpfList.clear(); 0459 _vectorList.clear(); 0460 0461 H5::Exception::dontPrint(); 0462 try{ 0463 _hdfFile = new H5::H5File(qPrintable(_directoryName), H5F_ACC_RDONLY); 0464 }catch(H5::Exception e){ 0465 //dump to debug log somewhere 0466 Debug::self()->log(QString("Failed to open HDF5 file with name ") + _directoryName +QString(" ") + QString(e.getCDetailMsg())); 0467 _hdfFile = NULL; 0468 return false; 0469 } 0470 0471 H5Lvisit(_hdfFile->getId(), H5_INDEX_CRT_ORDER, H5_ITER_NATIVE, HDF5Source::visitFunc, (void*)this); 0472 0473 //Add one index field per vector length 0474 for(int i =0; i<lengths.size(); i++){ 0475 _fieldList.append(QString("INDEX-") + QString::number(lengths[i])); 0476 _vectorList.append(QString("INDEX-") + QString::number(lengths[i])); 0477 _indexList.append(QString("INDEX-") + QString::number(lengths[i])); 0478 //Debug::self()->log(QString("Adding to indexList ") + QString("INDEX-") + QString::number(lengths[i])); 0479 } 0480 0481 registerChange(); 0482 return true; // false if something went wrong 0483 } 0484 0485 //TODO: make this do something 0486 unsigned HDF5Source::samplesPerFrame(const QString& field){ 0487 return 1; 0488 } 0489 0490 unsigned HDF5Source::frameCount(const QString& field){ 0491 //Debug::self()->log(QString("Getting frame count of ") + field); 0492 if(_indexList.contains(field)){ 0493 //Debug::self()->log(QString("Returning index len ") + QString::number(lengths[_indexList.indexOf(field)])); 0494 return lengths[_indexList.indexOf(field)]; 0495 }else if(_vectorList.contains(field)){ 0496 if(field.contains("->")){//attribute vector 0497 QStringList list = field.split("->"); 0498 0499 QString fieldName = list[0]; 0500 QString attrName = list[list.size() -1]; 0501 try{ 0502 H5::Attribute attr = _hdfFile->openDataSet(qPrintable(fieldName)).openAttribute(qPrintable(attrName)); 0503 H5::DataSpace space = attr.getSpace(); 0504 hsize_t size = 0; 0505 space.getSimpleExtentDims(&size, NULL); 0506 //Debug::self()->log(QString("Returning attr vec len ") + QString::number((int)size)); 0507 0508 return size; 0509 }catch(H5::Exception e){ 0510 Debug::self()->log(QString("Problem reading dataset ") + field + QString(" ") + QString(e.getCDetailMsg())); 0511 return 0; 0512 } 0513 }else{ 0514 try{ 0515 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(field)); 0516 H5::DataSpace space = dataset.getSpace(); 0517 0518 hsize_t size = 0; 0519 space.getSimpleExtentDims(&size, NULL); 0520 //Debug::self()->log(QString("Returning vec len ") + QString::number((int)size)); 0521 return size; 0522 }catch(H5::Exception e){ 0523 Debug::self()->log(QString("Failed to get frame count of ") + field); 0524 0525 } 0526 } 0527 }else if(_mpfList.contains(field)){ 0528 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(field)); 0529 int nDims = dataset.getArrayType().getArrayNDims(); 0530 hsize_t * sizes = new hsize_t[nDims]; 0531 dataset.getArrayType().getArrayDims(sizes); 0532 int size = sizes[0]; 0533 delete[] sizes; 0534 //Debug::self()->log(QString("Returning mpf len") + QString::number(size)); 0535 return size; 0536 }else{ 0537 //Debug::self()->log(QString("Returning 0")); 0538 return 0; 0539 } 0540 return 0; 0541 } 0542 0543 int HDF5Source::readField(double* dataVec, const QString& name, int start, int numFrames){ 0544 0545 //Debug::self()->log(QString("Into readField, name: ") + name + QString(" start: ") + QString::number(start) + QString(" numFrames: ") + QString::number(numFrames)); 0546 0547 //Populate the index field provided by the plugin 0548 if(_indexList.contains(name)){ 0549 for(int i = start; i<numFrames + start; i++){ 0550 dataVec[i-start] = i; 0551 } 0552 return numFrames; 0553 }else if(name.contains("->")){//attribute vector 0554 QStringList list = name.split("->"); 0555 0556 QString fieldName = list[0]; 0557 QString attrName = list[list.size() -1]; 0558 try{ 0559 0560 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(fieldName)); 0561 H5::Attribute attr = dataset.openAttribute(qPrintable(attrName)); 0562 0563 double* temp = new double[frameCount(name)]; 0564 attr.read(attr.getDataType(), temp);//can only read the whole attribute 0565 memcpy(dataVec, &temp[start], numFrames*samplesPerFrame(name)*sizeof(double)); 0566 0567 delete[] temp; 0568 return numFrames; 0569 }catch (H5::Exception e){ 0570 Debug::self()->log(QString("Problem reading dataset ") + name + QString(" ") + QString(e.getCDetailMsg())); 0571 } 0572 0573 return 0; 0574 }else{ 0575 0576 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(name)); 0577 0578 H5::DataSpace dataspace = dataset.getSpace(); 0579 0580 hsize_t dataSize = numFrames*samplesPerFrame(name); 0581 0582 hsize_t offsetOut = 0; 0583 hsize_t memsize = (numFrames + 1)*samplesPerFrame(name);//this better not work 0584 //ugh this worked. No idea why, but memsize must be strictly larger than numframes 0585 //or else data offsets don't work. Really feels like an off-by-one in the hdf library 0586 0587 H5::DataSpace memspace(1, &memsize); 0588 0589 memspace.selectHyperslab( H5S_SELECT_SET, &dataSize, &offsetOut); 0590 0591 hsize_t startSize = start*samplesPerFrame(name); 0592 hsize_t framesSize = numFrames*samplesPerFrame(name); 0593 0594 //Debug::self()->log(QString("Going to read, datasize = ") + QString::number(dataSize)); 0595 0596 dataspace.selectHyperslab(H5S_SELECT_SET, &framesSize, &startSize); 0597 0598 try{ 0599 dataset.read((void*)dataVec, H5::PredType::NATIVE_DOUBLE, memspace, dataspace); 0600 }catch(H5::Exception e){ 0601 Debug::self()->log(QString("Problem reading dataset ") + name + QString(" ") + QString(e.getCDetailMsg())); 0602 numFrames = 0; 0603 }catch(const std::exception& e1){ 0604 Debug::self()->log(QString("Problem reading dataset ") + name + QString(" " ) + QString(e1.what())); 0605 numFrames = 0; 0606 }catch(...){ 0607 Debug::self()->log(QString("Unknown problem reading dataset ") + name); 0608 numFrames = 0; 0609 } 0610 } 0611 return numFrames; 0612 } 0613 0614 int HDF5Source::readScalar(double& scalar, const QString& field){ 0615 0616 scalar = 0; 0617 if(_scalarList.contains(field)){ 0618 0619 if(field.contains(QString("->"))){//attribute scalar 0620 QStringList list = field.split("->"); 0621 0622 QString fieldName = list[0]; 0623 QString attrName = list[list.size() -1]; 0624 try{ 0625 H5::DataSet data = _hdfFile->openDataSet(qPrintable(fieldName)); 0626 H5::Attribute attr = data.openAttribute(qPrintable(attrName)); 0627 H5::DataType type = H5::DataType(attr.getDataType()); 0628 if(type.getClass() == H5T_FLOAT){ 0629 attr.read(type, &scalar); 0630 }else if(type.getClass() == H5T_INTEGER){ 0631 int i; 0632 attr.read(type, &i); 0633 scalar = i; 0634 } 0635 }catch(H5::FileIException e){ 0636 Debug::self()->log(QString("Trouble opening group ") + fieldName + QString(" in readScalar, attribute: ") + attrName); 0637 } 0638 }else{ 0639 H5::DataSet data = _hdfFile->openDataSet(qPrintable(field)); 0640 if(data.getSpace().getSimpleExtentNdims() == 0){//real scalar 0641 H5::DataType type(data.getDataType()); 0642 if(type.getClass() == H5T_FLOAT){ 0643 data.read((void*)&scalar, type); 0644 }else if(type.getClass() == H5T_INTEGER){ 0645 int i; 0646 data.read((void*)&i, type); 0647 scalar = i; 0648 } 0649 }else{//dataset of length one 0650 return this->readField(&scalar, field, 0, 1); 0651 } 0652 } 0653 } 0654 return 0; 0655 } 0656 0657 int HDF5Source::readString(QString &data, const QString& field){ 0658 0659 //Debug::self()->log(QString("Reading string ") + field); 0660 H5std_string h5data; 0661 0662 if(field.contains("->")){//Attribute string 0663 QStringList list = field.split("->"); 0664 0665 QString fieldName = list[0]; 0666 QString attrName = list[list.size() -1]; 0667 0668 try{ 0669 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(fieldName)); 0670 H5::Attribute attr = dataset.openAttribute(qPrintable(attrName)); 0671 attr.read(attr.getDataType(), h5data); 0672 data = QString(h5data.c_str()); 0673 return 1; 0674 }catch(H5::Exception e){ 0675 Debug::self()->log(QString("Problem reading attribute ") + field + QString(" ") + QString(e.getCDetailMsg())); 0676 return 0; 0677 } 0678 }else{//dataset string 0679 try{ 0680 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(field)); 0681 H5::StrType datatype(dataset); 0682 dataset.read(h5data, datatype); 0683 data=QString(h5data.c_str()); 0684 }catch(H5::Exception e){ 0685 Debug::self()->log(QString("Problem reading dataset ") + field + QString(" ") + QString(e.getCDetailMsg())); 0686 return 0; 0687 } 0688 } 0689 0690 return 0; 0691 } 0692 0693 int HDF5Source::readMatrix(DataMatrix::ReadInfo& data, const QString& name){ 0694 //Debug::self()->log(QString("Reading matrix ") + name + QString(" xsize is ") + QString::number(data.xNumSteps) + QString(" ysize is ") + QString::number(data.yNumSteps) + QString(" xstart is ") + QString::number(data.xStart) + QString(" ystart is ") + QString::number(data.yStart)); 0695 hsize_t dataSize = data.xNumSteps*data.yNumSteps; 0696 0697 if(name.contains("->")){//attribute matrix 0698 QStringList list = name.split("->"); 0699 0700 QString fieldName = list[0]; 0701 QString attrName = list[list.size() -1]; 0702 try{ 0703 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(fieldName)); 0704 H5::Attribute attr = dataset.openAttribute(qPrintable(attrName)); 0705 H5::DataSpace space = attr.getSpace(); 0706 hsize_t* dims = new hsize_t[2]; 0707 space.getSimpleExtentDims(dims, NULL); 0708 0709 double* temp = new double[dims[0] * dims[1]]; 0710 attr.read(attr.getDataType(), temp);//can only read the whole attribute 0711 for(int i=0; i<data.xNumSteps; i++){ 0712 for(int j = 0; j<data.yNumSteps; j++){ 0713 data.data->z[i + dims[0]*j] = temp[((int)data.xStart + i) + dims[0]*((int)data.yStart + j)]; 0714 } 0715 } 0716 0717 delete[] dims; 0718 delete[] temp; 0719 }catch (H5::Exception e){ 0720 Debug::self()->log(QString("Problem reading dataset ") + name + QString(" ") + QString(e.getCDetailMsg())); 0721 dataSize = 0; 0722 } 0723 }else{ 0724 H5::DataSet dataset = _hdfFile->openDataSet(qPrintable(name)); 0725 0726 H5::DataSpace dataspace = dataset.getSpace(); 0727 0728 hsize_t* memsize = new hsize_t[2]; 0729 hsize_t* offset = new hsize_t[2]; 0730 0731 memsize[0] = data.xNumSteps; 0732 memsize[1] = data.yNumSteps; 0733 0734 H5::DataSpace memspace(2, memsize); 0735 0736 offset[0] = 0; 0737 offset[1] = 0; 0738 0739 memspace.selectHyperslab(H5S_SELECT_SET, memsize, offset); 0740 0741 hsize_t* startSize = new hsize_t[2]; 0742 hsize_t* frameSize = new hsize_t[2]; 0743 0744 startSize[0] = data.xStart; 0745 startSize[1] = data.yStart; 0746 0747 frameSize[0] = data.xNumSteps; 0748 frameSize[1] = data.yNumSteps; 0749 0750 dataspace.selectHyperslab(H5S_SELECT_SET, frameSize, startSize); 0751 0752 try{ 0753 dataset.read((void*)data.data->z, H5::PredType::NATIVE_DOUBLE, memspace, dataspace); 0754 }catch(H5::Exception e){ 0755 Debug::self()->log(QString("Problem reading dataset ") + name + QString(" ") + QString(e.getCDetailMsg())); 0756 dataSize = 0; 0757 }catch(const std::exception& e1){ 0758 Debug::self()->log(QString("Problem reading dataset ") + name + QString(" " ) + QString(e1.what())); 0759 dataSize = 0; 0760 }catch(...){ 0761 Debug::self()->log(QString("Unknown problem reading dataset ") + name); 0762 dataSize = 0; 0763 } 0764 delete[] memsize; 0765 delete[] offset; 0766 delete[] startSize; 0767 delete[] frameSize; 0768 } 0769 //set some matrix viewing parameters 0770 data.data->xMin = data.xStart; 0771 data.data->yMin = data.yStart; 0772 data.data->xStepSize = 1; 0773 data.data->yStepSize = 1; 0774 0775 return dataSize; 0776 } 0777 0778 // Check if the data in the from the source has updated. Typically done by checking the frame count of the datasource for 0779 // changes. 0780 Kst::Object::UpdateType HDF5Source::internalDataSourceUpdate() { 0781 return Kst::Object::NoChange; 0782 } 0783 0784 0785 // TODO a DataSource::DataInterface implementation as example 0786 0787 0788 0789 0790 0791 0792 QString HDF5Source::fileType() const { 0793 return "HDF5"; 0794 } 0795 0796 0797 void HDF5Source::save(QXmlStreamWriter &streamWriter) { 0798 Kst::DataSource::save(streamWriter); 0799 } 0800 0801 0802 0803 0804 0805 // Name used to identify the plugin. Used when loading the plugin. 0806 QString HDF5Plugin::pluginName() const { return tr("HDF5 Reader"); } 0807 QString HDF5Plugin::pluginDescription() const { return tr("HDF5 Reader"); } 0808 0809 /********************** 0810 HDF5Plugin - This class defines the plugin interface to the DataSource defined by the plugin. 0811 The primary requirements of this class are to provide the necessary connections to create the object 0812 which includes providing access to the configuration widget. 0813 0814 ***********************/ 0815 0816 Kst::DataSource *HDF5Plugin::create(Kst::ObjectStore *store, 0817 QSettings *cfg, 0818 const QString &filename, 0819 const QString &type, 0820 const QDomElement &element) const { 0821 0822 return new HDF5Source(store, cfg, filename, type, element); 0823 } 0824 0825 0826 // Provides the matrix list that this dataSource can provide from the provided filename. 0827 // This function should use understands to validate the file and then open and calculate the 0828 // list of matrices. 0829 QStringList HDF5Plugin::matrixList(QSettings *cfg, 0830 const QString& filename, 0831 const QString& type, 0832 QString *typeSuggestion, 0833 bool *complete) const { 0834 0835 0836 if (typeSuggestion) { 0837 *typeSuggestion = "HDF5"; 0838 } 0839 if ((!type.isEmpty() && !provides().contains(type)) || 0840 0 == understands(cfg, filename)) { 0841 if (complete) { 0842 *complete = false; 0843 } 0844 return QStringList(); 0845 } 0846 QStringList matrixList; 0847 0848 return matrixList; 0849 0850 } 0851 0852 0853 // Provides the scalar list that this dataSource can provide from the provided filename. 0854 // This function should use understands to validate the file and then open and calculate the 0855 // list of scalars if necessary. 0856 QStringList HDF5Plugin::scalarList(QSettings *cfg, 0857 const QString& filename, 0858 const QString& type, 0859 QString *typeSuggestion, 0860 bool *complete) const { 0861 0862 QStringList scalarList; 0863 0864 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0865 if (complete) { 0866 *complete = false; 0867 } 0868 return QStringList(); 0869 } 0870 0871 if (typeSuggestion) { 0872 *typeSuggestion = "HDF5"; 0873 } 0874 0875 //scalarList.append("FRAMES"); 0876 return scalarList; 0877 0878 } 0879 0880 0881 // Provides the string list that this dataSource can provide from the provided filename. 0882 // This function should use understands to validate the file and then open and calculate the 0883 // list of strings if necessary. 0884 QStringList HDF5Plugin::stringList(QSettings *cfg, 0885 const QString& filename, 0886 const QString& type, 0887 QString *typeSuggestion, 0888 bool *complete) const { 0889 0890 QStringList stringList; 0891 0892 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0893 if (complete) { 0894 *complete = false; 0895 } 0896 return QStringList(); 0897 } 0898 0899 if (typeSuggestion) { 0900 *typeSuggestion = "HDF5"; 0901 } 0902 0903 //stringList.append("FILENAME"); 0904 return stringList; 0905 0906 } 0907 0908 0909 // Provides the field list that this dataSource can provide from the provided filename. 0910 // This function should use understands to validate the file and then open and calculate the 0911 // list of fields if necessary. 0912 QStringList HDF5Plugin::fieldList(QSettings *cfg, 0913 const QString& filename, 0914 const QString& type, 0915 QString *typeSuggestion, 0916 bool *complete) const { 0917 Q_UNUSED(cfg) 0918 Q_UNUSED(filename) 0919 Q_UNUSED(type) 0920 0921 if (complete) { 0922 *complete = true; 0923 } 0924 0925 if (typeSuggestion) { 0926 *typeSuggestion = "HDF5"; 0927 } 0928 0929 QStringList fieldList; 0930 0931 if(understands(cfg, filename)){ 0932 0933 //TODO: open hdf file 0934 //get list of fields 0935 //I am confused about how field list is returned if this doesn't do anything 0936 } 0937 return fieldList; 0938 } 0939 0940 0941 // The main function used to determine if this plugin knows how to process the provided file. 0942 // Each datasource plugin should check the file and return a number between 0 and 100 based 0943 // on the likelyhood of the file being this type. 100 should only be returned if there is no way 0944 // that the file could be any datasource other than this one. 0945 int HDF5Plugin::understands(QSettings *cfg, const QString& filename) const { 0946 0947 Q_UNUSED(cfg) 0948 QFileInfo fi(filename); 0949 0950 int returnVal = 0; 0951 if (fi.suffix() == "h5" || fi.suffix() == "hdf5"){ 0952 returnVal += 40; 0953 if (H5::H5File::isHdf5(qPrintable(filename))){ 0954 returnVal += 40; 0955 } 0956 } 0957 return returnVal; 0958 } 0959 0960 0961 bool HDF5Plugin::supportsTime(QSettings *cfg, const QString& filename) const { 0962 //FIXME 0963 Q_UNUSED(cfg) 0964 Q_UNUSED(filename) 0965 return true; 0966 } 0967 0968 0969 QStringList HDF5Plugin::provides() const { 0970 QStringList rc; 0971 rc += "HDF5"; 0972 return rc; 0973 } 0974 0975 0976 // Request for this plugins configuration widget. 0977 Kst::DataSourceConfigWidget *HDF5Plugin::configWidget(QSettings *cfg, const QString& filename) const { 0978 Q_UNUSED(cfg) 0979 Q_UNUSED(filename) 0980 return 0;; 0981 0982 } 0983 0984 #ifndef QT5 0985 Q_EXPORT_PLUGIN2(kstdata_hdf5, HDF5Plugin) 0986 #endif 0987 0988 // vim: ts=2 sw=2 et