File indexing completed on 2025-01-26 04:12:09

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *   copyright : (C) 2005  University of British Columbia                  *
0006  *                   dscott@phas.ubc.ca                                    *
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 #include "lfiio.h"
0016 
0017 #include <QXmlStreamWriter>
0018 //#include <fitsio.h>
0019 #include <math.h>
0020 
0021 #define TIME_FIELD  "TIME"
0022 
0023 #include "kst_i18n.h"
0024 
0025 static const QString lfiioTypeString = I18N_NOOP("LFIIO image");
0026 
0027 class LFIIOSource::Config {
0028   public:
0029     Config() {
0030     }
0031 
0032     void read(QSettings *cfg, const QString& fileName = QString::null) {
0033       Q_UNUSED(fileName);
0034       cfg->beginGroup(lfiioTypeString);
0035       cfg->endGroup();
0036     }
0037 
0038     void save(QXmlStreamWriter& s) {
0039       Q_UNUSED(s);
0040     }
0041 
0042     void load(const QDomElement& e) {
0043       Q_UNUSED(e);
0044     }
0045 };
0046 
0047 
0048 LFIIOSource::LFIIOSource(Kst::ObjectStore *store, QSettings *cfg, const QString& filename, const QString& type, const QDomElement& e)
0049 : Kst::DataSource(store, cfg, filename, type, None), _config(0L) {
0050 
0051   _first = true;
0052   _valid = false;
0053 
0054   if (!type.isEmpty() && type != "LFIIO Image Source") {
0055     return;
0056   }
0057 
0058   _config = new LFIIOSource::Config;
0059   _config->read(cfg, filename);
0060   if (!e.isNull()) {
0061     _config->load(e);
0062   }
0063 
0064   if (init()) {
0065     _valid = true;
0066   }
0067 
0068   update();
0069 }
0070 
0071 
0072 
0073 LFIIOSource::~LFIIOSource() {
0074 }
0075 
0076 
0077 bool LFIIOSource::reset() {
0078   init();
0079   return true;
0080 }
0081 
0082 
0083 bool LFIIOSource::init() {
0084   Kst::Object::UpdateType updateType;
0085   bool                  bRetVal = false;
0086   int                   iResult = 0;
0087 
0088   _numFrames = 0;
0089 
0090   // read the metadata
0091   if (!_filename.isNull() && !_filename.isEmpty()) {
0092     QString   str;
0093     fitsfile* ffits;
0094     int       iStatus = 0;
0095 
0096     if (_first) {
0097       iResult = fits_open_table( &ffits, _filename.ascii(), READONLY, &iStatus );
0098       if (iResult == 0) {
0099         int keysexist;
0100         int morekeys;
0101 
0102         iResult = fits_get_hdrspace( ffits, &keysexist, &morekeys, &iStatus );
0103         if (iResult == 0) {
0104           char  keyname[FLEN_KEYWORD];
0105           char  value[FLEN_VALUE];
0106           char  comment[FLEN_COMMENT];
0107           int   keynum;
0108 
0109           for (keynum = 1; keynum <= keysexist; ++keynum) {
0110             iResult = fits_read_keyn( ffits, keynum, keyname, value, comment, &iStatus );
0111             if (iResult == 0) {
0112               str.sprintf("%s %s", value, comment);
0113               _metaData.insert(keyname, str);
0114             }
0115           }
0116 
0117           _first = false;
0118         }
0119       }
0120     }
0121   }
0122 
0123   updateType = update();
0124   if(updateType == Kst::Object::UPDATE) {
0125     bRetVal = true;
0126   }
0127 
0128   return bRetVal;
0129 }
0130 
0131 
0132 Kst::Object::UpdateType LFIIOSource::update() {
0133 
0134   Kst::Object::UpdateType updateType = Kst::Object::NO_CHANGE;
0135   QString               strTemplate;
0136   QString               strName;
0137   fitsfile*             ffits;
0138   char                  charTemplate[FLEN_CARD];
0139   char                  charName[FLEN_CARD];
0140   long                  lNumFrames;
0141   long                  lMaxRepeat = 1;
0142   long                  lRepeat;
0143   long                  lWidth;
0144   int                   iColNumber;
0145   int                   iNumCols;
0146   int                   iStatus = 0;
0147   int                   iResult = 0;
0148   int                   iTypeCode;
0149   int                   i;
0150   int                   newNF = 0;
0151 
0152   _valid  = false;
0153 
0154   if(!_filename.isNull() && !_filename.isEmpty()) {
0155     iResult = fits_open_table( &ffits, _filename.ascii(), READONLY, &iStatus );
0156     if(iResult == 0) {
0157       // determine size of data...
0158       iResult = fits_get_num_cols( ffits, &iNumCols, &iStatus );
0159       if(iResult == 0) {
0160         iResult = fits_get_num_rows( ffits, &lNumFrames, &iStatus );
0161         if(iResult == 0) {
0162           _fieldList.clear();
0163           _fieldList.append("INDEX");
0164 
0165           _valid = true;
0166           _bHasTime = false;
0167 
0168           // need to multiply lNumFrames by the maximum value of the vector repeat value...
0169           for(i = 0; i<iNumCols; i++) {
0170             iStatus = 0;
0171 
0172             sprintf(charTemplate, "%d", i+1);
0173             iResult = fits_get_colname( ffits, CASEINSEN, charTemplate, charName, &iColNumber, &iStatus );
0174             if(iResult == 0) {
0175               int iOffset = i;
0176               strName = charName;
0177 
0178               // ensure that we don't add duplicates to the _fieldList...
0179               while(_fieldList.findIndex(strName) != -1) {
0180                 strName = QString("%1[%2]").arg(charName).arg(iOffset);
0181                 iOffset++;
0182               }
0183             } else {
0184               strName.setNum(i);
0185             }
0186 
0187             _fieldList.append(strName);
0188 
0189             iStatus = 0;
0190             iResult = fits_get_coltype( ffits, i+1, &iTypeCode, &lRepeat, &lWidth, &iStatus );
0191             if(iResult == 0) {
0192               if(lRepeat > lMaxRepeat) {
0193                 lMaxRepeat = lRepeat;
0194               }
0195             }
0196           }
0197 
0198           // check if we have a time field defined by the header keys TIMEZERO and DELTA_T.
0199           //  If so then we create a new field called $TIME_FIELD, unless such a field already
0200           //  exists, in which case we do nothing...
0201           char charTimeZero[] = "TIMEZERO";
0202 
0203           iStatus = 0;
0204           iResult = fits_read_key( ffits, TDOUBLE, charTimeZero, &_dTimeZero, 0L, &iStatus );
0205           if(iResult == 0) {
0206             char charTimeDelta[] = "DELTA_T";
0207 
0208             iResult = fits_read_key( ffits, TDOUBLE, charTimeDelta, &_dTimeDelta, 0L, &iStatus );
0209             if(iResult == 0) {
0210               if(_fieldList.find(QString(TIME_FIELD)) == _fieldList.end()) {
0211                 _bHasTime = true;
0212                 _fieldList.append(TIME_FIELD);
0213               }
0214             }
0215           }
0216 
0217           if(lNumFrames * lMaxRepeat != _numFrames) {
0218             _numCols   = iNumCols;
0219             newNF = lNumFrames * lMaxRepeat;
0220             updateType = Kst::Object::UPDATE;
0221           }
0222         }
0223       }
0224       iStatus = 0;
0225       fits_close_file( ffits, &iStatus );
0226     }
0227   }
0228 
0229   bool isnew = newNF != _numFrames;
0230 
0231   _numFrames = newNF;
0232 
0233   return (isnew ? Kst::Object::UPDATE : Kst::Object::NO_CHANGE);
0234 }
0235 
0236 
0237 int LFIIOSource::readField(double *v, const QString& field, int s, int n) {
0238   double    dNan = strtod("nan", NULL);
0239   fitsfile* ffits;
0240   bool      bOk;
0241   int       i;
0242   int       iCol;
0243   int       iRead = -1;
0244   int       iStatus = 0;
0245   int       iAnyNull;
0246   int       iResult = 0;
0247 
0248   if (n < 0) {
0249     n = 1; /* n < 0 means read one sample, not frame - irrelavent here */
0250   }
0251 
0252   if (field == "INDEX") {
0253     for(i = 0; i < n; i++) {
0254       v[i] = (double)(s + i) ;
0255     }
0256     iRead =  n;
0257   } else if (_bHasTime && field == TIME_FIELD) {
0258     for(i = 0; i < n; i++) {
0259       v[i] = _dTimeZero + ((double)(s + i) * _dTimeDelta);
0260     }
0261     iRead =  n;
0262   } else {
0263     memset(v, 0, n * sizeof(double));
0264 
0265     bOk = getColNumber(field, &iCol);
0266     if (bOk) {
0267       _valid = false;
0268 
0269       if (!_filename.isNull() && !_filename.isEmpty()) {
0270         iResult = fits_open_table( &ffits, _filename.ascii(), READONLY, &iStatus );
0271         if (iResult == 0) {
0272           _valid = true;
0273 
0274           // copy the data...
0275           // N.B. fitsio column indices are 1 based, so we ask for iCol+1 instead of just iCol
0276           iResult = fits_read_col( ffits, TDOUBLE, iCol+1, s+1, 1, n, &dNan, v, &iAnyNull, &iStatus );
0277           if (iResult == 0) {
0278             iRead = n;
0279           }
0280 
0281           iStatus = 0;
0282           fits_close_file( ffits, &iStatus );
0283         }
0284       }
0285     }
0286   }
0287 
0288   return iRead;
0289 }
0290 
0291 
0292 bool LFIIOSource::getColNumber( const QString& field, int* piColNumber ) const {
0293   QString strName;
0294   bool    bOk     = false;
0295   bool    bRetVal = false;
0296   int     iCount;
0297   int     iCol;
0298   int     i;
0299 
0300   iCol = field.toUInt(&bOk);
0301   if (bOk) {
0302     if (iCol >= 0 && iCol < _numCols) {
0303       *piColNumber = iCol;
0304 
0305       bRetVal = true;
0306     }
0307   } else {
0308     iCount = _fieldList.count();
0309 
0310     // start at 1, because the first entry is INDEX...
0311     for (i=1; i<iCount; i++) {
0312       strName = _fieldList[i].lower();
0313       if (strName.compare(field.lower()) == 0) {
0314         bRetVal = true;
0315 
0316         // subtract 1 to be consistent with the value returned from the previous branch...
0317         *piColNumber = i-1;
0318 
0319         break;
0320       }
0321     }
0322   }
0323 
0324   return bRetVal;
0325 }
0326 
0327 
0328 bool LFIIOSource::isValidField(const QString& field) const {
0329   bool bRetVal = false;
0330   int  iCol;
0331 
0332   if (field == "INDEX") {
0333     bRetVal = true;
0334   } else if (field == TIME_FIELD && _bHasTime) {
0335     bRetVal = true;
0336   } else {
0337     bRetVal = getColNumber(field, &iCol);
0338   }
0339 
0340   return bRetVal;
0341 }
0342 
0343 
0344 int LFIIOSource::samplesPerFrame(const QString &field) {
0345   Q_UNUSED(field)
0346   return 1;
0347 }
0348 
0349 
0350 int LFIIOSource::frameCount(const QString& field) const {
0351   Q_UNUSED(field)
0352   return _numFrames;
0353 }
0354 
0355 
0356 bool LFIIOSource::isEmpty() const {
0357   return _numFrames < 1;
0358 }
0359 
0360 
0361 QString LFIIOSource::fileType() const {
0362   return lfiioTypeString;
0363 }
0364 
0365 
0366 void LFIIOSource::save(QXmlStreamWriter &streamWriter) {
0367   Kst::DataSource::save(streamWriter);
0368 }
0369 
0370 
0371 int LFIIOSource::readScalar(double &S, const QString& scalar) {
0372   if (scalar == "FRAMES") {
0373     S = _numFrames;
0374     return 1;
0375   }
0376   return 0;
0377 }
0378 
0379 
0380 int LFIIOSource::readString(QString &S, const QString& string) {
0381   if (string == "FILE") {
0382     S = _filename;
0383     return 1;
0384   } else if (_metaData.contains(string)) {
0385     S = _metaData[string];
0386     return 1;
0387   }
0388   return 0;
0389 }
0390 
0391 
0392 QString LFIIOPlugin::pluginName() const { return "LFIIO Image Source Reader"; }
0393 QString LFIIOPlugin::pluginDescription() const { return "LFIIO Image Source Reader"; }
0394 
0395 
0396 Kst::DataSource *LFIIOPlugin::create(Kst::ObjectStore *store,
0397                                             QSettings *cfg,
0398                                             const QString &filename,
0399                                             const QString &type,
0400                                             const QDomElement &element) const {
0401 
0402   return new LFIIOSource(store, cfg, filename, type, element);
0403 }
0404 
0405 
0406 
0407 QStringList LFIIOPlugin::matrixList(QSettings *cfg,
0408                                              const QString& filename,
0409                                              const QString& type,
0410                                              QString *typeSuggestion,
0411                                              bool *complete) const {
0412   if (typeSuggestion) {
0413     *typeSuggestion = lfiioTypeString;
0414   }
0415   if ((!type.isEmpty() && !provides().contains(type)) ||
0416       0 == understands(cfg, filename)) {
0417     if (complete) {
0418       *complete = false;
0419     }
0420     return QStringList();
0421   }
0422   return QStringList();
0423 
0424 }
0425 
0426 
0427 QStringList LFIIOPlugin::scalarList(QSettings *cfg,
0428                                             const QString& filename,
0429                                             const QString& type,
0430                                             QString *typeSuggestion,
0431                                             bool *complete) const {
0432 
0433   QStringList scalarList;
0434 
0435   if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) {
0436     if (complete) {
0437       *complete = false;
0438     }
0439     return QStringList();
0440   }
0441 
0442   if (typeSuggestion) {
0443     *typeSuggestion = lfiioTypeString;
0444   }
0445 
0446   scalarList.append("FRAMES");
0447   return scalarList;
0448 
0449 }
0450 
0451 
0452 QStringList LFIIOPlugin::stringList(QSettings *cfg,
0453                                       const QString& filename,
0454                                       const QString& type,
0455                                       QString *typeSuggestion,
0456                                       bool *complete) const {
0457 
0458   QStringList stringList;
0459 
0460   if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) {
0461     if (complete) {
0462       *complete = false;
0463     }
0464     return QStringList();
0465   }
0466 
0467   if (typeSuggestion) {
0468     *typeSuggestion = lfiioTypeString;
0469   }
0470 
0471   stringList.append("FILENAME");
0472 
0473   QString   str;
0474   fitsfile* ffits;
0475   int       iStatus = 0;
0476   int       iResult = 0;
0477 
0478   iResult = fits_open_table(&ffits, filename.ascii(), READONLY, &iStatus);
0479   if (iResult == 0) {
0480     int keysexist;
0481     int morekeys;
0482 
0483     iResult = fits_get_hdrspace( ffits, &keysexist, &morekeys, &iStatus );
0484     if (iResult == 0) {
0485       char  keyname[FLEN_KEYWORD];
0486       char  value[FLEN_VALUE];
0487       char  comment[FLEN_COMMENT];
0488       int   keynum;
0489 
0490       for (keynum=1; keynum <= keysexist; ++keynum) {
0491         iResult = fits_read_keyn( ffits, keynum, keyname, value, comment, &iStatus );
0492         if (iResult == 0) {
0493           stringList.append(keyname);
0494         }
0495       }
0496     }
0497   }
0498 
0499   return stringList;
0500 }
0501 
0502 
0503 QStringList LFIIOPlugin::fieldList(QSettings *cfg,
0504                                             const QString& filename,
0505                                             const QString& type,
0506                                             QString *typeSuggestion,
0507                                             bool *complete) const {
0508   Q_UNUSED(type)
0509   QStringList fieldList;
0510   bool valid = true;
0511   bool hasTime = false;
0512 
0513   if (complete) {
0514     *complete = true;
0515   }
0516 
0517   if (typeSuggestion) {
0518     *typeSuggestion = lfiioTypeString;
0519   }
0520   if (understands(cfg, filename)) {
0521     QString               strName;
0522     fitsfile*             ffits;
0523     int                   iStatus = 0;
0524     int                   iNumCols;
0525     long                  lNumFrames;
0526     int                   i;
0527     char                  charTemplate[ FLEN_CARD ];
0528     char                  charName[ FLEN_CARD ];
0529     long                  lMaxRepeat = 1;
0530     long                  lRepeat;
0531     long                  lWidth;
0532     int                   iColNumber;
0533     int                   iResult = 0;
0534     int                   iTypeCode;
0535 
0536     iResult = fits_open_table( &ffits, filename.ascii(), READONLY, &iStatus );
0537     if (iResult == 0) {
0538       //
0539       // determine size of data...
0540       //
0541       iResult = fits_get_num_cols( ffits, &iNumCols, &iStatus );
0542       if (iResult == 0) {
0543         iResult = fits_get_num_rows( ffits, &lNumFrames, &iStatus );
0544         if (iResult == 0) {
0545           fieldList.append("INDEX");
0546           valid = true;
0547           hasTime = false;
0548 
0549           // need to multiply lNumFrames by the maximum value of the vector repeat value...
0550           for (i=0; i<iNumCols; i++) {
0551             iStatus = 0;
0552 
0553             sprintf(charTemplate, "%d", i+1);
0554             iResult = fits_get_colname( ffits, CASEINSEN, charTemplate, charName, &iColNumber, &iStatus );
0555             if (iResult == 0) {
0556               int iOffset = i;
0557 
0558               strName = charName;
0559               // ensure that we don't add duplicates to the _fieldList...
0560               while(fieldList.findIndex( strName ) != -1) {
0561                 strName = QString("%1[%2]").arg(charName).arg(iOffset);
0562                 iOffset++;
0563               }
0564             } else {
0565               strName.setNum(i);
0566             }
0567             fieldList.append(strName);
0568 
0569             iStatus = 0;
0570             iResult = fits_get_coltype( ffits, i+1, &iTypeCode, &lRepeat, &lWidth, &iStatus );
0571             if (iResult == 0) {
0572               if (lRepeat > lMaxRepeat) {
0573                 lMaxRepeat = lRepeat;
0574               }
0575             }
0576           }
0577 
0578           //  Check if we have a time field defined by the header keys TIMEZERO and DELTA_T.
0579           //  If so then we create a new field called $TIME_FIELD, unless such a field already
0580           //  exists, in which case we do nothing...
0581           char charTimeZero[] = "TIMEZERO";
0582           double timeZero;
0583           double timeDelta;
0584 
0585           iStatus = 0;
0586           iResult = fits_read_key( ffits, TDOUBLE, charTimeZero, &timeZero, 0L, &iStatus );
0587           if (iResult == 0) {
0588             char charTimeDelta[] = "DELTA_T";
0589 
0590             iResult = fits_read_key( ffits, TDOUBLE, charTimeDelta, &timeDelta, 0L, &iStatus );
0591             if (iResult == 0) {
0592               if (fieldList.find(QString(TIME_FIELD)) == fieldList.end()) {
0593                 hasTime = true;
0594                 fieldList.append(TIME_FIELD);
0595               }
0596             }
0597           }
0598         }
0599       }
0600       iStatus = 0;
0601       fits_close_file( ffits, &iStatus );
0602     }
0603   }
0604 
0605   return fieldList;
0606 }
0607 
0608 
0609 int LFIIOPlugin::understands(QSettings *cfg, const QString& filename) const {
0610   Q_UNUSED(cfg)
0611   fitsfile* ffits;
0612   int       iStatus = 0;
0613   int       iRetVal = 0;
0614 
0615   // determine if it is a FITS file...
0616   if (fits_open_table( &ffits, filename.ascii(), READONLY, &iStatus ) == 0 ) {
0617     fits_close_file( ffits, &iStatus );
0618     iRetVal = 90;
0619   }
0620 
0621   return iRetVal;
0622 }
0623 
0624 
0625 
0626 bool LFIIOPlugin::supportsTime(QSettings *cfg, const QString& filename) const {
0627   //FIXME
0628   Q_UNUSED(cfg)
0629   Q_UNUSED(filename)
0630   return true;
0631 }
0632 
0633 
0634 QStringList LFIIOPlugin::provides() const {
0635   QStringList rc;
0636   rc += "LFIIO Image Source";
0637   return rc;
0638 }
0639 
0640 
0641 Kst::DataSourceConfigWidget *LFIIOPlugin::configWidget(QSettings *cfg, const QString& filename) const {
0642 
0643   Q_UNUSED(cfg)
0644   Q_UNUSED(filename)
0645   return 0;;
0646 
0647 }
0648 
0649 Q_EXPORT_PLUGIN2(kstdata_qimagesource, LFIIOPlugin)
0650 
0651 
0652 // vim: ts=2 sw=2 et