source: trunk/src/fitsHeader.cc

Last change on this file was 1450, checked in by MatthewWhiting, 4 years ago

AXA-537 - Adding a bit more care in the pointer handling, particularly for the reconFilter in the copy constructor

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);
[1450]66    if (wcs){
67        free(wcs);
68    }
[378]69  }
[272]70
[378]71  FitsHeader::FitsHeader(const FitsHeader& h)
72  {
73    operator=(h);
74  }
[272]75
[378]76  FitsHeader& FitsHeader::operator= (const FitsHeader& h)
77  {
78    if(this == &h) return *this;
[971]79    this->fptr = h.fptr;
[378]80    this->wcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
81    this->wcs->flag     = -1;
82    wcsini(true, h.wcs->naxis, this->wcs);
83    wcscopy(true, h.wcs, this->wcs);
84    wcsset(this->wcs);
85    this->nwcs          = h.nwcs;
86    this->wcsIsGood     = h.wcsIsGood;
[570]87    this->flag2D        = h.flag2D;
[378]88    this->spectralUnits = h.spectralUnits;
[947]89    this->spectralType  = h.spectralType;
[570]90    this->spectralDescription = h.spectralDescription;
[757]91    this->originalFluxUnits = h.originalFluxUnits;
[378]92    this->fluxUnits     = h.fluxUnits;
93    this->intFluxUnits  = h.intFluxUnits;
[788]94    this->itsBeam       = h.itsBeam;
[378]95    this->blankKeyword  = h.blankKeyword;
96    this->bzeroKeyword  = h.bzeroKeyword;
97    this->bscaleKeyword = h.bscaleKeyword;
98    this->scale         = h.scale;
99    this->offset        = h.offset;
100    this->power         = h.power;
101    return *this;
102  }
[272]103
[971]104  int FitsHeader::openFITS(std::string name)
105  {
106    int status = 0;
107    if( fits_open_file(&this->fptr,name.c_str(),READONLY,&status) ){
108      fits_report_error(stderr, status);
109      // if(((status==URL_PARSE_ERROR)||(status==BAD_NAXIS))
110      //         &&(this->pars().getFlagSubsection()))
111      //        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.");
112    }
113    return status;
114  }
115
116  int FitsHeader::closeFITS()
117  {
118    int status=0;
119    fits_close_file(this->fptr, &status);
120    if (status){
121      DUCHAMPWARN("Cube Reader","Error closing file: ");
122      fits_report_error(stderr, status);
123    }
124    return status;
125
126  }
127
[378]128  void FitsHeader::setWCS(struct wcsprm *w)
129  {
[528]130    ///  A function that assigns the wcs parameters, and runs
131    ///   wcsset to set it up correctly.
132    ///  Performs a check to see if the WCS is good (by looking at
133    ///   the lng and lat wcsprm parameters), and sets the wcsIsGood
134    ///   flag accordingly.
135    /// \param w A WCSLIB wcsprm struct with the correct parameters.
136
[378]137    wcscopy(true, w, this->wcs);
138    wcsset(this->wcs);
139    if( (w->lng!=-1) && (w->lat!=-1) ) this->wcsIsGood = true;
140  }
[272]141
[1382]142  struct wcsprm *FitsHeader::getWCScopy()
[378]143  {
[528]144    ///  A function that returns a properly initilized wcsprm object
145    ///  corresponding to the WCS.
146
[378]147    struct wcsprm *wNew = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
148    wNew->flag=-1;
149    wcsini(true, this->wcs->naxis, wNew);
150    wcscopy(true, this->wcs, wNew);
151    wcsset(wNew);
152    return wNew;
153  }
[272]154
[1296]155  int FitsHeader::wcsToPix(double xWorld, double yWorld, double zWorld, double &xPix, double &yPix, double &zPix)
156  {
157      double world[3],pix[3];
158      world[0]=xWorld;
159      world[1]=yWorld;
160      world[2]=zWorld;
161      int returnval = wcsToPixSingle(this->wcs, world, pix);
162      if(returnval==0){
163          xPix=pix[0];
164          yPix=pix[1];
165          zPix=pix[2];
166      }
167      else {
168          xPix=-1.;
169          yPix=-1.;
170          zPix=-1.;
171      }
172      return returnval;
173  }
[378]174  int FitsHeader::wcsToPix(const double *world, double *pix)
175  {     
176    return wcsToPixSingle(this->wcs, world, pix); 
[419]177  }
[378]178  int FitsHeader::wcsToPix(const double *world, double *pix, const int npts)
179  {
180    return wcsToPixMulti(this->wcs, world, pix, npts); 
[419]181  }
[1296]182  int FitsHeader::pixToWCS(double xPix, double yPix, double zPix, double &xWorld, double &yWorld, double &zWorld)
183  {
184      double world[3],pix[3];
185      pix[0]=xPix;
186      pix[1]=yPix;
187      pix[2]=zPix;
188      int returnval = pixToWCSSingle(this->wcs, pix, world);
189      if(returnval==0){
190          xWorld=world[0];
191          yWorld=world[1];
192          zWorld=world[2];
193      }
194      else {
195          xWorld=-1.;
196          yWorld=-1.;
197          zWorld=-1.;
198      }
199      return returnval;
200  }
[378]201  int FitsHeader::pixToWCS(const double *pix, double *world)
202  {   
203    return pixToWCSSingle(this->wcs, pix, world); 
[419]204  }
[378]205  int FitsHeader::pixToWCS(const double *pix, double *world, const int npts)
206  {
207    return pixToWCSMulti(this->wcs, pix,world, npts); 
[419]208  }
[272]209
[378]210
211  double FitsHeader::pixToVel(double &x, double &y, double &z)
212  {
213    double vel;
214    if(this->wcsIsGood){
215      double *pix   = new double[3];
216      double *world = new double[3];
217      pix[0] = x; pix[1] = y; pix[2] = z;
218      pixToWCSSingle(this->wcs,pix,world);
219      vel = this->specToVel(world[2]);
220      delete [] pix;
221      delete [] world;
222    }
223    else vel = z;
224    return vel;
[272]225  }
226
[378]227  double* FitsHeader::pixToVel(double &x, double &y, double *zarray, int size)
228  {
229    double *newzarray = new double[size];
230    if(this->wcsIsGood){
231      double *pix   = new double[size*3];
232      for(int i=0;i<size;i++){
233        pix[3*i]   = x;
234        pix[3*i+1] = y;
235        pix[3*i+2] = zarray[i];
236      }
237      double *world = new double[size*3];
238      pixToWCSMulti(this->wcs,pix,world,size);
239      delete [] pix;
240      for(int i=0;i<size;i++) newzarray[i] = this->specToVel(world[3*i+2]);
241      delete [] world;
[272]242    }
[378]243    else{
244      for(int i=0;i<size;i++) newzarray[i] = zarray[i];
245    }
246    return newzarray;
[272]247  }
[378]248
249  double FitsHeader::specToVel(const double &coord)
250  {
251    double vel;
252    if(power==1.0) vel =  coord*this->scale + this->offset;
253    else vel = pow( (coord*this->scale + this->offset), this->power);
254    return vel;
[272]255  }
256
[378]257  double FitsHeader::velToSpec(const float &velocity)
258  {
259    //   return velToCoord(this->wcs,velocity,this->spectralUnits);};
260    return (pow(velocity, 1./this->power) - this->offset) / this->scale;
261  }
[272]262
[378]263  std::string FitsHeader::getIAUName(double ra, double dec)
264  {
[642]265    if(std::string(this->wcs->lngtyp)=="RA")
[378]266      return getIAUNameEQ(ra, dec, this->wcs->equinox);
267    else
268      return getIAUNameGAL(ra, dec);
269  }
[272]270
[949]271  void FitsHeader::fixSpectralUnits(std::string units)
[378]272  {
[528]273    ///  Put the units for the FITS header into some sort of standard form.
274    ///
275    ///  We first get the desired spectral units from the Parameter set,
276    ///  and then transform the spectral units of the wcsprm struct to
277    ///  those units. If this doesn't work, we leave them as they are. If
278    ///  they are blank, we make them SPC and give an error message --
279    ///  this should hopefully NOT happen.
280    ///
281    ///  We also work out the units for the integrated flux. If there are
282    ///  three axes, we just append the spectral units to the flux units
283    ///  (removing "/beam" if it is present). If there are just two, we
284    ///  simply keep it the same, removing the "/beam".
285    ///
286    ///  \param par The parameter set telling us what the desired
287    ///             spectral units are.
[375]288
[949]289
[378]290    double sc=1.;
291    double of=0.;
292    double po=1.;
[949]293 
294    this->spectralUnits = this->wcs->cunit[this->wcs->spec];
295
296    if(units != ""){
297
298      if(this->wcsIsGood){
299 
300        int status = wcsunits( this->wcs->cunit[this->wcs->spec], units.c_str(), &sc, &of, &po);
301
302        if(status > 0){
303          DUCHAMPERROR("fixSpectralUnits","Conversion of spectral units from '" << this->wcs->cunit[this->wcs->spec] << "' to '" << units
304                       << "' failed, wcslib code = " << status << ": " << wcsunits_errmsg[status]);
305          if(this->spectralUnits==""){
306            DUCHAMPERROR("fixSpectralUnits", "Spectral units not specified. For data presentation, we will use dummy units of \"SPC\".\n"
307                         << "Please report this occurence -- it should not happen! In the meantime, you may want to set the CUNIT"
308                         << this->wcs->spec + 1 <<" keyword to make this work.");
309            this->spectralUnits = "SPC";
310          }
[378]311        }
[949]312        else this->spectralUnits = units;
[378]313      }
[272]314    }
[378]315    this->scale = sc;
316    this->offset= of;
317    this->power = po;
[949]318   
[434]319  }
320
[796]321  bool FitsHeader::needBeamSize()
322  {
323    ///  A function that tells you whether the beam correction is
324    ///  needed. It checks to see whether the flux units string ends in
325    ///  "/beam" (in which case the beam size etc is needed and
326    ///  integrated fluxes need to be corrected). If we don't have any beam
327    ///  information, this will return false.
328    ///  /return True if FitsHeader::fluxUnits ends in "/beam". False
329    ///  otherwise.
330
331    int size = this->fluxUnits.size();
332    if(this->itsBeam.origin()==EMPTY) return false; // we have no beam to correct with!
333    else if(size<6) return false;
334    else {
335      std::string tailOfFluxUnits = makelower(this->fluxUnits.substr(size-5,size));
336      return (tailOfFluxUnits == "/beam");
337    }
338  }
339
[434]340  void FitsHeader::setIntFluxUnits()
341  {
342
[528]343    /// Work out the integrated flux units, based on the spectral
344    /// units. If flux is per beam, trim the /beam from the flux
345    /// units. Then, if as long as the image is 3D, multiply by the
346    /// spectral units.
[378]347   
[791]348    if(this->needBeamSize())
349      this->intFluxUnits = this->fluxUnits.substr(0,this->fluxUnits.size()-5);
350    else
351      this->intFluxUnits = this->fluxUnits;
[272]352
[570]353    if(!this->flag2D) this->intFluxUnits += std::string(" ") + this->spectralUnits;
[513]354
[272]355  }
356
[963]357  std::string FitsHeader::lngtype()
358  {
359    std::string lngtyp(this->wcs->lngtyp);
360    if(removeLeadingBlanks(lngtyp)==""){
361      lngtyp = this->wcs->ctype[this->wcs->lng];
362      return lngtyp.substr(0,4);
363    }
364    else return lngtyp;
365  }
[675]366
[963]367  std::string FitsHeader::lattype()
368  {
369    std::string lattyp(this->wcs->lattyp);
370    if(removeLeadingBlanks(lattyp)==""){
371      lattyp = this->wcs->ctype[this->wcs->lat];
372      return lattyp.substr(0,4);
373    }
374    else return lattyp;
375  }
[675]376
[1133]377  float FitsHeader::getShapeScale()
378  {
379    // Returns a scale factor that will scale the reported size of the fitted ellipses to numbers that are sensible.
[1176]380      float scale;
381      float cdelt = fabs(this->wcs->cdelt[this->wcs->lng]);
382      if(cdelt>0.01) scale =1.;
[1211]383      else if(cdelt<1.e-3) scale=3600.;
[1176]384      else scale = 60.;
385      return scale;
[1133]386  }
387
388  std::string FitsHeader::getShapeUnits()
389  {
[1176]390      std::string units="deg";
391      float cdelt = fabs(this->wcs->cdelt[this->wcs->lng]);
392      if(cdelt>0.01) units="deg";
[1211]393      else if(cdelt<1.e-3) units="arcsec";
[1176]394      else units="arcmin";
395      return units;
[1133]396  }
397
398
[272]399}
Note: See TracBrowser for help on using the repository browser.