File indexing completed on 2024-12-22 04:17:05
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 "healpix.h" 0014 0015 #include <assert.h> 0016 #include <QXmlStreamWriter> 0017 #include <math.h> 0018 0019 #include "ui_healpixconfig.h" 0020 0021 #define DEFAULT_XDIM 800 0022 #define DEFAULT_YDIM 600 0023 #define HPUNIT_RAD 0 0024 #define HPUNIT_DEG 1 0025 #define HPUNIT_RADEC 2 0026 #define HPUNIT_LATLON 3 0027 0028 #include "kst_i18n.h" 0029 0030 static const QString healpixTypeString = I18N_NOOP("HEALPIX image"); 0031 0032 class HealpixSource::Config { 0033 public: 0034 Config() { 0035 _nX = 800; 0036 _nY = 600; 0037 _autoTheta = true; 0038 _autoPhi = true; 0039 //FIXME switch to radians default later 0040 _thetaUnits = HPUNIT_RADEC; 0041 _phiUnits = HPUNIT_RADEC; 0042 _vecUnits = HPUNIT_RADEC; 0043 _autoMag = true; 0044 _vecDegrade = 0; 0045 _vecTheta = 0; 0046 _vecPhi = 0; 0047 _vecQU = false; 0048 } 0049 0050 void read(QSettings *cfg, const QString& fileName = QString::null) { 0051 Q_UNUSED(fileName); 0052 cfg->beginGroup(healpixTypeString); 0053 double confThetaMin; 0054 double confThetaMax; 0055 double confPhiMin; 0056 double confPhiMax; 0057 int tempdegrade; 0058 0059 if (!fileName.isEmpty()) { 0060 cfg->endGroup(); 0061 cfg->beginGroup(fileName); 0062 } 0063 _nX = cfg->value("Matrix X Dimension", DEFAULT_XDIM).toInt(); 0064 _nY = cfg->value("Matrix Y Dimension", DEFAULT_YDIM).toInt(); 0065 _autoTheta = cfg->value("Theta Autoscale", true).toBool(); 0066 _thetaUnits = cfg->value("Theta Units", HPUNIT_RADEC).toInt(); 0067 confThetaMin = cfg->value("Theta Min", 0).toDouble(); 0068 confThetaMax = cfg->value("Theta Max", 0).toDouble(); 0069 _autoPhi = cfg->value("Phi Autoscale", true).toBool(); 0070 _phiUnits = cfg->value("Phi Units", HPUNIT_RADEC).toInt(); 0071 confPhiMin = cfg->value("Phi Min", 0).toDouble(); 0072 confPhiMax = cfg->value("Phi Max", 0).toDouble(); 0073 _vecTheta = cfg->value("Vector Theta", 0).toInt(); 0074 _vecPhi = cfg->value("Vector Phi", 0).toInt(); 0075 tempdegrade = cfg->value("Vector Degrade Factor", 1).toInt(); 0076 _autoMag = cfg->value("Vector Magnitude Autoscale", true).toBool(); 0077 _maxMag = cfg->value("Vector Max Magnitude", 0).toDouble(); 0078 _vecQU = cfg->value("Vector is QU", false).toBool(); 0079 0080 // check degrade factor 0081 checkDegrade(tempdegrade); 0082 _vecDegrade = tempdegrade; 0083 0084 // convert the entered range values into radians and 0085 // force them to the correct range. 0086 theta2Internal(_thetaUnits, confThetaMin); 0087 theta2Internal(_thetaUnits, confThetaMax); 0088 phi2Internal(_phiUnits, confPhiMin); 0089 phi2Internal(_phiUnits, confPhiMax); 0090 0091 // swap theta min/max if coordinate system requires it 0092 if (confThetaMax < confThetaMin) { 0093 double temp = confThetaMax; 0094 confThetaMax = confThetaMin; 0095 confThetaMin = temp; 0096 } 0097 0098 _thetaMin = confThetaMin; 0099 _thetaMax = confThetaMax; 0100 _phiMin = confPhiMin; 0101 _phiMax = confPhiMax; 0102 0103 cfg->endGroup(); 0104 } 0105 0106 void save(QXmlStreamWriter& s) { 0107 double confThetaMin = _thetaMin; 0108 double confThetaMax = _thetaMax; 0109 double confPhiMin = _phiMin; 0110 double confPhiMax = _phiMax; 0111 0112 // export the internal range (in radians) to the 0113 // selected coordinate system 0114 theta2External(_thetaUnits, confThetaMin); 0115 theta2External(_thetaUnits, confThetaMax); 0116 phi2External(_phiUnits, confPhiMin); 0117 phi2External(_phiUnits, confPhiMax); 0118 0119 // swap theta min/max if coordinate system requires it 0120 if (confThetaMax < confThetaMin) { 0121 double temp = confThetaMax; 0122 confThetaMax = confThetaMin; 0123 confThetaMin = temp; 0124 } 0125 s.writeStartElement("properties"); 0126 s.writeAttribute("dim-x", QString::number(_nX)); 0127 s.writeAttribute("dim-y", QString::number(_nY)); 0128 s.writeAttribute("theta-auto", QVariant(_autoTheta).toString()); 0129 s.writeAttribute("theta-units", QString::number(_thetaUnits)); 0130 s.writeAttribute("theta-min", QString::number(confThetaMin)); 0131 s.writeAttribute("theta-max", QString::number(confThetaMax)); 0132 s.writeAttribute("phi-auto", QVariant(_autoPhi).toString()); 0133 s.writeAttribute("phi-units", QString::number(_phiUnits)); 0134 s.writeAttribute("phi-min", QString::number(confPhiMin)); 0135 s.writeAttribute("phi-max", QString::number(confPhiMax)); 0136 s.writeAttribute("vector-theta", QString::number(_vecTheta)); 0137 s.writeAttribute("vector-phi", QString::number(_vecPhi)); 0138 s.writeAttribute("vector-degrade", QVariant(_vecDegrade).toString()); 0139 s.writeAttribute("vector-auto", QVariant(_autoMag).toString()); 0140 s.writeAttribute("vector-max", QString::number(_maxMag)); 0141 s.writeAttribute("vector-QU", QVariant(_vecQU).toString()); 0142 s.writeEndElement(); 0143 } 0144 0145 void parseProperties(QXmlStreamAttributes &properties) { 0146 double confThetaMin; 0147 double confThetaMax; 0148 double confPhiMin; 0149 double confPhiMax; 0150 int tempdegrade; 0151 0152 _nX = properties.value("dim-x").toString().toInt(); 0153 _nY = properties.value("dim-y").toString().toInt(); 0154 _autoTheta = QVariant(properties.value("theta-auto").toString()).toBool(); 0155 _thetaUnits = properties.value("theta-units").toString().toInt(); 0156 confThetaMin = properties.value("theta-min").toString().toDouble(); 0157 confThetaMax = properties.value("theta-max").toString().toDouble(); 0158 _autoPhi = QVariant(properties.value("phi-auto").toString()).toBool(); 0159 _phiUnits = properties.value("phi-units").toString().toInt(); 0160 confPhiMin = properties.value("phi-min").toString().toDouble(); 0161 confPhiMax = properties.value("phi-max").toString().toDouble(); 0162 _vecTheta = properties.value("vector-theta").toString().toInt(); 0163 _vecPhi = properties.value("vector-phi").toString().toInt(); 0164 tempdegrade = QVariant(properties.value("vector-degrade").toString()).toBool(); 0165 _autoMag = QVariant(properties.value("vector-auto").toString()).toBool(); 0166 _vecQU = QVariant(properties.value("vector-QU").toString()).toBool(); 0167 _maxMag = properties.value("vector-max").toString().toDouble(); 0168 0169 checkDegrade(tempdegrade); 0170 _vecDegrade = tempdegrade; 0171 0172 // convert the entered range values into radians and 0173 // force them to the correct range. 0174 theta2Internal(_thetaUnits, confThetaMin); 0175 theta2Internal(_thetaUnits, confThetaMax); 0176 phi2Internal(_phiUnits, confPhiMin); 0177 phi2Internal(_phiUnits, confPhiMax); 0178 0179 // swap theta min/max if coordinate system requires it 0180 if (confThetaMax < confThetaMin) { 0181 double temp = confThetaMax; 0182 confThetaMax = confThetaMin; 0183 confThetaMin = temp; 0184 } 0185 0186 _thetaMin = confThetaMin; 0187 _thetaMax = confThetaMax; 0188 _phiMin = confPhiMin; 0189 _phiMax = confPhiMax; 0190 } 0191 0192 0193 void load(const QDomElement& e) { 0194 double confThetaMin; 0195 double confThetaMax; 0196 double confPhiMin; 0197 double confPhiMax; 0198 int tempdegrade; 0199 QDomNode n = e.firstChild(); 0200 while (!n.isNull()) { 0201 QDomElement e = n.toElement(); 0202 if (!e.isNull()) { 0203 if (e.tagName() == "dim") { 0204 if (e.hasAttribute("x")) { 0205 _nX = e.attribute("x").toInt(); 0206 } 0207 if (e.hasAttribute("y")) { 0208 _nX = e.attribute("y").toInt(); 0209 } 0210 } else if (e.tagName() == "theta") { 0211 if (e.hasAttribute("auto")) { 0212 _autoTheta = e.attribute("auto").toInt(); 0213 } 0214 if (e.hasAttribute("units")) { 0215 _thetaUnits = e.attribute("units").toInt(); 0216 } 0217 if (e.hasAttribute("min")) { 0218 confThetaMin = e.attribute("min").toDouble(); 0219 } 0220 if (e.hasAttribute("max")) { 0221 confThetaMax = e.attribute("max").toDouble(); 0222 } 0223 } else if (e.tagName() == "phi") { 0224 if (e.hasAttribute("auto")) { 0225 _autoPhi = e.attribute("auto").toInt(); 0226 } 0227 if (e.hasAttribute("units")) { 0228 _phiUnits = e.attribute("units").toInt(); 0229 } 0230 if (e.hasAttribute("min")) { 0231 confPhiMin = e.attribute("min").toDouble(); 0232 } 0233 if (e.hasAttribute("max")) { 0234 confPhiMax = e.attribute("max").toDouble(); 0235 } 0236 } else if (e.tagName() == "vector") { 0237 if (e.hasAttribute("auto")) { 0238 _autoMag = e.attribute("auto").toInt(); 0239 } 0240 if (e.hasAttribute("degrade")) { 0241 tempdegrade = e.attribute("degrade").toInt(); 0242 checkDegrade(tempdegrade); 0243 _vecDegrade = tempdegrade; 0244 } 0245 if (e.hasAttribute("theta")) { 0246 _vecTheta = e.attribute("theta").toInt(); 0247 } 0248 if (e.hasAttribute("phi")) { 0249 _vecPhi = e.attribute("phi").toInt(); 0250 } 0251 if (e.hasAttribute("QU")) { 0252 _vecQU = e.attribute("QU").toInt(); 0253 } 0254 if (e.hasAttribute("max")) { 0255 _maxMag = e.attribute("max").toDouble(); 0256 } 0257 } 0258 } 0259 n = n.nextSibling(); 0260 } 0261 0262 // convert the entered range values into radians and 0263 // force them to the correct range. 0264 theta2Internal(_thetaUnits, confThetaMin); 0265 theta2Internal(_thetaUnits, confThetaMax); 0266 phi2Internal(_phiUnits, confPhiMin); 0267 phi2Internal(_phiUnits, confPhiMax); 0268 0269 // swap theta min/max if coordinate system requires it 0270 if (confThetaMax < confThetaMin) { 0271 double temp = confThetaMax; 0272 confThetaMax = confThetaMin; 0273 confThetaMin = temp; 0274 } 0275 0276 _thetaMin = confThetaMin; 0277 _thetaMax = confThetaMax; 0278 _phiMin = confPhiMin; 0279 _phiMax = confPhiMax; 0280 } 0281 0282 // data range 0283 int _nX; 0284 int _nY; 0285 double _thetaMin; 0286 double _phiMin; 0287 double _thetaMax; 0288 double _phiMax; 0289 bool _autoTheta; 0290 bool _autoPhi; 0291 0292 //values are 0293 // 0 : Radians 0294 // 1 : Degrees 0295 // 2 : Degrees RA/DEC 0296 // 3 : Degrees Lat/Long 0297 int _thetaUnits; 0298 int _phiUnits; 0299 int _vecUnits; 0300 0301 // vector field 0302 int _vecDegrade; 0303 int _vecTheta; 0304 int _vecPhi; 0305 bool _autoMag; 0306 double _maxMag; 0307 bool _vecQU; 0308 0309 size_t _mapNside; 0310 0311 void checkDegrade(int& degrade) { 0312 int nside = _mapNside; 0313 if (!degrade) { 0314 return; 0315 } 0316 if ((nside == 1) && (degrade != 0)) { 0317 degrade = 0; 0318 return; 0319 } 0320 for (int i = 0; i < degrade; i++) { 0321 nside = (int)(nside/2); 0322 if (nside == 1) { 0323 degrade = i+1; 0324 return; 0325 } 0326 } 0327 return; 0328 } 0329 0330 void theta2Internal(int units, double& theta) { 0331 switch (units) { 0332 case HPUNIT_RAD: 0333 break; 0334 case HPUNIT_DEG: 0335 theta *= HEALPIX_PI/180.0; 0336 break; 0337 case HPUNIT_RADEC: case HPUNIT_LATLON: 0338 theta = (90.0 - theta) * HEALPIX_PI/180.0; 0339 break; 0340 default: 0341 break; 0342 } 0343 while (theta < 0.0) { 0344 theta += HEALPIX_PI; 0345 } 0346 while (theta > HEALPIX_PI) { 0347 theta -= HEALPIX_PI; 0348 } 0349 return; 0350 } 0351 0352 void theta2External(int units, double& theta) { 0353 switch (units) { 0354 case HPUNIT_RAD: 0355 break; 0356 case HPUNIT_DEG: 0357 theta *= 180.0/HEALPIX_PI; 0358 break; 0359 case HPUNIT_RADEC: case HPUNIT_LATLON: 0360 theta = 90.0 - theta*180.0/HEALPIX_PI; 0361 break; 0362 default: 0363 break; 0364 } 0365 return; 0366 } 0367 0368 void phi2Internal(int units, double& phi) { 0369 switch (units) { 0370 case HPUNIT_RAD: 0371 break; 0372 case HPUNIT_DEG: case HPUNIT_RADEC: case HPUNIT_LATLON: 0373 phi *= HEALPIX_PI/180.0; 0374 break; 0375 default: 0376 break; 0377 } 0378 while (phi < 0.0) { 0379 phi += 2.0*HEALPIX_PI; 0380 } 0381 while (phi > 2.0*HEALPIX_PI) { 0382 phi -= 2.0*HEALPIX_PI; 0383 } 0384 return; 0385 } 0386 0387 void phi2External(int units, double& phi) { 0388 switch (units) { 0389 case HPUNIT_RAD: 0390 break; 0391 case HPUNIT_DEG: case HPUNIT_RADEC: 0392 phi *= 180.0/HEALPIX_PI; 0393 break; 0394 case HPUNIT_LATLON: 0395 phi *= 180.0/HEALPIX_PI; 0396 if (phi >= 180.0) { 0397 phi -= 360.0; 0398 } 0399 break; 0400 default: 0401 break; 0402 } 0403 return; 0404 } 0405 }; 0406 0407 0408 HealpixSource::HealpixSource(Kst::ObjectStore *store, QSettings *cfg, const QString& filename, const QString& type, const QDomElement& e) 0409 : Kst::DataSource(store, cfg, filename, type), _config(0L) { 0410 _valid = false; 0411 0412 if (!type.isEmpty() && type != "HEALPIX Source") { 0413 return; 0414 } 0415 0416 _config = new HealpixSource::Config; 0417 _config->read(cfg, filename); 0418 if (!e.isNull()) { 0419 _config->load(e); 0420 } 0421 0422 if (init()) { 0423 _valid = true; 0424 } 0425 0426 update(); 0427 } 0428 0429 0430 HealpixSource::~HealpixSource() { 0431 if (_keys) { 0432 healpix_keys_free(_keys); 0433 } 0434 if (_names) { 0435 healpix_strarr_free(_names, HEALPIX_FITS_MAXCOL); 0436 } 0437 if (_units) { 0438 healpix_strarr_free(_units, HEALPIX_FITS_MAXCOL); 0439 } 0440 } 0441 0442 0443 void HealpixSource::reset() { 0444 return; 0445 } 0446 0447 0448 bool HealpixSource::init() { 0449 size_t poff; 0450 0451 strncpy(_healpixfile, _filename.toLatin1().data(), HEALPIX_STRNL); 0452 0453 _names = healpix_strarr_alloc(HEALPIX_FITS_MAXCOL); 0454 _units = healpix_strarr_alloc(HEALPIX_FITS_MAXCOL); 0455 _keys = healpix_keys_alloc(); 0456 0457 if (!healpix_fits_map_info(_healpixfile, &_mapNside, &_mapOrder, &_mapCoord, &_mapType, &_nMaps, _creator, _extname, _names, _units, _keys)) { 0458 healpix_keys_free(_keys); 0459 healpix_strarr_free(_names, HEALPIX_FITS_MAXCOL); 0460 healpix_strarr_free(_units, HEALPIX_FITS_MAXCOL); 0461 0462 return false; 0463 } 0464 0465 _config->_mapNside = _mapNside; 0466 if (_mapType == HEALPIX_FITS_CUT) { 0467 poff = 1; 0468 } else { 0469 poff = 0; 0470 } 0471 0472 _mapNpix = 12 * _mapNside * _mapNside; 0473 0474 // populate the metadata 0475 QString metaVal; 0476 QString metaName; 0477 0478 metaName = "NSIDE"; 0479 metaVal.sprintf("%lu", (long unsigned int)_mapNside); 0480 _metaData.insert(metaName, metaVal); 0481 0482 metaName = "NPIX"; 0483 metaVal.sprintf("%lu", (long unsigned int)_mapNpix); 0484 _metaData.insert(metaName, metaVal); 0485 0486 metaName = "ORDER"; 0487 metaVal.sprintf("%d", _mapOrder); 0488 _metaData.insert(metaName, metaVal); 0489 0490 metaName = "COORD"; 0491 metaVal.sprintf("%d", _mapCoord); 0492 _metaData.insert(metaName, metaVal); 0493 0494 metaName = "TYPE"; 0495 metaVal.sprintf("%d", _mapType); 0496 _metaData.insert(metaName, metaVal); 0497 0498 metaName = "NMAPS"; 0499 metaVal.sprintf("%lu", (long unsigned int)_nMaps); 0500 _metaData.insert(metaName, metaVal); 0501 0502 metaName = "CREATOR"; 0503 metaVal.sprintf("%s", _creator); 0504 _metaData.insert(metaName, metaVal); 0505 0506 metaName = "EXTNAME"; 0507 metaVal.sprintf("%s", _extname); 0508 _metaData.insert(metaName, metaVal); 0509 0510 for (size_t j = 0; j < _keys->nskeys; j++) { 0511 metaName.sprintf("%s", _keys->skeynames[j]); 0512 metaVal.sprintf("%s", _keys->skeyvals[j]); 0513 _metaData.insert(metaName, metaVal); 0514 } 0515 0516 for (size_t j = 0; j < _keys->nikeys; j++) { 0517 metaName.sprintf("%s", _keys->ikeynames[j]); 0518 metaVal.sprintf("%d", _keys->ikeyvals[j]); 0519 _metaData.insert(metaName, metaVal); 0520 } 0521 0522 for (size_t j = 0; j < _keys->nfkeys; j++) { 0523 metaName.sprintf("%s", _keys->fkeynames[j]); 0524 metaVal.sprintf("%e", _keys->fkeyvals[j]); 0525 _metaData.insert(metaName, metaVal); 0526 } 0527 0528 // populate the field list 0529 QString mapName; 0530 for (size_t i = 0; i < _nMaps; i++) { 0531 if (strlen(_names[i+poff]) == 0) { 0532 mapName.sprintf("%d - %s",(int)(i+1),"MAP"); 0533 } else { 0534 mapName.sprintf("%d - %s",(int)(i+1),_names[i+poff]); 0535 } 0536 if (strlen(_units[i+poff]) == 0) { 0537 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),"Unknown Units"); 0538 } else { 0539 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),_units[i+poff]); 0540 } 0541 _matrixList.append(mapName); 0542 } 0543 0544 if (_mapType == HEALPIX_FITS_CUT) { 0545 if (strlen(_names[_nMaps+1]) == 0) { 0546 mapName.sprintf("%s","HITS"); 0547 } else { 0548 mapName.sprintf("%s",_names[_nMaps+1]); 0549 } 0550 _matrixList.append(mapName); 0551 if (strlen(_names[_nMaps+2]) == 0) { 0552 mapName.sprintf("%s","ERRORS"); 0553 } else { 0554 mapName.sprintf("%s",_names[_nMaps+2]); 0555 } 0556 if (strlen(_units[_nMaps+2]) == 0) { 0557 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),"Unknown Units"); 0558 } else { 0559 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),_units[_nMaps+2]); 0560 } 0561 _matrixList.append(mapName); 0562 } 0563 0564 _fieldList.append("1 - Vector Field Head Theta"); 0565 _fieldList.append("2 - Vector Field Head Phi"); 0566 _fieldList.append("3 - Vector Field Tail Theta"); 0567 _fieldList.append("4 - Vector Field Tail Phi"); 0568 0569 return true; 0570 } 0571 0572 0573 Kst::Object::UpdateType HealpixSource::update() { 0574 // updates not supported yet 0575 // we should check to see if the FITS file has changed on disk 0576 return Kst::Object::NO_CHANGE; 0577 } 0578 0579 0580 bool HealpixSource::matrixDimensions( const QString& matrix, int* xDim, int* yDim) { 0581 Q_UNUSED(matrix) 0582 if (_valid) { 0583 (*xDim) = _config->_nX; 0584 (*yDim) = _config->_nY; 0585 return true; 0586 } 0587 return false; 0588 } 0589 0590 0591 int HealpixSource::readMatrix(Kst::MatrixData* data, const QString& field, int xStart, 0592 int yStart, int xNumSteps, 0593 int yNumSteps) { 0594 // If the file is _valid, then we already 0595 // have all the header information- no need to read it again. 0596 // We also know that the matrix index is not out-of-range. 0597 if (_valid && isValidMatrix(field)) { 0598 fitsfile *fp; 0599 int colnum; 0600 int fieldnum; 0601 int ret = 0; 0602 int ncol; 0603 int ttype; 0604 long nrows; 0605 long pcount; 0606 int tfields; 0607 char extname[HEALPIX_STRNL]; 0608 char comment[HEALPIX_STRNL]; 0609 float *datavec; 0610 int *pixvec; 0611 float *mapdata; 0612 float nullval = 0.0; 0613 int nnull = 0; 0614 int keynpix; 0615 int keyfirst; 0616 int ischunk; 0617 long nelem; 0618 0619 if (_matrixList.contains(field)) { 0620 fieldnum = _matrixList.findIndex(field); 0621 } else { 0622 fieldnum = field.toInt(); 0623 fieldnum--; 0624 } 0625 0626 // check range 0627 if ((xStart >= _config->_nX) || (yStart >= _config->_nY)) { 0628 return -1; 0629 } 0630 int nxread = xNumSteps; 0631 if (nxread < 0) { 0632 nxread = 1; 0633 } 0634 if (xStart + nxread > _config->_nX) { 0635 nxread = _config->_nX - xStart; 0636 } 0637 int nyread = yNumSteps; 0638 if (nyread < 0) { 0639 nyread = 1; 0640 } 0641 if (yStart + nyread > _config->_nY) { 0642 nyread = _config->_nY - yStart; 0643 } 0644 0645 if (_mapType == HEALPIX_FITS_CUT) { 0646 // cut-sphere files have extra pixel/hits/error columns 0647 colnum = fieldnum + 2; 0648 ncol = (int)_nMaps + 3; 0649 } else { 0650 colnum = fieldnum + 1; 0651 ncol = (int)_nMaps; 0652 } 0653 0654 // open file and move to second header unit 0655 if (fits_open_file(&fp, _healpixfile, READONLY, &ret)) { 0656 return -1; 0657 } 0658 0659 if (fits_movabs_hdu(fp, 2, &ttype, &ret)) { 0660 return -1; 0661 } 0662 0663 // read the number of rows 0664 if (fits_read_btblhdr(fp, ncol, &nrows, &tfields, NULL, NULL, NULL, extname, &pcount, &ret)) { 0665 ret = 0; 0666 fits_close_file(fp, &ret); 0667 return -1; 0668 } 0669 0670 mapdata = (float*)calloc(_mapNpix, sizeof(float)); 0671 //initialize data to HEALPIX_NULL 0672 for (size_t j = 0; j < _mapNpix; j++) { 0673 mapdata[j] = HEALPIX_NULL; 0674 } 0675 0676 if (_mapType == HEALPIX_FITS_CUT) { 0677 // For a cut-sphere file, we must read the entire 0678 // file and then re-map the data onto a full-sphere 0679 // vector. 0680 0681 datavec = (float*)calloc((size_t) nrows, sizeof(float)); 0682 pixvec = (int*)calloc((size_t) nrows, sizeof(int)); 0683 0684 if (fits_read_col(fp, TINT, 1, 1, 1, nrows, &nullval, pixvec, &nnull, &ret)) { 0685 free(pixvec); 0686 free(datavec); 0687 free(mapdata); 0688 ret = 0; 0689 fits_close_file(fp, &ret); 0690 return -1; 0691 } 0692 0693 if (fits_read_col(fp, TFLOAT, colnum, 1, 1, nrows, &nullval, datavec, &nnull, &ret)) { 0694 free(pixvec); 0695 free(datavec); 0696 free(mapdata); 0697 ret = 0; 0698 fits_close_file(fp, &ret); 0699 return -1; 0700 } 0701 0702 for (long j = 0; j < nrows; j++) { 0703 if ((pixvec[j] >= 0) && (pixvec[j] < (int)_mapNpix)) { 0704 mapdata[pixvec[j]] = datavec[j]; 0705 } 0706 } 0707 free(pixvec); 0708 free(datavec); 0709 } else { 0710 /* is this a chunk? */ 0711 if ((nrows != (long)(_mapNpix))&&(1024*nrows != (long)(_mapNpix))) { 0712 /*this must be a chunk file*/ 0713 char charFirstPix[] = "FIRSTPIX"; 0714 if (fits_read_key(fp, TLONG, charFirstPix, &keyfirst, comment, &ret)) { 0715 /*must at least have FIRSTPIX key*/ 0716 fits_close_file(fp, &ret); 0717 return 0; 0718 } else { 0719 char charNPix[] = "NPIX"; 0720 if (fits_read_key(fp, TLONG, charNPix, &keynpix, comment, &ret)) { 0721 ret = 0; 0722 /*might be using LASTPIX instead*/ 0723 char charLastPix[] = "LASTPIX"; 0724 if (fits_read_key(fp, TLONG, charLastPix, &keynpix, comment, &ret)) { 0725 fits_close_file(fp, &ret); 0726 return 0; 0727 } else { 0728 keynpix = keynpix - keyfirst + 1; 0729 ischunk = 1; 0730 } 0731 } else { 0732 ischunk = 1; 0733 } 0734 } 0735 } else { 0736 ischunk = 0; 0737 } 0738 if (ischunk) { 0739 datavec = (float*)calloc((size_t)keynpix, sizeof(float)); 0740 nelem = (long)keynpix; 0741 } else { 0742 datavec = (float*)calloc(_mapNpix, sizeof(float)); 0743 nelem = (long)(_mapNpix); 0744 } 0745 if (fits_read_col(fp, TFLOAT, colnum, 1, 1, nelem, &nullval, datavec, &nnull, &ret)) { 0746 free(datavec); 0747 free(mapdata); 0748 ret = 0; 0749 fits_close_file(fp, &ret); 0750 return -1; 0751 } 0752 if (ischunk) { 0753 for (long j = 0; j < nelem; j++) { 0754 mapdata[j+keyfirst] = datavec[j]; 0755 } 0756 } else { 0757 for (long j = 0; j < nelem; j++) { 0758 mapdata[j] = datavec[j]; 0759 } 0760 } 0761 free(datavec); 0762 } 0763 0764 fits_close_file(fp, &ret); 0765 0766 // set the matrix to NULL 0767 for (int i = 0; i < nxread*nyread; i++) { 0768 data->z[i] = NAN; 0769 } 0770 0771 double theta, phi; 0772 size_t ppix; 0773 0774 // compute autorange parameters if necessary 0775 if (_config->_autoTheta || _config->_autoPhi) { 0776 double mapMinTheta = HEALPIX_PI; 0777 double mapMaxTheta = 0.0; 0778 double mapMinPhi = 2.0*HEALPIX_PI; 0779 double mapMaxPhi = 0.0; 0780 0781 for (size_t i = 0; i < _mapNpix; i++) { 0782 if (!healpix_is_fnull(mapdata[i])) { 0783 if (_mapOrder == HEALPIX_RING) { 0784 healpix_pix2ang_ring(_mapNside, i, &theta, &phi); 0785 } else { 0786 healpix_pix2ang_nest(_mapNside, i, &theta, &phi); 0787 } 0788 if (theta < mapMinTheta) { 0789 mapMinTheta = theta; 0790 } 0791 if (theta > mapMaxTheta) { 0792 mapMaxTheta = theta; 0793 } 0794 if (phi < mapMinPhi) { 0795 mapMinPhi = phi; 0796 } 0797 if (phi > mapMaxPhi) { 0798 mapMaxPhi = phi; 0799 } 0800 } 0801 } 0802 if (mapMaxTheta < mapMinTheta) { // no valid data in map 0803 mapMaxTheta = HEALPIX_PI; 0804 mapMinTheta = 0.0; 0805 mapMaxPhi = 2.0*HEALPIX_PI; 0806 mapMinPhi = 0.0; 0807 } 0808 if (_config->_autoTheta) { 0809 _config->_thetaMin = mapMinTheta; 0810 _config->_thetaMax = mapMaxTheta; 0811 } 0812 if (_config->_autoPhi) { 0813 _config->_phiMin = mapMinPhi; 0814 _config->_phiMax = mapMaxPhi; 0815 } 0816 //qDebug() << "HEALPIX autorange is Theta=[" << mapMinTheta << "..." << mapMaxTheta << "] Phi=[" << mapMinPhi << "..." << mapMaxPhi << "]"; 0817 } 0818 //qDebug() << "HEALPIX using range Theta=[" << _thetaMin << "..." << _thetaMax << "] Phi=[" << _phiMin << "..." << _phiMax << "]"; 0819 0820 // copy sphere data to matrix. 0821 for (int i = xStart; i < nxread; i++) { 0822 for (int j = yStart; j < nyread; j++) { 0823 healpix_proj_rev_car(_config->_thetaMin, _config->_thetaMax, _config->_phiMin, _config->_phiMax, (double)_config->_nX, (double)_config->_nY, (double)i, (double)j, &theta, &phi); 0824 if ((!healpix_is_dnull(theta)) && (!healpix_is_dnull(phi))) { 0825 if (_mapOrder == HEALPIX_RING) { 0826 healpix_ang2pix_ring(_mapNside, theta, phi, &ppix); 0827 } else { 0828 healpix_ang2pix_nest(_mapNside, theta, phi, &ppix); 0829 } 0830 if (!healpix_is_fnull(mapdata[ppix])) { 0831 data->z[i*nyread+j] = (double)mapdata[ppix]; 0832 } 0833 } 0834 } 0835 } 0836 free(mapdata); 0837 0838 // FIXME 0839 // Eventually, we can just always use radians for the 0840 // matrix range, since actual display units will be 0841 // handled by the Kst2DRenderer. For now, set the matrix 0842 // range to the same units used in the config dialog. 0843 // Note that this behaviour is broken, since 2 maps 0844 // from different files could be put on the same plot 0845 // in different units. It's the best we can do for now. 0846 // 0847 //data->yMin = _thetaMax; 0848 //data->yStepSize = -(_thetaMax - _thetaMin)/(double)_nY; 0849 //data->xMin = _phiMin; 0850 //if (_phiMin > _phiMax) { 0851 // data->xStepSize = (_phiMax + (2.0*HEALPIX_PI - _phiMin)) / (double)_nX; 0852 //} else { 0853 // data->xStepSize = ((_phiMax - _phiMin) / (double)_nX; 0854 //} 0855 0856 double tMin = _config->_thetaMin; 0857 double tMax = _config->_thetaMax; 0858 double pMin = _config->_phiMin; 0859 double pMax = _config->_phiMax; 0860 _config->theta2External(_config->_thetaUnits, tMin); 0861 _config->theta2External(_config->_thetaUnits, tMax); 0862 _config->phi2External(_config->_phiUnits, pMin); 0863 _config->phi2External(_config->_phiUnits, pMax); 0864 //qDebug() << "HEALPIX exported range Theta=[" << tMin << "..." << tMax << "] Phi=[" << pMin << "..." << pMax << "]"; 0865 0866 switch (_config->_thetaUnits) { 0867 case HPUNIT_RAD: case HPUNIT_DEG: 0868 data->yMin = tMax; 0869 data->yStepSize = (tMin - tMax)/(double)_config->_nY; 0870 break; 0871 case HPUNIT_RADEC: case HPUNIT_LATLON: 0872 data->yMin = tMax; 0873 data->yStepSize = (tMin - tMax)/(double)_config->_nY; 0874 break; 0875 default: 0876 break; 0877 } 0878 0879 data->xMin = pMin; 0880 switch (_config->_phiUnits) { 0881 case HPUNIT_RAD: 0882 if (pMin > pMax) { 0883 data->xStepSize = (pMax + (2.0*HEALPIX_PI-pMin)) / (double)_config->_nX; 0884 } else { 0885 data->xStepSize = (pMax - pMin) / (double)_config->_nX; 0886 } 0887 break; 0888 case HPUNIT_DEG: case HPUNIT_RADEC: 0889 if (pMin > pMax) { 0890 data->xStepSize = (pMax + (360.0-pMin)) / (double)_config->_nX; 0891 } else { 0892 data->xStepSize = (pMax - pMin) / (double)_config->_nX; 0893 } 0894 break; 0895 case HPUNIT_LATLON: 0896 if (pMin > pMax) { 0897 data->xStepSize = ((180.0+pMax) + (180.0-pMin)) / (double)_config->_nX; 0898 } else { 0899 data->xStepSize = (pMax - pMin) / (double)_config->_nX; 0900 } 0901 break; 0902 default: 0903 break; 0904 } 0905 return nxread*nyread; 0906 } else { 0907 return -1; 0908 } 0909 } 0910 0911 0912 int HealpixSource::readField(double *v, const QString& field, int s, int n) { 0913 Q_UNUSED(s) 0914 if (_valid && isValidField(field)) { 0915 fitsfile *fp; 0916 int coltheta; 0917 int colphi; 0918 int ret = 0; 0919 int ncol; 0920 int ttype; 0921 long nrows; 0922 long pcount; 0923 int tfields; 0924 char extname[HEALPIX_STRNL]; 0925 char comment[HEALPIX_STRNL]; 0926 float *datavec; 0927 int *pixvec; 0928 int *hits; 0929 float *mapdata; 0930 float *comptheta; 0931 float *compphi; 0932 float nullval; 0933 int nnull; 0934 size_t vecNside; 0935 size_t temppix; 0936 int fieldnum; 0937 double theta, phi; 0938 long nearest[8]; 0939 int keynpix; 0940 int keyfirst; 0941 int ischunk; 0942 long nelem; 0943 0944 if (_fieldList.contains(field)) { 0945 fieldnum = _fieldList.findIndex(field); 0946 } else { 0947 fieldnum = field.toInt(); 0948 fieldnum--; 0949 } 0950 0951 // check range 0952 if (n <= 0) { 0953 return -1; 0954 } 0955 0956 vecNside = _mapNside; 0957 for (int i = 0; i < _config->_vecDegrade; i++) { 0958 vecNside = (size_t)(vecNside/2); 0959 } 0960 0961 if (_mapType == HEALPIX_FITS_CUT) { 0962 // cut-sphere files have extra pixel/hits/error columns 0963 coltheta = _config->_vecTheta + 2; 0964 colphi = _config->_vecPhi + 2; 0965 ncol = (int)_nMaps + 3; 0966 } else { 0967 coltheta = _config->_vecTheta + 1; 0968 colphi = _config->_vecPhi + 1; 0969 ncol = (int)_nMaps; 0970 } 0971 0972 // open file and move to second header unit 0973 if (fits_open_file(&fp, _healpixfile, READONLY, &ret)) { 0974 return -1; 0975 } 0976 0977 if (fits_movabs_hdu(fp, 2, &ttype, &ret)) { 0978 return -1; 0979 } 0980 0981 // read the number of rows 0982 if (fits_read_btblhdr(fp, ncol, &nrows, &tfields, NULL, NULL, NULL, extname, &pcount, &ret)) { 0983 ret = 0; 0984 fits_close_file(fp, &ret); 0985 return -1; 0986 } 0987 0988 mapdata = (float*)calloc(_mapNpix, sizeof(float)); 0989 hits = (int*)calloc(12*vecNside*vecNside, sizeof(int)); 0990 0991 //----------------------------------------- 0992 // Read in the first component and degrade 0993 //----------------------------------------- 0994 for (size_t j = 0; j < _mapNpix; j++) { 0995 mapdata[j] = HEALPIX_NULL; 0996 } 0997 if (_mapType == HEALPIX_FITS_CUT) { 0998 datavec = (float*)calloc((size_t) nrows, sizeof(float)); 0999 pixvec = (int*)calloc((size_t) nrows, sizeof(int)); 1000 if (fits_read_col(fp, TINT, 1, 1, 1, nrows, &nullval, pixvec, &nnull, &ret)) { 1001 free(pixvec); 1002 free(datavec); 1003 free(mapdata); 1004 ret = 0; 1005 fits_close_file(fp, &ret); 1006 return -1; 1007 } 1008 if (fits_read_col(fp, TFLOAT, coltheta, 1, 1, nrows, &nullval, datavec, &nnull, &ret)) { 1009 free(pixvec); 1010 free(datavec); 1011 free(mapdata); 1012 ret = 0; 1013 fits_close_file(fp, &ret); 1014 return -1; 1015 } 1016 for (long j = 0; j < nrows; j++) { 1017 if ((pixvec[j] >= 0) && (pixvec[j] < (int)_mapNpix)) { 1018 mapdata[pixvec[j]] = datavec[j]; 1019 } 1020 } 1021 free(pixvec); 1022 free(datavec); 1023 } else { 1024 /* is this a chunk? */ 1025 if ((nrows != (long)(_mapNpix))&&(1024*nrows != (long)(_mapNpix))) { 1026 /*this must be a chunk file*/ 1027 char charFirstPix[] = "FIRSTPIX"; 1028 if (fits_read_key(fp, TLONG, charFirstPix, &keyfirst, comment, &ret)) { 1029 /*must at least have FIRSTPIX key*/ 1030 fits_close_file(fp, &ret); 1031 return 0; 1032 } else { 1033 char charNPix[] = "NPIX"; 1034 if (fits_read_key(fp, TLONG, charNPix, &keynpix, comment, &ret)) { 1035 ret = 0; 1036 /*might be using LASTPIX instead*/ 1037 char charLastPix[] = "LASTPIX"; 1038 if (fits_read_key(fp, TLONG, charLastPix, &keynpix, comment, &ret)) { 1039 fits_close_file(fp, &ret); 1040 return 0; 1041 } else { 1042 keynpix = keynpix - keyfirst + 1; 1043 ischunk = 1; 1044 } 1045 } else { 1046 ischunk = 1; 1047 } 1048 } 1049 } else { 1050 ischunk = 0; 1051 } 1052 if (ischunk) { 1053 datavec = (float*)calloc((size_t)keynpix, sizeof(float)); 1054 nelem = (long)keynpix; 1055 } else { 1056 datavec = (float*)calloc(_mapNpix, sizeof(float)); 1057 nelem = (long)(_mapNpix); 1058 } 1059 if (fits_read_col(fp, TFLOAT, coltheta, 1, 1, nelem, &nullval, datavec, &nnull, &ret)) { 1060 free(datavec); 1061 free(mapdata); 1062 ret = 0; 1063 fits_close_file(fp, &ret); 1064 return -1; 1065 } 1066 if (ischunk) { 1067 for (long j = 0; j < nelem; j++) { 1068 mapdata[j+keyfirst] = datavec[j]; 1069 } 1070 } else { 1071 for (long j = 0; j < nelem; j++) { 1072 mapdata[j] = datavec[j]; 1073 } 1074 } 1075 free(datavec); 1076 } 1077 comptheta = (float*)calloc(12*vecNside*vecNside, sizeof(float)); 1078 for (size_t i = 0; i < 12*vecNside*vecNside; i++) { 1079 comptheta[i] = HEALPIX_NULL; 1080 hits[i] = 0; 1081 } 1082 for (size_t i = 0; i < _mapNpix; i++) { 1083 if (!healpix_is_fnull(mapdata[i])) { 1084 if (_mapOrder == HEALPIX_NEST) { 1085 healpix_degrade_nest(_mapNside, i, vecNside, &temppix); 1086 } else { 1087 healpix_degrade_ring(_mapNside, i, vecNside, &temppix); 1088 } 1089 if (!healpix_is_fnull(comptheta[temppix])) { 1090 comptheta[temppix] += mapdata[i]; 1091 } else { 1092 comptheta[temppix] = mapdata[i]; 1093 } 1094 hits[temppix] += 1; 1095 } 1096 } 1097 for (size_t i = 0; i < 12*vecNside*vecNside; i++) { 1098 if (!healpix_is_fnull(comptheta[i])) { 1099 comptheta[i] = comptheta[i] / (double)hits[i]; 1100 } 1101 } 1102 1103 //----------------------------------------- 1104 // Read in the second component and degrade 1105 //----------------------------------------- 1106 for (size_t j = 0; j < _mapNpix; j++) { 1107 mapdata[j] = HEALPIX_NULL; 1108 } 1109 if (_mapType == HEALPIX_FITS_CUT) { 1110 datavec = (float*)calloc((size_t) nrows, sizeof(float)); 1111 pixvec = (int*)calloc((size_t) nrows, sizeof(int)); 1112 if (fits_read_col(fp, TINT, 1, 1, 1, nrows, &nullval, pixvec, &nnull, &ret)) { 1113 free(pixvec); 1114 free(datavec); 1115 free(mapdata); 1116 ret = 0; 1117 fits_close_file(fp, &ret); 1118 return -1; 1119 } 1120 if (fits_read_col(fp, TFLOAT, colphi, 1, 1, nrows, &nullval, datavec, &nnull, &ret)) { 1121 free(pixvec); 1122 free(datavec); 1123 free(mapdata); 1124 ret = 0; 1125 fits_close_file(fp, &ret); 1126 return -1; 1127 } 1128 for (long j = 0; j < nrows; j++) { 1129 if ((pixvec[j] >= 0) && (pixvec[j] < (int)_mapNpix)) { 1130 mapdata[pixvec[j]] = datavec[j]; 1131 } 1132 } 1133 free(pixvec); 1134 free(datavec); 1135 } else { 1136 /* is this a chunk? */ 1137 if ((nrows != (long)(_mapNpix))&&(1024*nrows != (long)(_mapNpix))) { 1138 /*this must be a chunk file*/ 1139 char charFirstPix[] = "FIRSTPIX"; 1140 if (fits_read_key(fp, TLONG, charFirstPix, &keyfirst, comment, &ret)) { 1141 /*must at least have FIRSTPIX key*/ 1142 fits_close_file(fp, &ret); 1143 return 0; 1144 } else { 1145 char charNPix[] = "NPIX"; 1146 if (fits_read_key(fp, TLONG, charNPix, &keynpix, comment, &ret)) { 1147 ret = 0; 1148 /*might be using LASTPIX instead*/ 1149 char charLastPix[] = "LASTPIX"; 1150 if (fits_read_key(fp, TLONG, charLastPix, &keynpix, comment, &ret)) { 1151 fits_close_file(fp, &ret); 1152 return 0; 1153 } else { 1154 keynpix = keynpix - keyfirst + 1; 1155 ischunk = 1; 1156 } 1157 } else { 1158 ischunk = 1; 1159 } 1160 } 1161 } else { 1162 ischunk = 0; 1163 } 1164 if (ischunk) { 1165 datavec = (float*)calloc((size_t)keynpix, sizeof(float)); 1166 nelem = (long)keynpix; 1167 } else { 1168 datavec = (float*)calloc(_mapNpix, sizeof(float)); 1169 nelem = (long)(_mapNpix); 1170 } 1171 if (fits_read_col(fp, TFLOAT, colphi, 1, 1, nelem, &nullval, datavec, &nnull, &ret)) { 1172 free(datavec); 1173 free(mapdata); 1174 ret = 0; 1175 fits_close_file(fp, &ret); 1176 return -1; 1177 } 1178 if (ischunk) { 1179 for (long j = 0; j < nelem; j++) { 1180 mapdata[j+keyfirst] = datavec[j]; 1181 } 1182 } else { 1183 for (long j = 0; j < nelem; j++) { 1184 mapdata[j] = datavec[j]; 1185 } 1186 } 1187 free(datavec); 1188 } 1189 1190 compphi = (float*)calloc(12*vecNside*vecNside, sizeof(float)); 1191 for (size_t i = 0; i < 12*vecNside*vecNside; i++) { 1192 compphi[i] = HEALPIX_NULL; 1193 hits[i] = 0; 1194 } 1195 for (size_t i = 0; i < _mapNpix; i++) { 1196 if (!healpix_is_fnull(mapdata[i])) { 1197 if (_mapOrder == HEALPIX_NEST) { 1198 healpix_degrade_nest(_mapNside, i, vecNside, &temppix); 1199 } else { 1200 healpix_degrade_ring(_mapNside, i, vecNside, &temppix); 1201 } 1202 if (!healpix_is_fnull(compphi[temppix])) { 1203 compphi[temppix] += mapdata[i]; 1204 } else { 1205 compphi[temppix] = mapdata[i]; 1206 } 1207 hits[temppix] += 1; 1208 } 1209 } 1210 for (size_t i = 0; i < 12*vecNside*vecNside; i++) { 1211 if (!healpix_is_fnull(compphi[i])) { 1212 compphi[i] = compphi[i] / (double)hits[i]; 1213 } 1214 } 1215 1216 free(hits); 1217 free(mapdata); 1218 fits_close_file(fp, &ret); 1219 1220 //---------------------------------------------- 1221 // compute head and tail coordinates in radians 1222 //---------------------------------------------- 1223 1224 // autoscale magnitude if necessary 1225 double vecMag = 0.0; 1226 if (_config->_autoMag) { 1227 for (size_t i = 0; i < 12*vecNside*vecNside; i++) { 1228 if (sqrt((double)(comptheta[i]*comptheta[i] + compphi[i]*compphi[i])) > vecMag) { 1229 vecMag = sqrt((double)(comptheta[i]*comptheta[i] + compphi[i]*compphi[i])); 1230 } 1231 } 1232 } else { 1233 vecMag = _config->_maxMag; 1234 } 1235 1236 // find distance to 4 nearest neighbor pixels and 1237 // use the average to compute how "long" the max 1238 // valued vector should be for a given pixel. 1239 // This is *expensive*, but we only load vector 1240 // fields infrequently, so should be ok. 1241 1242 // only actually compute the component of the 1243 // vectorfield that is requested. 1244 1245 double maxang; 1246 double thetapart; 1247 double phipart; 1248 double headtheta; 1249 double tailtheta; 1250 double headphi; 1251 double tailphi; 1252 double pmag; 1253 double alpha; 1254 // only compute as many elements as requested 1255 for (size_t i = 0; i < (size_t)n; i++) { 1256 if (!healpix_is_fnull(comptheta[i]) && !healpix_is_fnull(compphi[i])) { 1257 if (_config->_vecQU) { //theta is really Q, phi really U 1258 pmag = sqrt((double)(comptheta[i]*comptheta[i] + compphi[i]*compphi[i])); 1259 alpha = 0.5 * atan((double)compphi[i] / (double)comptheta[i]); 1260 thetapart = pmag * cos(alpha); 1261 phipart = pmag * sin(alpha); 1262 } else { 1263 thetapart = (double)comptheta[i]; 1264 phipart = (double)compphi[i]; 1265 } 1266 if (_mapOrder == HEALPIX_RING) { 1267 healpix_pix2ang_ring(vecNside, i, &theta, &phi); 1268 } else { 1269 healpix_pix2ang_nest(vecNside, i, &theta, &phi); 1270 } 1271 //find max angle for this pixel 1272 healpix_neighbors(vecNside, _mapOrder, i, nearest); 1273 maxang = healpix_loc_dist(vecNside, _mapOrder, i, nearest[0]); 1274 maxang += healpix_loc_dist(vecNside, _mapOrder, i, nearest[1]); 1275 maxang += healpix_loc_dist(vecNside, _mapOrder, i, nearest[2]); 1276 maxang += healpix_loc_dist(vecNside, _mapOrder, i, nearest[3]); 1277 maxang /= 4.0; 1278 thetapart *= maxang / vecMag; 1279 phipart *= maxang / vecMag; 1280 //find coordinates of head and tail 1281 headtheta = theta + 0.5 * thetapart; 1282 tailtheta = theta - 0.5 * thetapart; 1283 headphi = phi + 0.5 * phipart; 1284 tailphi = phi - 0.5 * phipart; 1285 while (headtheta > HEALPIX_PI) { 1286 headtheta -= HEALPIX_PI; 1287 } 1288 while (headtheta < 0.0) { 1289 headtheta += HEALPIX_PI; 1290 } 1291 while (tailtheta > HEALPIX_PI) { 1292 tailtheta -= HEALPIX_PI; 1293 } 1294 while (tailtheta < 0.0) { 1295 tailtheta += HEALPIX_PI; 1296 } 1297 while (headphi > 2.0 * HEALPIX_PI) { 1298 headphi -= 2.0 * HEALPIX_PI; 1299 } 1300 while (headphi < 0.0) { 1301 headphi += 2.0 * HEALPIX_PI; 1302 } 1303 while (tailphi > 2.0 * HEALPIX_PI) { 1304 tailphi -= 2.0 * HEALPIX_PI; 1305 } 1306 while (tailphi < 0.0) { 1307 tailphi += 2.0 * HEALPIX_PI; 1308 } 1309 switch (fieldnum) { 1310 case 0: //head theta 1311 v[i] = headtheta; 1312 break; 1313 case 1: //head phi 1314 v[i] = headphi; 1315 break; 1316 case 2: //tail theta 1317 v[i] = tailtheta; 1318 break; 1319 case 3: //tail phi 1320 v[i] = tailphi; 1321 break; 1322 default: 1323 break; 1324 } 1325 } 1326 } 1327 return n; 1328 } else { 1329 return -1; 1330 } 1331 } 1332 1333 1334 bool HealpixSource::isValidField(const QString& field) const { 1335 // need to allow for referencing fields by number, so 1336 // that command line options work. 1337 if (_fieldList.contains(field)) { 1338 return true; 1339 } else { 1340 bool ok = false; 1341 int num = field.toInt(&ok); 1342 if (ok && num <= (int)_fieldList.count() && num != 0) { 1343 return true; 1344 } else { 1345 return false; 1346 } 1347 } 1348 1349 return _fieldList.contains(field); 1350 } 1351 1352 1353 bool HealpixSource::isValidMatrix(const QString& field) const { 1354 // need to allow for referencing fields by number, so 1355 // that command line options work. 1356 if (_matrixList.contains(field)) { 1357 return true; 1358 } else { 1359 bool ok = false; 1360 int num = field.toInt(&ok); 1361 if (ok && num <= (int)_matrixList.count() && num != 0) { 1362 return true; 1363 } else { 1364 return false; 1365 } 1366 } 1367 } 1368 1369 1370 int HealpixSource::samplesPerFrame(const QString &field) { 1371 Q_UNUSED(field) 1372 return 1; 1373 } 1374 1375 1376 int HealpixSource::frameCount(const QString& field) const { 1377 Q_UNUSED(field) 1378 if (_valid) { 1379 // return the number of pixels in the sky for 1380 // the degraded vectorfield 1381 size_t vecNside = _mapNside; 1382 for (int i = 0; i < _config->_vecDegrade; i++) { 1383 vecNside = (size_t)(vecNside/2); 1384 } 1385 return (int)(12*vecNside*vecNside); 1386 } else { 1387 return 0; 1388 } 1389 } 1390 1391 1392 bool HealpixSource::isEmpty() const { 1393 return !_valid; 1394 } 1395 1396 1397 QString HealpixSource::fileType() const { 1398 return healpixTypeString; 1399 } 1400 1401 1402 void HealpixSource::save(QXmlStreamWriter &streamWriter) { 1403 Kst::DataSource::save(streamWriter); 1404 } 1405 1406 1407 void HealpixSource::parseProperties(QXmlStreamAttributes &properties) { 1408 _config->parseProperties(properties); 1409 } 1410 1411 1412 int HealpixSource::readScalar(double &S, const QString& scalar) { 1413 if (scalar == "FRAMES") { 1414 S = 1; 1415 return 1; 1416 } 1417 return 0; 1418 } 1419 1420 1421 int HealpixSource::readString(QString &S, const QString& string) { 1422 if (string == "FILE") { 1423 S = _filename; 1424 return 1; 1425 } else if (_metaData.contains(string)) { 1426 S = _metaData[string]; 1427 return 1; 1428 } 1429 return 0; 1430 } 1431 1432 1433 class ConfigWidgetHealpixInternal : public QWidget, public Ui_HealpixConfig { 1434 public: 1435 ConfigWidgetHealpixInternal(QWidget *parent) : QWidget(parent), Ui_HealpixConfig() { setupUi(this); } 1436 }; 1437 1438 1439 class ConfigWidgetHealpix : public Kst::DataSourceConfigWidget { 1440 public: 1441 ConfigWidgetHealpix() : Kst::DataSourceConfigWidget() { 1442 QGridLayout *layout = new QGridLayout(this); 1443 _hc = new ConfigWidgetHealpixInternal(this); 1444 layout->addWidget(_hc, 0, 0); 1445 layout->activate(); 1446 } 1447 1448 ~ConfigWidgetHealpix() {} 1449 1450 void setConfig(QSettings *cfg) { 1451 Kst::DataSourceConfigWidget::setConfig(cfg); 1452 } 1453 1454 void load() { 1455 QStringList unitList; 1456 //FIXME add back in when we have a renderer 1457 //unitList.append("(Radians)"); 1458 //unitList.append("(Degrees)"); 1459 unitList.append("(RA/DEC)"); 1460 //unitList.append("(Lat/Long)"); 1461 _cfg->beginGroup("Healpix General"); 1462 _hc->matThetaUnits->clear(); 1463 _hc->matPhiUnits->clear(); 1464 _hc->vecTheta->clear(); 1465 _hc->vecPhi->clear(); 1466 _hc->matThetaUnits->insertStringList(unitList); 1467 _hc->matPhiUnits->insertStringList(unitList); 1468 //FIXME change to HPUNIT_RAD 1469 _hc->matThetaUnits->setCurrentItem(0); 1470 _hc->matPhiUnits->setCurrentItem(0); 1471 _hc->matDimX->setValue(_cfg->value("Matrix X Dimension", DEFAULT_XDIM).toInt()); 1472 _hc->matDimY->setValue(_cfg->value("Matrix Y Dimension", DEFAULT_YDIM).toInt()); 1473 _hc->matThetaAuto->setChecked(_cfg->value("Theta Autoscale", true).toBool()); 1474 //FIXME Only one combobox item for now... 1475 //_hc->matThetaUnits->setCurrentItem(_cfg->readEntry("Theta Units", HPUNIT_RAD)); 1476 _hc->matThetaUnits->setCurrentItem(0); 1477 _hc->matThetaMin->setText(_cfg->value("Theta Min").toString()); 1478 _hc->matThetaMax->setText(_cfg->value("Theta Max").toString()); 1479 _hc->matPhiAuto->setChecked(_cfg->value("Phi Autoscale", true).toBool()); 1480 //FIXME Only one combobox item for now... 1481 //_hc->matPhiUnits->setCurrentItem(_cfg->readEntry("Phi Units", HPUNIT_RAD)); 1482 _hc->matPhiUnits->setCurrentItem(0); 1483 _hc->matPhiMin->setText(_cfg->value("Phi Min").toString()); 1484 _hc->matPhiMax->setText(_cfg->value("Phi Max").toString()); 1485 _hc->vecTheta->setCurrentItem(_cfg->value("Vector Theta", 0).toInt()); 1486 _hc->vecPhi->setCurrentItem(_cfg->value("Vector Phi", 0).toInt()); 1487 _hc->vecDegrade->setValue(_cfg->value("Vector Degrade Factor", 1).toInt()); 1488 _hc->vecMagAuto->setChecked(_cfg->value("Vector Magnitude Autoscale", true).toBool()); 1489 _hc->vecMag->setText(_cfg->value("Vector Max Magnitude").toString()); 1490 _hc->vecQU->setChecked(_cfg->value("Vector is QU", false).toBool()); 1491 1492 bool hasInstance = (_instance != 0L); 1493 1494 if (hasInstance) { 1495 _hc->vecTheta->insertStringList(_instance->matrixList()); 1496 _hc->vecPhi->insertStringList(_instance->matrixList()); 1497 Kst::SharedPtr<HealpixSource> src = Kst::kst_cast<HealpixSource>(_instance); 1498 assert(src); 1499 _cfg->endGroup(); 1500 _cfg->beginGroup(src->fileName()); 1501 _hc->matDimX->setValue(_cfg->value("Matrix X Dimension", DEFAULT_XDIM).toInt()); 1502 _hc->matDimY->setValue(_cfg->value("Matrix Y Dimension", DEFAULT_YDIM).toInt()); 1503 _hc->matThetaAuto->setChecked(_cfg->value("Theta Autoscale", true).toBool()); 1504 //FIXME Only one combobox item for now... 1505 //_hc->matThetaUnits->setCurrentItem(_cfg->readEntry("Theta Units", HPUNIT_RAD)); 1506 _hc->matThetaUnits->setCurrentItem(0); 1507 _hc->matThetaMin->setText(_cfg->value("Theta Min").toString()); 1508 _hc->matThetaMax->setText(_cfg->value("Theta Max").toString()); 1509 _hc->matPhiAuto->setChecked(_cfg->value("Phi Autoscale", true).toBool()); 1510 //FIXME Only one combobox item for now... 1511 //_hc->matPhiUnits->setCurrentItem(_cfg->readEntry("Phi Units", HPUNIT_RAD)); 1512 _hc->matPhiUnits->setCurrentItem(0); 1513 _hc->matPhiMin->setText(_cfg->value("Phi Min").toString()); 1514 _hc->matPhiMax->setText(_cfg->value("Phi Max").toString()); 1515 _hc->vecTheta->setCurrentItem(_cfg->value("Vector Theta", 0).toInt()); 1516 _hc->vecPhi->setCurrentItem(_cfg->value("Vector Phi", 0).toInt()); 1517 _hc->vecDegrade->setValue(_cfg->value("Vector Degrade Factor", 1).toInt()); 1518 _hc->vecMagAuto->setChecked(_cfg->value("Vector Magnitude Autoscale", true).toBool()); 1519 _hc->vecMag->setText(_cfg->value("Vector Max Magnitude").toString()); 1520 _hc->vecQU->setChecked(_cfg->value("Vector is QU", false).toBool()); 1521 _cfg->endGroup(); 1522 } 1523 } 1524 1525 void save() { 1526 assert(_cfg); 1527 _cfg->beginGroup("Healpix General"); 1528 // If we have an instance, save settings for that instance only 1529 Kst::SharedPtr<HealpixSource> src = Kst::kst_cast<HealpixSource>(_instance); 1530 if (src) { 1531 _cfg->endGroup(); 1532 _cfg->beginGroup(src->fileName()); 1533 } 1534 _cfg->writeEntry("Matrix X Dimension", _hc->matDimX->value()); 1535 _cfg->writeEntry("Matrix Y Dimension", _hc->matDimY->value()); 1536 _cfg->writeEntry("Theta Autoscale", _hc->matThetaAuto->isChecked()); 1537 //FIXME override for now 1538 //_cfg->writeEntry("Theta Units", _hc->matThetaUnits->currentItem()); 1539 _cfg->writeEntry("Theta Units", HPUNIT_RADEC); 1540 _cfg->writeEntry("Theta Min", _hc->matThetaMin->text()); 1541 _cfg->writeEntry("Theta Max", _hc->matThetaMax->text()); 1542 _cfg->writeEntry("Phi Autoscale", _hc->matPhiAuto->isChecked()); 1543 //FIXME override for now 1544 //_cfg->writeEntry("Phi Units", _hc->matPhiUnits->currentItem()); 1545 _cfg->writeEntry("Phi Units", HPUNIT_RADEC); 1546 _cfg->writeEntry("Phi Min", _hc->matPhiMin->text()); 1547 _cfg->writeEntry("Phi Max", _hc->matPhiMax->text()); 1548 _cfg->writeEntry("Vector Theta", _hc->vecTheta->currentItem()); 1549 _cfg->writeEntry("Vector Phi", _hc->vecPhi->currentItem()); 1550 _cfg->writeEntry("Vector Degrade Factor", _hc->vecDegrade->value()); 1551 _cfg->writeEntry("Vector Magnitude Autoscale", _hc->vecMagAuto->isChecked()); 1552 _cfg->writeEntry("Vector Max Magnitude", _hc->vecMag->text()); 1553 _cfg->writeEntry("Vector is QU", _hc->vecQU->isChecked()); 1554 _cfg->endGroup(); 1555 1556 // Update the instance from our new settings 1557 if (src && src->reusable()) { 1558 src->_config->read(_cfg, src->fileName()); 1559 src->reset(); 1560 } 1561 } 1562 1563 ConfigWidgetHealpixInternal *_hc; 1564 }; 1565 1566 1567 QString HealpixPlugin::pluginName() const { return "HEALPIX Source Reader"; } 1568 QString HealpixPlugin::pluginDescription() const { return "HEALPIX Source Reader"; } 1569 1570 1571 Kst::DataSource *HealpixPlugin::create(Kst::ObjectStore *store, 1572 QSettings *cfg, 1573 const QString &filename, 1574 const QString &type, 1575 const QDomElement &element) const { 1576 1577 return new HealpixSource(store, cfg, filename, type, element); 1578 } 1579 1580 1581 1582 QStringList HealpixPlugin::matrixList(QSettings *cfg, 1583 const QString& filename, 1584 const QString& type, 1585 QString *typeSuggestion, 1586 bool *complete) const { 1587 Q_UNUSED(type) 1588 QStringList matrixList; 1589 1590 if (complete) { 1591 *complete = true; 1592 } 1593 1594 if (typeSuggestion) { 1595 *typeSuggestion = healpixTypeString; 1596 } 1597 if ( understands(cfg, filename) ) { 1598 size_t poff; 1599 1600 int mapType; 1601 int mapOrder; 1602 int mapCoord; 1603 size_t mapNside; 1604 size_t nMaps; 1605 char healpixfile[HEALPIX_STRNL]; 1606 healpix_keys *keys; 1607 char creator[HEALPIX_STRNL]; 1608 char extname[HEALPIX_STRNL]; 1609 char **names; 1610 char **units; 1611 1612 strncpy(healpixfile, filename.toLatin1().data(), HEALPIX_STRNL); 1613 1614 names = healpix_strarr_alloc(HEALPIX_FITS_MAXCOL); 1615 units = healpix_strarr_alloc(HEALPIX_FITS_MAXCOL); 1616 keys = healpix_keys_alloc(); 1617 1618 if (healpix_fits_map_info(healpixfile, &mapNside, &mapOrder, &mapCoord, &mapType, &nMaps, creator, extname, names, units, keys)) { 1619 if (mapType == HEALPIX_FITS_CUT) { 1620 poff = 1; 1621 } else { 1622 poff = 0; 1623 } 1624 1625 // populate the field list 1626 QString mapName; 1627 for (size_t i = 0; i < nMaps; i++) { 1628 if (strlen(names[i+poff]) == 0) { 1629 mapName.sprintf("%d - %s",(int)(i+1),"MAP"); 1630 } else { 1631 mapName.sprintf("%d - %s",(int)(i+1),names[i+poff]); 1632 } 1633 if (strlen(units[i+poff]) == 0) { 1634 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),"Unknown Units"); 1635 } else { 1636 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),units[i+poff]); 1637 } 1638 matrixList.append(mapName); 1639 } 1640 1641 if (mapType == HEALPIX_FITS_CUT) { 1642 if (strlen(names[nMaps+1]) == 0) { 1643 mapName.sprintf("%s","HITS"); 1644 } else { 1645 mapName.sprintf("%s",names[nMaps+1]); 1646 } 1647 matrixList.append(mapName); 1648 if (strlen(names[nMaps+2]) == 0) { 1649 mapName.sprintf("%s","ERRORS"); 1650 } else { 1651 mapName.sprintf("%s",names[nMaps+2]); 1652 } 1653 if (strlen(units[nMaps+2]) == 0) { 1654 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),"Unknown Units"); 1655 } else { 1656 mapName.sprintf("%s (%s)",mapName.toLatin1().data(),units[nMaps+2]); 1657 } 1658 matrixList.append(mapName); 1659 } 1660 } 1661 1662 healpix_keys_free(keys); 1663 healpix_strarr_free(names, HEALPIX_FITS_MAXCOL); 1664 healpix_strarr_free(units, HEALPIX_FITS_MAXCOL); 1665 } 1666 1667 return matrixList; 1668 1669 } 1670 1671 1672 QStringList HealpixPlugin::scalarList(QSettings *cfg, 1673 const QString& filename, 1674 const QString& type, 1675 QString *typeSuggestion, 1676 bool *complete) const { 1677 1678 QStringList scalarList; 1679 1680 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 1681 if (complete) { 1682 *complete = false; 1683 } 1684 return QStringList(); 1685 } 1686 1687 if (typeSuggestion) { 1688 *typeSuggestion = healpixTypeString; 1689 } 1690 1691 scalarList.append("FRAMES"); 1692 return scalarList; 1693 1694 } 1695 1696 1697 QStringList HealpixPlugin::stringList(QSettings *cfg, 1698 const QString& filename, 1699 const QString& type, 1700 QString *typeSuggestion, 1701 bool *complete) const { 1702 1703 QStringList stringList; 1704 1705 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 1706 if (complete) { 1707 *complete = false; 1708 } 1709 return QStringList(); 1710 } 1711 1712 if (typeSuggestion) { 1713 *typeSuggestion = healpixTypeString; 1714 } 1715 1716 stringList.append("FILENAME"); 1717 1718 int mapType; 1719 int mapOrder; 1720 int mapCoord; 1721 size_t mapNside; 1722 size_t nMaps; 1723 char healpixfile[HEALPIX_STRNL]; 1724 healpix_keys *keys; 1725 char creator[HEALPIX_STRNL]; 1726 char extname[HEALPIX_STRNL]; 1727 char **names; 1728 char **units; 1729 1730 strncpy(healpixfile, filename.toLatin1().data(), HEALPIX_STRNL); 1731 1732 names = healpix_strarr_alloc(HEALPIX_FITS_MAXCOL); 1733 units = healpix_strarr_alloc(HEALPIX_FITS_MAXCOL); 1734 keys = healpix_keys_alloc(); 1735 1736 if (healpix_fits_map_info(healpixfile, &mapNside, &mapOrder, &mapCoord, &mapType, &nMaps, creator, extname, names, units, keys)) { 1737 // populate the metadata 1738 QString metaVal; 1739 QString metaName; 1740 1741 metaName = "NSIDE"; 1742 metaVal.sprintf("%lu", (long unsigned int)mapNside); 1743 stringList.append(metaName); 1744 1745 metaName = "NPIX"; 1746 size_t mapNpix = 12 * mapNside * mapNside; 1747 metaVal.sprintf("%lu", (long unsigned int)mapNpix); 1748 stringList.append(metaName); 1749 1750 metaName = "ORDER"; 1751 metaVal.sprintf("%d", mapOrder); 1752 stringList.append(metaName); 1753 1754 metaName = "COORD"; 1755 metaVal.sprintf("%d", mapCoord); 1756 stringList.append(metaName); 1757 1758 metaName = "TYPE"; 1759 metaVal.sprintf("%d", mapType); 1760 stringList.append(metaName); 1761 1762 metaName = "NMAPS"; 1763 metaVal.sprintf("%lu", (long unsigned int)nMaps); 1764 stringList.append(metaName); 1765 1766 metaName = "CREATOR"; 1767 metaVal.sprintf("%s", creator); 1768 stringList.append(metaName); 1769 1770 metaName = "EXTNAME"; 1771 metaVal.sprintf("%s", extname); 1772 stringList.append(metaName); 1773 1774 for (size_t j = 0; j < keys->nskeys; j++) { 1775 metaName.sprintf("%s", keys->skeynames[j]); 1776 metaVal.sprintf("%s", keys->skeyvals[j]); 1777 stringList.append(metaName); 1778 } 1779 1780 for (size_t j = 0; j < keys->nikeys; j++) { 1781 metaName.sprintf("%s", keys->ikeynames[j]); 1782 metaVal.sprintf("%d", keys->ikeyvals[j]); 1783 stringList.append(metaName); 1784 } 1785 1786 for (size_t j = 0; j < keys->nfkeys; j++) { 1787 metaName.sprintf("%s", keys->fkeynames[j]); 1788 metaVal.sprintf("%e", keys->fkeyvals[j]); 1789 stringList.append(metaName); 1790 } 1791 } 1792 1793 healpix_keys_free(keys); 1794 healpix_strarr_free(names, HEALPIX_FITS_MAXCOL); 1795 healpix_strarr_free(units, HEALPIX_FITS_MAXCOL); 1796 1797 return stringList; 1798 1799 } 1800 1801 QStringList HealpixPlugin::fieldList(QSettings *cfg, 1802 const QString& filename, 1803 const QString& type, 1804 QString *typeSuggestion, 1805 bool *complete) const { 1806 Q_UNUSED(type) 1807 QStringList fieldList; 1808 1809 if (complete) { 1810 *complete = true; 1811 } 1812 1813 if (typeSuggestion) { 1814 *typeSuggestion = healpixTypeString; 1815 } 1816 if ( understands(cfg, filename) ) { 1817 fieldList.append("1 - Vector Field Head Theta"); 1818 fieldList.append("2 - Vector Field Head Phi"); 1819 fieldList.append("3 - Vector Field Tail Theta"); 1820 fieldList.append("4 - Vector Field Tail Phi"); 1821 } 1822 return fieldList; 1823 } 1824 1825 1826 int HealpixPlugin::understands(QSettings *cfg, const QString& filename) const { 1827 Q_UNUSED(cfg) 1828 1829 int ret; 1830 char thealpixfile[HEALPIX_STRNL]; 1831 int tOrder; 1832 int tCoord; 1833 int tType; 1834 size_t tNside; 1835 size_t tMaps; 1836 1837 strncpy(thealpixfile, filename.toLatin1().data(), HEALPIX_STRNL); 1838 ret = healpix_fits_map_test(thealpixfile, &tNside, &tOrder, &tCoord, &tType, &tMaps); 1839 1840 if (ret) { 1841 // MUST return 100, since LFIIO datasource returns 99 1842 // for *all* valid FITS files 1843 return 100; 1844 } else { 1845 return 0; 1846 } 1847 } 1848 1849 1850 bool HealpixPlugin::supportsTime(QSettings *cfg, const QString& filename) const { 1851 //FIXME 1852 Q_UNUSED(cfg) 1853 Q_UNUSED(filename) 1854 return true; 1855 } 1856 1857 1858 QStringList HealpixPlugin::provides() const { 1859 QStringList rc; 1860 rc += "HEALPIX Source"; 1861 return rc; 1862 } 1863 1864 1865 Kst::DataSourceConfigWidget *HealpixPlugin::configWidget(QSettings *cfg, const QString& filename) const { 1866 Q_UNUSED(filename) 1867 ConfigWidgetHealpix *config = new ConfigWidgetHealpix; 1868 config->setConfig(cfg); 1869 config->load(); 1870 return config; 1871 } 1872 1873 Q_EXPORT_PLUGIN2(kstdata_qimagesource, HealpixPlugin) 1874 1875 1876 // vim: ts=2 sw=2 et