File indexing completed on 2025-01-05 04:12:04
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2014 Northwestern University * 0004 * nchapman@u.northwestern.edu * 0005 * g-novak@northwestern.edu * 0006 * * 0007 * This program is free software; you can redistribute it and/or modify * 0008 * it under the terms of the GNU General Public License as published by * 0009 * the Free Software Foundation; either version 2 of the License, or * 0010 * (at your option) any later version. * 0011 * * 0012 ***************************************************************************/ 0013 0014 #include "fitstable.h" 0015 0016 #include <QXmlStreamWriter> 0017 #include <QFileInfo> 0018 0019 #define DBG if(0) 0020 0021 using namespace Kst; 0022 0023 /* Scalar interface */ 0024 0025 class DataInterfaceFitsTableScalar : public DataSource::DataInterface<DataScalar>{ 0026 public: 0027 DataInterfaceFitsTableScalar(FitsTableSource& s) : source(s) {} 0028 0029 // read one element 0030 int read(const QString&, DataScalar::ReadInfo&); 0031 0032 // named elements 0033 QStringList list() const { return source._scalars.keys(); } 0034 bool isListComplete() const { return true; } 0035 bool isValid(const QString&) const; 0036 0037 // T specific 0038 const DataScalar::DataInfo dataInfo(const QString&) const { return DataScalar::DataInfo(); } 0039 void setDataInfo(const QString&, const DataScalar::DataInfo&) {} 0040 0041 // meta data 0042 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0043 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0044 0045 private: 0046 FitsTableSource& source; 0047 }; 0048 0049 0050 int DataInterfaceFitsTableScalar::read(const QString& scalar, DataScalar::ReadInfo& p){ 0051 0052 DBG qDebug() << "Entering DataInterfaceFitsTableScalar::read() with scalar: " << scalar << endl; 0053 return source.readScalar(p.value, scalar); 0054 } 0055 0056 0057 bool DataInterfaceFitsTableScalar::isValid(const QString& scalar) const{ 0058 0059 DBG qDebug() << "Entering DataInterfaceFitsTableScalar::isValid() with scalar: " << scalar << endl; 0060 return source._scalars.contains( scalar ); 0061 } 0062 0063 /* String interface */ 0064 0065 class DataInterfaceFitsTableString : public DataSource::DataInterface<DataString>{ 0066 public: 0067 DataInterfaceFitsTableString(FitsTableSource& s) : source(s) {} 0068 0069 // read one element 0070 int read(const QString&, DataString::ReadInfo&); 0071 0072 // named elements 0073 QStringList list() const { return source._strings.keys(); } 0074 bool isListComplete() const { return true; } 0075 bool isValid(const QString&) const; 0076 0077 // T specific 0078 const DataString::DataInfo dataInfo(const QString&) const { return DataString::DataInfo(); } 0079 void setDataInfo(const QString&, const DataString::DataInfo&) {} 0080 0081 // meta data 0082 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0083 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0084 0085 private: 0086 FitsTableSource& source; 0087 }; 0088 0089 0090 int DataInterfaceFitsTableString::read(const QString& string, DataString::ReadInfo& p){ 0091 0092 DBG qDebug() << "Entering DataInterfaceFitsTableString::read() with string: " << string << endl; 0093 if (isValid(string) && p.value) { 0094 *p.value = source._strings[string]; 0095 return 1; 0096 } 0097 return 0; 0098 } 0099 0100 0101 bool DataInterfaceFitsTableString::isValid(const QString& string) const{ 0102 0103 DBG qDebug() << "Entering DataInterfaceFitsTableString::isValid() with string: " << string << endl; 0104 return source._strings.contains( string ); 0105 } 0106 0107 /* Vector interface */ 0108 0109 class DataInterfaceFitsTableVector : public DataSource::DataInterface<DataVector>{ 0110 public: 0111 DataInterfaceFitsTableVector(FitsTableSource& s) : source(s) {} 0112 0113 // read one element 0114 int read(const QString&, DataVector::ReadInfo&); 0115 0116 // named elements 0117 QStringList list() const { return source._fieldList; } 0118 bool isListComplete() const { return true; } 0119 bool isValid(const QString&) const; 0120 0121 // T specific 0122 const DataVector::DataInfo dataInfo(const QString&) const; 0123 void setDataInfo(const QString&, const DataVector::DataInfo&) {} 0124 0125 // meta data 0126 QMap<QString, double> metaScalars(const QString&); 0127 QMap<QString, QString> metaStrings(const QString&); 0128 0129 private: 0130 FitsTableSource& source; 0131 }; 0132 0133 0134 const DataVector::DataInfo DataInterfaceFitsTableVector::dataInfo(const QString &field) const{ 0135 0136 DBG qDebug() << "Entering DataInterfaceFitsTableVector::dataInfo() with field: " << field << endl; 0137 if (!source._fieldList.contains(field)) 0138 return DataVector::DataInfo(); 0139 0140 return DataVector::DataInfo(source.frameCount(field), source.samplesPerFrame(field)); 0141 } 0142 0143 int DataInterfaceFitsTableVector::read(const QString& field, DataVector::ReadInfo& p){ 0144 0145 DBG qDebug() << "Entering DataInterfaceFitsTableVector::read() with field: " << field << endl; 0146 return source.readField(p.data, field, p.startingFrame, p.numberOfFrames); 0147 } 0148 0149 0150 bool DataInterfaceFitsTableVector::isValid(const QString& field) const{ 0151 0152 DBG qDebug() << "Entering DataInterfaceFitsTableVector::isValid() with field: " << field << endl; 0153 return source._fieldList.contains(field); 0154 } 0155 0156 QMap<QString, double> DataInterfaceFitsTableVector::metaScalars(const QString& field){ 0157 Q_UNUSED(field); 0158 QMap<QString, double> fieldScalars; 0159 0160 DBG qDebug() << "Entering DataInterfaceFitsTableVector::metaScalars() with field: " << field << endl; 0161 return fieldScalars; 0162 } 0163 0164 QMap<QString, QString> DataInterfaceFitsTableVector::metaStrings(const QString& field){ 0165 0166 QMap<QString, QString> fieldStrings; 0167 DBG qDebug() << "Entering DataInterfaceFitsTableVector::metaStrings() with field: " << field << endl; 0168 return fieldStrings; 0169 } 0170 0171 /* Matrix interface */ 0172 0173 class DataInterfaceFitsTableMatrix : public DataSource::DataInterface<DataMatrix>{ 0174 public: 0175 0176 DataInterfaceFitsTableMatrix(FitsTableSource& s) : source(s) {} 0177 0178 // read one element 0179 int read(const QString&, DataMatrix::ReadInfo&); 0180 0181 // named elements 0182 QStringList list() const { return source._matrixList; } 0183 bool isListComplete() const { return true; } 0184 bool isValid(const QString&) const; 0185 0186 // T specific 0187 const DataMatrix::DataInfo dataInfo (const QString&) const; 0188 void setDataInfo(const QString&, const DataMatrix::DataInfo&) {} 0189 0190 // meta data 0191 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0192 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0193 0194 private: 0195 FitsTableSource& source; 0196 }; 0197 0198 0199 const DataMatrix::DataInfo DataInterfaceFitsTableMatrix::dataInfo(const QString& matrix) const{ 0200 0201 DBG qDebug() << "Entering DataInterfaceFitsTableMatrix::dataInfo() with matrix: " << matrix << endl; 0202 if (!source._matrixList.contains( matrix ) ) { 0203 return DataMatrix::DataInfo(); 0204 } 0205 0206 DataMatrix::DataInfo info; 0207 info.samplesPerFrame = 1; 0208 info.xSize = 32; 0209 info.ySize = 12; 0210 0211 return info; 0212 } 0213 0214 0215 int DataInterfaceFitsTableMatrix::read(const QString& field, DataMatrix::ReadInfo& p){ 0216 0217 DBG qDebug() << "Entering DataInterfaceFitsTableMatrix::read() with field: " << field << endl; 0218 int count = source.readMatrix(p.data->z, field); 0219 0220 p.data->xMin = 0; 0221 p.data->yMin = 0; 0222 p.data->xStepSize = 1; 0223 p.data->yStepSize = 1; 0224 0225 return count; 0226 } 0227 0228 0229 bool DataInterfaceFitsTableMatrix::isValid(const QString& field) const { 0230 0231 DBG qDebug() << "Entering DataInterfaceFitsTableMatrix::isValid() with field: " << field << endl; 0232 return source._matrixList.contains(field); 0233 } 0234 0235 /********************** 0236 FitsTableSource - This class defines the main DataSource which derives 0237 from DataSource. The key functions that this class must provide is the ability 0238 to create the source, provide details about the source be able to process the 0239 data. 0240 ***********************/ 0241 FitsTableSource::FitsTableSource(Kst::ObjectStore *store, QSettings *cfg, 0242 const QString& filename, const QString& type, const QDomElement& e) 0243 : Kst::DataSource(store, cfg, filename, type), _fptr(0L), _config(0L), 0244 is(new DataInterfaceFitsTableScalar(*this)), 0245 it(new DataInterfaceFitsTableString(*this)), 0246 iv(new DataInterfaceFitsTableVector(*this)), 0247 im(new DataInterfaceFitsTableMatrix(*this)){ 0248 0249 DBG qDebug() << "Entering FitsTableSource::FitsTableSource() with filename: " << filename << endl; 0250 setInterface(is); 0251 setInterface(it); 0252 setInterface(iv); 0253 setInterface(im); 0254 0255 setUpdateType(None); 0256 0257 if (!type.isEmpty() && type != "FITS Table") { 0258 return; 0259 } 0260 0261 _valid = false; 0262 _maxFrameCount = 0; 0263 0264 _filename = filename; 0265 0266 if (init()) { 0267 _valid = true; 0268 } 0269 0270 registerChange(); 0271 } 0272 0273 0274 0275 FitsTableSource::~FitsTableSource() { 0276 0277 DBG qDebug() << "Entering FitsTableSource::~FitsTableSource()\n"; 0278 int status = 0; 0279 if (_fptr) { 0280 fits_close_file( _fptr, &status ); 0281 _fptr = 0L; 0282 } 0283 } 0284 0285 0286 void FitsTableSource::reset() { 0287 0288 DBG qDebug() << "Entering FitsTableSource::reset()\n"; 0289 0290 int status = 0; 0291 0292 if (_fptr){ 0293 fits_close_file(_fptr, &status); 0294 _fptr = 0L; 0295 } 0296 _maxFrameCount = 0; 0297 _valid = init(); 0298 } 0299 0300 int FitsTableSource::validField(int typecode){ 0301 /* check to see if typcode is one of the supported ones. If yes, return 1, 0302 else return 0 */ 0303 0304 int tmp; 0305 0306 switch(typecode){ 0307 case TINT: 0308 case TLONG: /* also covers TINT32BIT */ 0309 case TLONGLONG: 0310 case TFLOAT: 0311 case TDOUBLE: 0312 case TLOGICAL: 0313 tmp = 1; 0314 break; 0315 default: 0316 tmp = 0; 0317 } 0318 return tmp; 0319 } 0320 0321 // If the datasource has any predefined fields they should be populated here. 0322 bool FitsTableSource::init() { 0323 int status = 0; /* cfitsio status flag */ 0324 int colnum; /* column number in table */ 0325 int ncol; /* number of columns in table */ 0326 long nrow; /* number of rows in table */ 0327 char colname[512]; /* Name for column */ 0328 int typecode; /* data type of column in FITS table */ 0329 long width; /* width codes from fits_get_coltype(). not used */ 0330 int hdutype; /* FITS HDU type */ 0331 long repeat; /* used to determine if matrix or vector */ 0332 long i,j,k; /* loop variables */ 0333 char coltemplate[512]; /* template for reading column names */ 0334 QString tmp; /* format string for bolometer array */ 0335 int numHDU; /* total number of HDUs in FITS file */ 0336 int idx; /* used to get index of elements in lists, so we don't 0337 add the same scalar name, vector name, etc to the 0338 relevant list twice */ 0339 int naxis; /* length of naxes variable. Used for reading TDIM */ 0340 long *naxes; /* array to contain dimensionality of FITS columns */ 0341 int maxdim; /* maximum allowed array size of naxes */ 0342 QStringList allcols; /* list of all column names */ 0343 int nkeys; /* Number of header keywords in current HDU */ 0344 int keylength; /* length of keyword in characters (not used) */ 0345 int keyclass; /* class of FITS header keyword, e.g., TYP_USER_KEY */ 0346 char keyname[10]; /* array to hold FITS keyword name */ 0347 char keyvalue[128]; /* array to hold FITS keyword value */ 0348 char keycomment[128]; /* array to hold FITS keyword comment */ 0349 char fitsrecord[128]; /* array to hold one line of FITS header */ 0350 char keytype; /* FITS key type (string, float, int, etc) */ 0351 0352 maxdim = 2; 0353 naxes = (long *) malloc(maxdim*sizeof(long)); 0354 0355 DBG qDebug() << "Entering FitsTableSource::init() with filename: " << _filename.toAscii() << endl; 0356 // First, try to open the file 0357 if(fits_open_file( &_fptr, _filename.toAscii(), READONLY, &status )){ 0358 fits_close_file( _fptr, &status ); 0359 _fptr = 0L; 0360 _valid = false; 0361 free(naxes); 0362 return false; 0363 } 0364 _scalars.clear(); 0365 _fieldList.clear(); 0366 _matrixList.clear(); 0367 _strings.clear(); 0368 _colName.clear(); 0369 _colRepeat.clear(); 0370 _colType.clear(); 0371 _colOffset.clear(); 0372 tableHDU.clear(); 0373 tableRow.clear(); 0374 0375 // Some standard stuff 0376 _fieldList += "INDEX"; 0377 _colName += "INDEX"; 0378 _colRepeat << 1; 0379 _colType << 1; 0380 _colOffset << 0; 0381 0382 _strings = fileMetas(); 0383 _maxFrameCount = 0; 0384 0385 /* get total number of HDUs */ 0386 if (fits_get_num_hdus(_fptr, &numHDU, &status)){ 0387 fits_report_error(stderr,status); 0388 _fptr = 0L; 0389 _valid = false; 0390 free(naxes); 0391 return false; 0392 } /* can't read number of HDUs, so quit */ 0393 0394 nrow = 0; 0395 for (i=1; i<= numHDU; i++){ /* loop over all HDUs */ 0396 if (fits_movabs_hdu(_fptr, i, &hdutype, &status)){ 0397 fits_report_error(stderr,status); 0398 status = 0; 0399 continue; 0400 } /* failed moving to an HDU, so try to skip and go to next one */ 0401 /* read header to assign string and scalar values. For now only 0402 read USER_KEYs. May want to add UNIT_KEYs eventually, to get the 0403 units for every vector */ 0404 if(fits_get_hdrspace(_fptr, &nkeys, NULL, &status)){ /* total # of keys */ 0405 fits_report_error(stderr,status); 0406 status = 0; 0407 continue; 0408 } 0409 for (j=1; j<= nkeys; j++){ /* loop over keys */ 0410 if(fits_read_record(_fptr, j, fitsrecord, &status)){ 0411 fprintf(stderr,"Failed to read record number %ld\n",j); 0412 fits_report_error(stderr,status); 0413 status = 0; 0414 continue; 0415 } /* failed to read a record, so skip and continue */ 0416 if (fits_get_keyname(fitsrecord, keyname, &keylength, &status)){ 0417 fprintf(stderr,"Failed to read keyword from record = %s\n",fitsrecord); 0418 fits_report_error(stderr,status); 0419 status = 0; 0420 continue; 0421 } /* failed to read keyword name, so skip and continue */ 0422 if (strcmp(keyname,"HISTORY") == 0) /* skip HISTORY keywords */ 0423 continue; 0424 if (fits_parse_value(fitsrecord, keyvalue, keycomment, &status)){ 0425 fprintf(stderr,"Failed to read value and comment from key = %s\n",keyname); 0426 fits_report_error(stderr,status); 0427 status = 0; 0428 continue; 0429 } /* failed to read keyword value or comment, so skip and continue */ 0430 if (fits_get_keytype(keyvalue, &keytype, &status)){ 0431 fprintf(stderr,"Failed to read type (string, int, float) for key = %s, value = %s\n",keyname,keyvalue); 0432 fits_report_error(stderr,status); 0433 status = 0; 0434 continue; 0435 } /* failed to read keytype, so skip and continue */ 0436 keyclass = fits_get_keyclass(fitsrecord); 0437 if (keyclass == TYP_USER_KEY){ 0438 if (keytype == 'C' || keytype == 'L'){ /* string or logical */ 0439 _strings[QString(keyname)] = QString(keyvalue); 0440 } else if (keytype == 'I' || keytype == 'F'){ /* int or float */ 0441 _scalars[QString(keyname)] = atof(keyvalue); 0442 } 0443 } 0444 } 0445 0446 /* check if table HDU, and skip if not */ 0447 if (hdutype == ASCII_TBL || hdutype == BINARY_TBL){ 0448 if(fits_get_num_cols(_fptr, &ncol, &status)){ /* read # of columns */ 0449 fprintf(stderr,"Failed to read # of columns in HDU = %ld\n",i); 0450 fits_report_error(stderr,status); 0451 status = 0; 0452 continue; 0453 } /* failed to read number of columns, so skip and continue */ 0454 if(fits_get_num_rows(_fptr, &nrow, &status)){ /* read # of rows */ 0455 fprintf(stderr,"Failed to read # of rows in HDU = %ld\n",i); 0456 fits_report_error(stderr,status); 0457 status = 0; 0458 continue; 0459 } /* failed to read number of rows, so skip and continue */ 0460 tableRow << nrow; 0461 tableHDU << i; 0462 } else 0463 continue; /* skip non-table HDUs for reading table columns */ 0464 for (j=1; j<= ncol; j++){ 0465 sprintf(coltemplate,"%ld",j); 0466 if(fits_get_colname(_fptr, CASEINSEN, coltemplate, colname, &colnum, &status)){ 0467 fprintf(stderr,"Failed to read column name for column = %ld\n",j); 0468 fits_report_error(stderr,status); 0469 status = 0; 0470 continue; 0471 } /* failed to read column name, so skip and continue */ 0472 if(fits_get_coltype(_fptr, colnum, &typecode,&repeat,&width, &status)){ 0473 fprintf(stderr,"Failed to read column type for column = %s\n",colname); 0474 fits_report_error(stderr,status); 0475 status = 0; 0476 continue; 0477 } /* failed to read column type, so skip and continue */ 0478 if (validField(typecode)){ 0479 if (repeat == 1){ /* not an array of values */ 0480 idx = _fieldList.indexOf(QString(colname)); 0481 if (idx == -1){ /* not present in list already */ 0482 _fieldList << QString(colname); 0483 _colName << QString(colname); 0484 _colRepeat << repeat; 0485 _colType << typecode; 0486 _colOffset << 0; 0487 } 0488 _frameCounts[QString(colname)] += nrow; 0489 if (_frameCounts[QString(colname)] > _maxFrameCount) 0490 _maxFrameCount = _frameCounts[QString(colname)]; 0491 } else{ /* is an array of values */ 0492 /* TODO: should these be matrices instead (or perhaps as well?) 0493 I don't understand how matrices should work with KST */ 0494 if(fits_read_tdim(_fptr,colnum,maxdim, &naxis, naxes, &status)){ 0495 fprintf(stderr,"Failed to read dimensions of column = %s\n",colname); 0496 fits_report_error(stderr,status); 0497 status = 0; 0498 continue; 0499 } 0500 for (k=0; k < repeat; k++){ 0501 if (naxis == 1) 0502 tmp.sprintf("%s_%02ld",colname,k%naxes[0]+1); 0503 else if (naxis == 2) 0504 tmp.sprintf("%s_%02ld_%02ld",colname,k/naxes[0]+1,k%naxes[0]+1); 0505 else /* 3-D arrays not supported right now */ 0506 break; 0507 idx = _fieldList.indexOf(tmp); 0508 if (idx == -1){ /* not present already */ 0509 _fieldList << tmp; 0510 _colName << QString(colname); 0511 _colRepeat << repeat; 0512 _colType << typecode; 0513 _colOffset << k; 0514 } 0515 _frameCounts[tmp] += nrow; 0516 if (_frameCounts[QString(colname)] > _maxFrameCount) 0517 _maxFrameCount = _frameCounts[QString(colname)]; 0518 } 0519 } 0520 } else /* end if(validField) */ 0521 fprintf(stderr,"Skipping unsupported type for column = %s\n",colname); 0522 } /* end loop over columns */ 0523 } /* end loop over HDUs */ 0524 0525 /* set all fields to have _maxFrameCount size */ 0526 allcols = _frameCounts.keys(); 0527 for (i=0; i < allcols.size(); i++) 0528 _frameCounts[allcols[i]] = _maxFrameCount; 0529 registerChange(); 0530 free(naxes); 0531 return true; // false if something went wrong 0532 } 0533 0534 /* Check if the data in the from the source has updated. Considering how FITS 0535 files are built up we can consider that they are always fixed */ 0536 0537 Kst::Object::UpdateType FitsTableSource::internalDataSourceUpdate() { 0538 0539 DBG qDebug() << "Entering FitsTableSource::internalDataSourceUpdate()\n"; 0540 return Kst::Object::NoChange; 0541 } 0542 0543 int FitsTableSource::readScalar(double *v, const QString& field){ 0544 DBG qDebug() << "Entering FitsTableSource::readScalar() with field: " << field << endl; 0545 0546 *v = _scalars[field]; 0547 return 1; 0548 } 0549 0550 int FitsTableSource::readString(QString *stringValue, const QString& stringName){ 0551 DBG qDebug() << "Entering FitsTableSource::readString() with field: " << stringName << endl; 0552 *stringValue = _strings[stringName]; 0553 return 1; 0554 } 0555 0556 int FitsTableSource::readField(double *v, const QString& field, int s, int n) { 0557 int status = 0; /* cfitsio status flag */ 0558 int colnum; /* column number in table */ 0559 int anynul; /* Number of null values read by fits_read_col() */ 0560 int typecode; /* data type of column in FITS table */ 0561 long repeat; /* used to determine if matrix or vector */ 0562 void *data; /* empty pointer for reading data */ 0563 long nelements; /* size of data to read */ 0564 long offset; /* offset for data when repeat > 1 */ 0565 long idx; /* used when reading from Pixel Readout and tracking which 0566 section of data array is being read by fits_read_col */ 0567 long totalidx; /* to keep track of our location in the v array */ 0568 long i,j,k; /* loop variables */ 0569 long nrow; /* number of rows read for each data chunk */ 0570 long maxrow; /* maximum number of rows to read at once. Later re-used 0571 to signify the number of rows to read for the current 0572 HDU, which may not be tableRow[i], due to the fact 0573 that the offset, s, may not be zero. */ 0574 long currow; /* current row index (when looping over data chunks */ 0575 int hdutype; /* FITS HDU type */ 0576 char *colname; /* Name for column */ 0577 int firstHDU; /* Flag to control whether we are reading the first HDU 0578 containing data for a field. Necessary to keep track of 0579 s, the offset from the beginning of data */ 0580 QByteArray ba; /* needed to convert a QString to char array */ 0581 0582 DBG qDebug() << "Entering FitsTableSource::readField() with params: " << field << ", from " << s << " for " << n << " frames" << endl; 0583 0584 /* For INDEX field */ 0585 if (field.toLower() == "index") { 0586 if (n < 0) { 0587 v[0] = double(s); 0588 return 1; 0589 } 0590 for (int i = 0; i < n; ++i) { 0591 v[i] = double(s + i); 0592 } 0593 return n; 0594 } 0595 0596 idx = _fieldList.indexOf(field); /* get index of field in list */ 0597 repeat = _colRepeat[idx]; 0598 typecode = _colType[idx]; /* FITS type code for field */ 0599 ba = _colName[idx].toLocal8Bit(); /* FITS column name of field */ 0600 colname = ba.data(); 0601 offset = _colOffset[idx]; /* data offset */ 0602 0603 firstHDU = 1; 0604 maxrow = 100000/repeat; /* cap on max rows to read at once */ 0605 nelements = maxrow * repeat; /* so we read an integer number of 'repeat' at a time */ 0606 if (typecode == TINT) 0607 data = (int *) malloc(nelements*sizeof(int)); 0608 else if (typecode == TLONG || typecode == TINT32BIT) 0609 data = (long *) malloc(nelements*sizeof(long)); 0610 else if (typecode == TLONGLONG) 0611 data = (long long *) malloc(nelements*sizeof(long long)); 0612 else if (typecode == TFLOAT) 0613 data = (float *) malloc(nelements*sizeof(float)); 0614 else if (typecode == TDOUBLE) 0615 data = (double *) malloc(nelements*sizeof(double)); 0616 else if (typecode == TLOGICAL) 0617 data = (bool *) malloc(nelements*sizeof(bool)); 0618 0619 totalidx = 0; 0620 for (i=0; i < tableHDU.size(); i++){ /* loop over table HDUs */ 0621 if (totalidx >= n) /* quit when we have read all data requested */ 0622 break; 0623 if (fits_movabs_hdu(_fptr, tableHDU[i], &hdutype, &status)){ 0624 fits_report_error(stderr,status); 0625 status = 0; 0626 continue; 0627 } /* failed moving to an HDU, so try to skip and go to next one */ 0628 if(fits_get_colnum(_fptr, CASEINSEN, colname, &colnum, &status)){ 0629 status = 0; /* column not found in this HDU, so skip. */ 0630 continue; 0631 } 0632 if (firstHDU == 1){ 0633 maxrow = tableRow[i] - s; 0634 firstHDU = 0; 0635 currow = s + 1; /* FITS starts counting from row 1 */ 0636 } else{ 0637 maxrow = tableRow[i]; 0638 currow = 1; /* FITS starts counting from row 1 */ 0639 } 0640 0641 /* figure out how many chunks we need to read the rows in this HDU */ 0642 idx = (maxrow*repeat)%nelements; 0643 if (idx == 0) /* divides evenly */ 0644 idx = (maxrow*repeat)/nelements; 0645 else 0646 idx = (maxrow*repeat)/nelements + 1; 0647 for (j=0; j < idx; j++){ /* loop over row chunks */ 0648 if (totalidx >= n) /* quit when we have read all data requested */ 0649 break; 0650 if (j == (idx - 1)) /* last iteration */ 0651 nrow = (maxrow*repeat - j*nelements)/repeat; 0652 else 0653 nrow = nelements/repeat; 0654 /* check to make sure we don't read more data than requested */ 0655 if (totalidx + nrow > n) 0656 nrow = n - totalidx; 0657 if (typecode == TINT){ 0658 if (fits_read_col(_fptr, typecode, colnum, currow, 1, 0659 nrow*repeat, NULL, &(((int *)data)[0]), &anynul, &status)){ 0660 fprintf(stderr,"Failed to read column = %s, filling with NaNs\n",colname); 0661 fits_report_error(stderr,status); 0662 status = 0; 0663 for (k=0; k < nrow; k++) 0664 v[totalidx+k] = sqrt(-1); 0665 } else { 0666 for (k=0; k < nrow; k++){ 0667 v[totalidx+k] = (double) ((int *)data)[k*repeat+offset]; 0668 } 0669 } 0670 } else if (typecode == TLONG || typecode == TINT32BIT){ 0671 if (fits_read_col(_fptr, typecode, colnum, currow, 1, 0672 nrow*repeat, NULL, &(((long *)data)[0]), &anynul, &status)){ 0673 fprintf(stderr,"Failed to read column = %s, filling with NaNs\n",colname); 0674 fits_report_error(stderr,status); 0675 status = 0; 0676 for (k=0; k < nrow; k++) 0677 v[totalidx+k] = sqrt(-1); 0678 } else { 0679 for (k=0; k < nrow; k++){ 0680 v[totalidx+k] = (double) ((long *)data)[k*repeat+offset]; 0681 } 0682 } 0683 } else if (typecode == TLONGLONG){ 0684 if (fits_read_col(_fptr, typecode, colnum, currow, 1, 0685 nrow*repeat, NULL, &(((long long *)data)[0]), &anynul, &status)){ 0686 fprintf(stderr,"Failed to read column = %s, filling with NaNs\n",colname); 0687 fits_report_error(stderr,status); 0688 status = 0; 0689 for (k=0; k < nrow; k++) 0690 v[totalidx+k] = sqrt(-1); 0691 } else { 0692 for (k=0; k < nrow; k++){ 0693 v[totalidx+k] = (double) ((long long *)data)[k*repeat+offset]; 0694 } 0695 } 0696 }else if (typecode == TFLOAT){ 0697 if (fits_read_col(_fptr, typecode, colnum, currow, 1, 0698 nrow*repeat, NULL, &(((float *)data)[0]), &anynul, &status)){ 0699 fprintf(stderr,"Failed to read column = %s, filling with NaNs\n",colname); 0700 fits_report_error(stderr,status); 0701 status = 0; 0702 for (k=0; k < nrow; k++) 0703 v[totalidx+k] = sqrt(-1); 0704 } else { 0705 for (k=0; k < nrow; k++) 0706 v[totalidx+k] = (double) ((float *)data)[k*repeat+offset]; 0707 } 0708 }else if (typecode == TDOUBLE){ 0709 if (fits_read_col(_fptr, typecode, colnum, currow, 1, 0710 nrow*repeat, NULL, &(((double *)data)[0]), &anynul, &status)){ 0711 fprintf(stderr,"Failed to read column = %s, filling with NaNs\n",colname); 0712 fits_report_error(stderr,status); 0713 status = 0; 0714 for (k=0; k < nrow; k++) 0715 v[totalidx+k] = sqrt(-1); 0716 } else { 0717 for (k=0; k < nrow; k++) 0718 v[totalidx+k] = (double) ((double *)data)[k*repeat+offset]; 0719 } 0720 }else if (typecode == TLOGICAL){ 0721 if (fits_read_col(_fptr, typecode, colnum, currow, 1, 0722 nrow*repeat, NULL, &(((bool *)data)[0]), &anynul, &status)){ 0723 fprintf(stderr,"Failed to read column = %s, filling with NaNs\n",colname); 0724 fits_report_error(stderr,status); 0725 status = 0; 0726 for (k=0; k < nrow; k++) 0727 v[totalidx+k] = sqrt(-1); 0728 } else { 0729 for (k=0; k < nrow; k++) 0730 v[totalidx+k] = (double) ((bool *)data)[k*repeat+offset]; 0731 } 0732 } 0733 totalidx += nrow; 0734 currow += nrow; 0735 } /* end loop over row chunks */ 0736 } /* end loop over HDUs */ 0737 0738 for (i=totalidx; i< n; i++) /* fill remainder with NaNs */ 0739 v[i] = sqrt(-1); 0740 free(data); 0741 return n; 0742 } 0743 0744 int FitsTableSource::readMatrix(double *v, const QString& field){ 0745 int status = 0; /* cfitsio status flag */ 0746 int colnum; /* column number in table */ 0747 int anynul; /* Number of null values read by fits_read_col() */ 0748 int typecode; /* data type of column in FITS table */ 0749 long width; /* width code from fits_get_coltype(). not used */ 0750 long repeat; /* used to determine if matrix or vector */ 0751 long n; /* total size */ 0752 long nrow; /* number of rows */ 0753 void *data; /* empty pointer for reading data */ 0754 0755 /* TODO: The code in this function is probably all wrong. Since fitstable 0756 does not currently implement matrices, this function never gets called */ 0757 DBG qDebug() << "Entering FitsTableSource::readMatrix() with field: " << field << endl; 0758 if (fits_get_colnum(_fptr, CASEINSEN, field.toAscii().data(), &colnum, &status)) 0759 fits_report_error(stderr,status); 0760 if (fits_get_coltype(_fptr, colnum, &typecode, &repeat, &width, &status)) 0761 fits_report_error(stderr,status); 0762 if (fits_get_num_rows(_fptr, &nrow, &status)) 0763 fits_report_error(stderr,status); 0764 0765 n = repeat*nrow; 0766 if (typecode == TLONG || typecode == TINT32BIT) 0767 data = (int *) malloc(n*sizeof(int)); 0768 else if (typecode == TLONGLONG) 0769 data = (long long *) malloc(n*sizeof(long long)); 0770 else if (typecode == TFLOAT) 0771 data = (float *) malloc(n*sizeof(float)); 0772 else if (typecode == TDOUBLE) 0773 data = (double *) malloc(n*sizeof(double)); 0774 else if (typecode == TLOGICAL) 0775 data = (bool *) malloc(n*sizeof(bool)); 0776 0777 if (fits_read_col(_fptr, typecode, colnum, 1, 1, n, NULL, data, &anynul, &status)) 0778 fits_report_error(stderr,status); 0779 for (int i=0; i < n; i++){ 0780 if (typecode == TLONG || typecode == TINT32BIT) 0781 v[i] = (double) ((int *)data)[i]; 0782 else if (typecode == TLONGLONG) 0783 v[i] = (double) ((long long *)data)[i]; 0784 else if (typecode == TFLOAT) 0785 v[i] = (double) ((float *)data)[i]; 0786 else if (typecode == TDOUBLE) 0787 v[i] = (double) ((double *)data)[i]; 0788 else if (typecode == TLOGICAL) 0789 v[i] = (double) ((bool *)data)[i]; 0790 } 0791 0792 free(data); 0793 return n; 0794 } 0795 0796 int FitsTableSource::frameCount(const QString& field) const { 0797 0798 DBG qDebug() << "Entering FitsTableSource::frameCount() with field: " << field << endl; 0799 if (field.isEmpty() || field.toLower() == "index") { 0800 return _maxFrameCount; 0801 } else { 0802 return _frameCounts[field]; 0803 } 0804 } 0805 0806 QString FitsTableSource::fileType() const { 0807 return "FITS Table Datasource"; 0808 } 0809 0810 0811 void FitsTableSource::save(QXmlStreamWriter &streamWriter) { 0812 Kst::DataSource::save(streamWriter); 0813 } 0814 0815 int FitsTableSource::samplesPerFrame(const QString& field) { 0816 return 1; 0817 } 0818 0819 0820 // Name used to identify the plugin. Used when loading the plugin. 0821 QString FitsTableSourcePlugin::pluginName() const { return "FITS Table Datasource Reader"; } 0822 QString FitsTableSourcePlugin::pluginDescription() const { return "FITS Table Datasource Reader"; } 0823 0824 /********************** 0825 FitsTablesourcePlugin - This class defines the plugin interface to the DataSource 0826 defined by the plugin. The primary requirements of this class are to provide the 0827 necessary connections to create the object which includes providing access to 0828 the configuration widget. 0829 ***********************/ 0830 0831 Kst::DataSource *FitsTableSourcePlugin::create(Kst::ObjectStore *store, 0832 QSettings *cfg, 0833 const QString &filename, 0834 const QString &type, 0835 const QDomElement &element) const { 0836 0837 return new FitsTableSource(store, cfg, filename, type, element); 0838 } 0839 0840 0841 // Provides the matrix list that this dataSource can provide from the provided filename. 0842 // This function should use understands to validate the file and then open and calculate the 0843 // list of matrices. 0844 QStringList FitsTableSourcePlugin::matrixList(QSettings *cfg, 0845 const QString& filename, 0846 const QString& type, 0847 QString *typeSuggestion, 0848 bool *complete) const { 0849 0850 DBG qDebug() << "Entering FitsTableSourcePlugin::matrixList()\n"; 0851 if (typeSuggestion) { 0852 *typeSuggestion = "FITS Table Datasource"; 0853 } 0854 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0855 if (complete) { 0856 *complete = false; 0857 } 0858 return QStringList(); 0859 } 0860 QStringList matrixList; 0861 0862 return matrixList; 0863 0864 } 0865 0866 0867 /* Provides the scalar list that this dataSource can provide from the provided 0868 filename. This function should use understands to validate the file and then 0869 open and calculate the list of scalars if necessary. 0870 */ 0871 QStringList FitsTableSourcePlugin::scalarList(QSettings *cfg, 0872 const QString& filename, 0873 const QString& type, 0874 QString *typeSuggestion, 0875 bool *complete) const { 0876 0877 QStringList scalarList; 0878 0879 DBG qDebug() << "Entering FitsTableSourcePlugin::scalarList()\n"; 0880 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0881 if (complete) { 0882 *complete = false; 0883 } 0884 return QStringList(); 0885 } 0886 0887 if (typeSuggestion) { 0888 *typeSuggestion = "FITS Table Datasource"; 0889 } 0890 0891 scalarList.append("FRAMES"); 0892 return scalarList; 0893 } 0894 0895 0896 /* Provides the string list that this dataSource can provide from the provided 0897 filename. This function should use understands to validate the file and then 0898 open and calculate the list of strings if necessary. 0899 */ 0900 QStringList FitsTableSourcePlugin::stringList(QSettings *cfg, 0901 const QString& filename, 0902 const QString& type, 0903 QString *typeSuggestion, 0904 bool *complete) const { 0905 0906 QStringList stringList; 0907 0908 DBG qDebug() << "Entering FitsTableSourcePlugin::stringList()\n"; 0909 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0910 if (complete) { 0911 *complete = false; 0912 } 0913 return QStringList(); 0914 } 0915 0916 if (typeSuggestion) { 0917 *typeSuggestion = "FITS Table Datasource"; 0918 } 0919 0920 stringList.append("FILENAME"); 0921 return stringList; 0922 } 0923 0924 0925 /* Provides the field list that this dataSource can provide from the provided 0926 filename. This function should use understands to validate the file and then 0927 open and calculate the list of fields if necessary. 0928 */ 0929 QStringList FitsTableSourcePlugin::fieldList(QSettings *cfg, 0930 const QString& filename, 0931 const QString& type, 0932 QString *typeSuggestion, 0933 bool *complete) const { 0934 Q_UNUSED(cfg) 0935 Q_UNUSED(filename) 0936 Q_UNUSED(type) 0937 0938 DBG qDebug() << "Entering FitsTableSourcePlugin::fieldList()\n"; 0939 if (complete) { 0940 *complete = true; 0941 } 0942 0943 if (typeSuggestion) { 0944 *typeSuggestion = "FITS Table Datasource"; 0945 } 0946 0947 QStringList fieldList; 0948 return fieldList; 0949 } 0950 0951 /* The main function used to determine if this plugin knows how to process the 0952 provided file. Each datasource plugin should check the file and return a number 0953 between 0 and 100 based on the likelyhood of the file being this type. 100 0954 should only be returned if there is no way that the file could be any datasource 0955 other than this one. 0956 */ 0957 int FitsTableSourcePlugin::understands(QSettings *cfg, const QString& filename) const { 0958 /* This function will attempt to open the file as a FITS file, then loop 0959 through the HDUs to see if any are binary or ascii tables. If so, and 0960 if any table has > 0 rows, then this is a FITS table that can be read 0961 by this plugin. A value of 80 is returned, otherwise zero */ 0962 Q_UNUSED(cfg) 0963 0964 fitsfile *ff; 0965 int status = 0; /* FITS error status */ 0966 int i; /* loop variable */ 0967 int ret_val = 0; 0968 int numHDU; /* total number of HDUs in FITS file */ 0969 int hdutype; /* FITS HDU type */ 0970 long nrow; /* number of rows in table */ 0971 0972 DBG qDebug() << "Entering FitsTableSourcePlugin::understands()\n"; 0973 if(fits_open_file(&ff, filename.toAscii(), READONLY, &status)){ 0974 fits_close_file(ff,&status); 0975 return 0; 0976 } 0977 if (fits_get_num_hdus(ff, &numHDU, &status)){ 0978 fits_close_file(ff,&status); 0979 return 0; 0980 } 0981 for(i=1; i<= numHDU; i++){ 0982 if (fits_movabs_hdu(ff, i, &hdutype, &status)){ 0983 fits_report_error(stderr,status); 0984 status = 0; 0985 continue; 0986 } 0987 if (hdutype == ASCII_TBL || hdutype == BINARY_TBL){ 0988 if(fits_get_num_rows(ff, &nrow, &status)){ 0989 fits_report_error(stderr,status); 0990 status = 0; 0991 continue; 0992 } 0993 if (nrow > 0){ 0994 ret_val = 80; 0995 break; 0996 } 0997 } 0998 } 0999 status = 0; 1000 fits_close_file(ff,&status); 1001 return ret_val; 1002 } 1003 1004 bool FitsTableSourcePlugin::supportsTime(QSettings *cfg, const QString& filename) const { 1005 //FIXME 1006 Q_UNUSED(cfg) 1007 Q_UNUSED(filename) 1008 return false; 1009 } 1010 1011 1012 QStringList FitsTableSourcePlugin::provides() const { 1013 QStringList rc; 1014 rc += "FITS Table Datasource"; 1015 return rc; 1016 } 1017 1018 1019 // Request for this plugins configuration widget. 1020 Kst::DataSourceConfigWidget *FitsTableSourcePlugin::configWidget(QSettings *cfg, 1021 const QString& filename) const { 1022 1023 Q_UNUSED(cfg) 1024 Q_UNUSED(filename) 1025 return 0; 1026 } 1027 1028 1029 #ifndef QT5 1030 Q_EXPORT_PLUGIN2(kstdata_fitstable, FitsTableSourcePlugin) 1031 #endif 1032 1033 // vim: ts=2 sw=2 et