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