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