source: trunk/src/fitsHeader.cc @ 1441

Last change on this file since 1441 was 1382, checked in by MatthewWhiting, 10 years ago

While in the mood for cleaning up allocation of memory, I've changed the way FitsHeader::getWCS() works. That function now simply returns the wcs pointer, while the old version of it has been renamed getWCScopy(), as it actually makes a copy of the WCS struct and returns a pointer to it.

File size: 12.1 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// fitsHeader.cc: Information about the FITS file's header.
3// -----------------------------------------------------------------------
4// Copyright (C) 2006, Matthew Whiting, ATNF
5//
6// This program is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 2 of the License, or (at your
9// option) any later version.
10//
11// Duchamp is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14// for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Duchamp; if not, write to the Free Software Foundation,
18// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19//
20// Correspondence concerning Duchamp may be directed to:
21//    Internet email: Matthew.Whiting [at] atnf.csiro.au
22//    Postal address: Dr. Matthew Whiting
23//                    Australia Telescope National Facility, CSIRO
24//                    PO Box 76
25//                    Epping NSW 1710
26//                    AUSTRALIA
27// -----------------------------------------------------------------------
[272]28#include <iostream>
29#include <sstream>
30#include <string>
[541]31#include <stdlib.h>
[394]32#include <wcslib/wcs.h>
33#include <wcslib/wcsunits.h>
[393]34#include <duchamp/duchamp.hh>
35#include <duchamp/param.hh>
36#include <duchamp/fitsHeader.hh>
37#include <duchamp/Utils/utils.hh>
[272]38
[378]39namespace duchamp
[272]40{
41
[378]42  FitsHeader::FitsHeader()
43  {
[971]44    this->fptr = 0;
[378]45    this->wcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
46    this->wcs->flag=-1;
47    wcsini(true, 3, this->wcs);
48    this->wcsIsGood = false;
49    this->nwcs = 0;
[570]50    this->flag2D=false;
51    this->spectralUnits="";
52    this->spectralDescription=duchamp::duchampSpectralDescription[FREQUENCY];
[1210]53    this->originalFluxUnits="";
54    this->fluxUnits="";
55    this->intFluxUnits="";
[378]56    this->scale=1.;
57    this->offset=0.;
58    this->power=1.;
[788]59    this->itsBeam.empty();
[378]60  }
[272]61
[378]62  FitsHeader::~FitsHeader()
63  {
[528]64    /// @details Uses the WCSLIB function wcsvfree to clear the wcsprm struct.
[378]65    wcsvfree(&nwcs,&wcs);
66  }
[272]67
[378]68  FitsHeader::FitsHeader(const FitsHeader& h)
69  {
70    operator=(h);
71  }
[272]72
[378]73  FitsHeader& FitsHeader::operator= (const FitsHeader& h)
74  {
75    if(this == &h) return *this;
[971]76    this->fptr = h.fptr;
[378]77    this->wcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
78    this->wcs->flag     = -1;
79    wcsini(true, h.wcs->naxis, this->wcs);
80    wcscopy(true, h.wcs, this->wcs);
81    wcsset(this->wcs);
82    this->nwcs          = h.nwcs;
83    this->wcsIsGood     = h.wcsIsGood;
[570]84    this->flag2D        = h.flag2D;
[378]85    this->spectralUnits = h.spectralUnits;
[947]86    this->spectralType  = h.spectralType;
[570]87    this->spectralDescription = h.spectralDescription;
[757]88    this->originalFluxUnits = h.originalFluxUnits;
[378]89    this->fluxUnits     = h.fluxUnits;
90    this->intFluxUnits  = h.intFluxUnits;
[788]91    this->itsBeam       = h.itsBeam;
[378]92    this->blankKeyword  = h.blankKeyword;
93    this->bzeroKeyword  = h.bzeroKeyword;
94    this->bscaleKeyword = h.bscaleKeyword;
95    this->scale         = h.scale;
96    this->offset        = h.offset;
97    this->power         = h.power;
98    return *this;
99  }
[272]100
[971]101  int FitsHeader::openFITS(std::string name)
102  {
103    int status = 0;
104    if( fits_open_file(&this->fptr,name.c_str(),READONLY,&status) ){
105      fits_report_error(stderr, status);
106      // if(((status==URL_PARSE_ERROR)||(status==BAD_NAXIS))
107      //         &&(this->pars().getFlagSubsection()))
108      //        DUCHAMPERROR("Cube Reader", "It may be that the subsection you've entered is invalid. Either it has the wrong number of axes, or one axis has too large a range.");
109    }
110    return status;
111  }
112
113  int FitsHeader::closeFITS()
114  {
115    int status=0;
116    fits_close_file(this->fptr, &status);
117    if (status){
118      DUCHAMPWARN("Cube Reader","Error closing file: ");
119      fits_report_error(stderr, status);
120    }
121    return status;
122
123  }
124
[378]125  void FitsHeader::setWCS(struct wcsprm *w)
126  {
[528]127    ///  A function that assigns the wcs parameters, and runs
128    ///   wcsset to set it up correctly.
129    ///  Performs a check to see if the WCS is good (by looking at
130    ///   the lng and lat wcsprm parameters), and sets the wcsIsGood
131    ///   flag accordingly.
132    /// \param w A WCSLIB wcsprm struct with the correct parameters.
133
[378]134    wcscopy(true, w, this->wcs);
135    wcsset(this->wcs);
136    if( (w->lng!=-1) && (w->lat!=-1) ) this->wcsIsGood = true;
137  }
[272]138
[1382]139  struct wcsprm *FitsHeader::getWCScopy()
[378]140  {
[528]141    ///  A function that returns a properly initilized wcsprm object
142    ///  corresponding to the WCS.
143
[378]144    struct wcsprm *wNew = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
145    wNew->flag=-1;
146    wcsini(true, this->wcs->naxis, wNew);
147    wcscopy(true, this->wcs, wNew);
148    wcsset(wNew);
149    return wNew;
150  }
[272]151
[1296]152  int FitsHeader::wcsToPix(double xWorld, double yWorld, double zWorld, double &xPix, double &yPix, double &zPix)
153  {
154      double world[3],pix[3];
155      world[0]=xWorld;
156      world[1]=yWorld;
157      world[2]=zWorld;
158      int returnval = wcsToPixSingle(this->wcs, world, pix);
159      if(returnval==0){
160          xPix=pix[0];
161          yPix=pix[1];
162          zPix=pix[2];
163      }
164      else {
165          xPix=-1.;
166          yPix=-1.;
167          zPix=-1.;
168      }
169      return returnval;
170  }
[378]171  int FitsHeader::wcsToPix(const double *world, double *pix)
172  {     
173    return wcsToPixSingle(this->wcs, world, pix); 
[419]174  }
[378]175  int FitsHeader::wcsToPix(const double *world, double *pix, const int npts)
176  {
177    return wcsToPixMulti(this->wcs, world, pix, npts); 
[419]178  }
[1296]179  int FitsHeader::pixToWCS(double xPix, double yPix, double zPix, double &xWorld, double &yWorld, double &zWorld)
180  {
181      double world[3],pix[3];
182      pix[0]=xPix;
183      pix[1]=yPix;
184      pix[2]=zPix;
185      int returnval = pixToWCSSingle(this->wcs, pix, world);
186      if(returnval==0){
187          xWorld=world[0];
188          yWorld=world[1];
189          zWorld=world[2];
190      }
191      else {
192          xWorld=-1.;
193          yWorld=-1.;
194          zWorld=-1.;
195      }
196      return returnval;
197  }
[378]198  int FitsHeader::pixToWCS(const double *pix, double *world)
199  {   
200    return pixToWCSSingle(this->wcs, pix, world); 
[419]201  }
[378]202  int FitsHeader::pixToWCS(const double *pix, double *world, const int npts)
203  {
204    return pixToWCSMulti(this->wcs, pix,world, npts); 
[419]205  }
[272]206
[378]207
208  double FitsHeader::pixToVel(double &x, double &y, double &z)
209  {
210    double vel;
211    if(this->wcsIsGood){
212      double *pix   = new double[3];
213      double *world = new double[3];
214      pix[0] = x; pix[1] = y; pix[2] = z;
215      pixToWCSSingle(this->wcs,pix,world);
216      vel = this->specToVel(world[2]);
217      delete [] pix;
218      delete [] world;
219    }
220    else vel = z;
221    return vel;
[272]222  }
223
[378]224  double* FitsHeader::pixToVel(double &x, double &y, double *zarray, int size)
225  {
226    double *newzarray = new double[size];
227    if(this->wcsIsGood){
228      double *pix   = new double[size*3];
229      for(int i=0;i<size;i++){
230        pix[3*i]   = x;
231        pix[3*i+1] = y;
232        pix[3*i+2] = zarray[i];
233      }
234      double *world = new double[size*3];
235      pixToWCSMulti(this->wcs,pix,world,size);
236      delete [] pix;
237      for(int i=0;i<size;i++) newzarray[i] = this->specToVel(world[3*i+2]);
238      delete [] world;
[272]239    }
[378]240    else{
241      for(int i=0;i<size;i++) newzarray[i] = zarray[i];
242    }
243    return newzarray;
[272]244  }
[378]245
246  double FitsHeader::specToVel(const double &coord)
247  {
248    double vel;
249    if(power==1.0) vel =  coord*this->scale + this->offset;
250    else vel = pow( (coord*this->scale + this->offset), this->power);
251    return vel;
[272]252  }
253
[378]254  double FitsHeader::velToSpec(const float &velocity)
255  {
256    //   return velToCoord(this->wcs,velocity,this->spectralUnits);};
257    return (pow(velocity, 1./this->power) - this->offset) / this->scale;
258  }
[272]259
[378]260  std::string FitsHeader::getIAUName(double ra, double dec)
261  {
[642]262    if(std::string(this->wcs->lngtyp)=="RA")
[378]263      return getIAUNameEQ(ra, dec, this->wcs->equinox);
264    else
265      return getIAUNameGAL(ra, dec);
266  }
[272]267
[949]268  void FitsHeader::fixSpectralUnits(std::string units)
[378]269  {
[528]270    ///  Put the units for the FITS header into some sort of standard form.
271    ///
272    ///  We first get the desired spectral units from the Parameter set,
273    ///  and then transform the spectral units of the wcsprm struct to
274    ///  those units. If this doesn't work, we leave them as they are. If
275    ///  they are blank, we make them SPC and give an error message --
276    ///  this should hopefully NOT happen.
277    ///
278    ///  We also work out the units for the integrated flux. If there are
279    ///  three axes, we just append the spectral units to the flux units
280    ///  (removing "/beam" if it is present). If there are just two, we
281    ///  simply keep it the same, removing the "/beam".
282    ///
283    ///  \param par The parameter set telling us what the desired
284    ///             spectral units are.
[375]285
[949]286
[378]287    double sc=1.;
288    double of=0.;
289    double po=1.;
[949]290 
291    this->spectralUnits = this->wcs->cunit[this->wcs->spec];
292
293    if(units != ""){
294
295      if(this->wcsIsGood){
296 
297        int status = wcsunits( this->wcs->cunit[this->wcs->spec], units.c_str(), &sc, &of, &po);
298
299        if(status > 0){
300          DUCHAMPERROR("fixSpectralUnits","Conversion of spectral units from '" << this->wcs->cunit[this->wcs->spec] << "' to '" << units
301                       << "' failed, wcslib code = " << status << ": " << wcsunits_errmsg[status]);
302          if(this->spectralUnits==""){
303            DUCHAMPERROR("fixSpectralUnits", "Spectral units not specified. For data presentation, we will use dummy units of \"SPC\".\n"
304                         << "Please report this occurence -- it should not happen! In the meantime, you may want to set the CUNIT"
305                         << this->wcs->spec + 1 <<" keyword to make this work.");
306            this->spectralUnits = "SPC";
307          }
[378]308        }
[949]309        else this->spectralUnits = units;
[378]310      }
[272]311    }
[378]312    this->scale = sc;
313    this->offset= of;
314    this->power = po;
[949]315   
[434]316  }
317
[796]318  bool FitsHeader::needBeamSize()
319  {
320    ///  A function that tells you whether the beam correction is
321    ///  needed. It checks to see whether the flux units string ends in
322    ///  "/beam" (in which case the beam size etc is needed and
323    ///  integrated fluxes need to be corrected). If we don't have any beam
324    ///  information, this will return false.
325    ///  /return True if FitsHeader::fluxUnits ends in "/beam". False
326    ///  otherwise.
327
328    int size = this->fluxUnits.size();
329    if(this->itsBeam.origin()==EMPTY) return false; // we have no beam to correct with!
330    else if(size<6) return false;
331    else {
332      std::string tailOfFluxUnits = makelower(this->fluxUnits.substr(size-5,size));
333      return (tailOfFluxUnits == "/beam");
334    }
335  }
336
[434]337  void FitsHeader::setIntFluxUnits()
338  {
339
[528]340    /// Work out the integrated flux units, based on the spectral
341    /// units. If flux is per beam, trim the /beam from the flux
342    /// units. Then, if as long as the image is 3D, multiply by the
343    /// spectral units.
[378]344   
[791]345    if(this->needBeamSize())
346      this->intFluxUnits = this->fluxUnits.substr(0,this->fluxUnits.size()-5);
347    else
348      this->intFluxUnits = this->fluxUnits;
[272]349
[570]350    if(!this->flag2D) this->intFluxUnits += std::string(" ") + this->spectralUnits;
[513]351
[272]352  }
353
[963]354  std::string FitsHeader::lngtype()
355  {
356    std::string lngtyp(this->wcs->lngtyp);
357    if(removeLeadingBlanks(lngtyp)==""){
358      lngtyp = this->wcs->ctype[this->wcs->lng];
359      return lngtyp.substr(0,4);
360    }
361    else return lngtyp;
362  }
[675]363
[963]364  std::string FitsHeader::lattype()
365  {
366    std::string lattyp(this->wcs->lattyp);
367    if(removeLeadingBlanks(lattyp)==""){
368      lattyp = this->wcs->ctype[this->wcs->lat];
369      return lattyp.substr(0,4);
370    }
371    else return lattyp;
372  }
[675]373
[1133]374  float FitsHeader::getShapeScale()
375  {
376    // Returns a scale factor that will scale the reported size of the fitted ellipses to numbers that are sensible.
[1176]377      float scale;
378      float cdelt = fabs(this->wcs->cdelt[this->wcs->lng]);
379      if(cdelt>0.01) scale =1.;
[1211]380      else if(cdelt<1.e-3) scale=3600.;
[1176]381      else scale = 60.;
382      return scale;
[1133]383  }
384
385  std::string FitsHeader::getShapeUnits()
386  {
[1176]387      std::string units="deg";
388      float cdelt = fabs(this->wcs->cdelt[this->wcs->lng]);
389      if(cdelt>0.01) units="deg";
[1211]390      else if(cdelt<1.e-3) units="arcsec";
[1176]391      else units="arcmin";
392      return units;
[1133]393  }
394
395
[272]396}
Note: See TracBrowser for help on using the repository browser.