source: trunk/src/fitsHeader.cc @ 913

Last change on this file since 913 was 913, checked in by MatthewWhiting, 12 years ago

A large swathe of changes aimed at improving warning/error/exception handling. Now make use of macros and streams. Also, there is now a distinction between DUCHAMPERROR and DUCHAMPTHROW.

File size: 9.8 KB
Line 
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// -----------------------------------------------------------------------
28#include <iostream>
29#include <sstream>
30#include <string>
31#include <stdlib.h>
32#include <wcslib/wcs.h>
33#include <wcslib/wcsunits.h>
34#include <duchamp/duchamp.hh>
35#include <duchamp/param.hh>
36#include <duchamp/fitsHeader.hh>
37#include <duchamp/Utils/utils.hh>
38
39namespace duchamp
40{
41
42  FitsHeader::FitsHeader()
43  {
44    this->wcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
45    this->wcs->flag=-1;
46    wcsini(true, 3, this->wcs);
47    this->wcsIsGood = false;
48    this->nwcs = 0;
49    this->flag2D=false;
50    this->spectralUnits="";
51    this->spectralDescription=duchamp::duchampSpectralDescription[FREQUENCY];
52    this->originalFluxUnits="counts";
53    this->fluxUnits="counts";
54    this->intFluxUnits="counts";
55    this->scale=1.;
56    this->offset=0.;
57    this->power=1.;
58    this->itsBeam.empty();
59  }
60
61  FitsHeader::~FitsHeader()
62  {
63    /// @details Uses the WCSLIB function wcsvfree to clear the wcsprm struct.
64    wcsvfree(&nwcs,&wcs);
65  }
66
67  FitsHeader::FitsHeader(const FitsHeader& h)
68  {
69    operator=(h);
70  }
71
72  FitsHeader& FitsHeader::operator= (const FitsHeader& h)
73  {
74    if(this == &h) return *this;
75    this->wcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
76    this->wcs->flag     = -1;
77    wcsini(true, h.wcs->naxis, this->wcs);
78    wcscopy(true, h.wcs, this->wcs);
79    wcsset(this->wcs);
80    this->nwcs          = h.nwcs;
81    this->wcsIsGood     = h.wcsIsGood;
82    this->naxis         = h.naxis;
83    this->flag2D        = h.flag2D;
84    this->spectralUnits = h.spectralUnits;
85    this->spectralDescription = h.spectralDescription;
86    this->originalFluxUnits = h.originalFluxUnits;
87    this->fluxUnits     = h.fluxUnits;
88    this->intFluxUnits  = h.intFluxUnits;
89    this->itsBeam       = h.itsBeam;
90    this->blankKeyword  = h.blankKeyword;
91    this->bzeroKeyword  = h.bzeroKeyword;
92    this->bscaleKeyword = h.bscaleKeyword;
93    this->scale         = h.scale;
94    this->offset        = h.offset;
95    this->power         = h.power;
96    return *this;
97  }
98
99  void FitsHeader::setWCS(struct wcsprm *w)
100  {
101    ///  A function that assigns the wcs parameters, and runs
102    ///   wcsset to set it up correctly.
103    ///  Performs a check to see if the WCS is good (by looking at
104    ///   the lng and lat wcsprm parameters), and sets the wcsIsGood
105    ///   flag accordingly.
106    /// \param w A WCSLIB wcsprm struct with the correct parameters.
107
108    wcscopy(true, w, this->wcs);
109    wcsset(this->wcs);
110    if( (w->lng!=-1) && (w->lat!=-1) ) this->wcsIsGood = true;
111  }
112
113  struct wcsprm *FitsHeader::getWCS()
114  {
115    ///  A function that returns a properly initilized wcsprm object
116    ///  corresponding to the WCS.
117
118    struct wcsprm *wNew = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
119    wNew->flag=-1;
120    wcsini(true, this->wcs->naxis, wNew);
121    wcscopy(true, this->wcs, wNew);
122    wcsset(wNew);
123    return wNew;
124  }
125
126  int FitsHeader::wcsToPix(const double *world, double *pix)
127  {     
128    return wcsToPixSingle(this->wcs, world, pix); 
129  }
130  int FitsHeader::wcsToPix(const double *world, double *pix, const int npts)
131  {
132    return wcsToPixMulti(this->wcs, world, pix, npts); 
133  }
134  int FitsHeader::pixToWCS(const double *pix, double *world)
135  {   
136    return pixToWCSSingle(this->wcs, pix, world); 
137  }
138  int FitsHeader::pixToWCS(const double *pix, double *world, const int npts)
139  {
140    return pixToWCSMulti(this->wcs, pix,world, npts); 
141  }
142
143
144  double FitsHeader::pixToVel(double &x, double &y, double &z)
145  {
146    double vel;
147    if(this->wcsIsGood){
148      double *pix   = new double[3];
149      double *world = new double[3];
150      pix[0] = x; pix[1] = y; pix[2] = z;
151      pixToWCSSingle(this->wcs,pix,world);
152      vel = this->specToVel(world[2]);
153      delete [] pix;
154      delete [] world;
155    }
156    else vel = z;
157    return vel;
158  }
159
160  double* FitsHeader::pixToVel(double &x, double &y, double *zarray, int size)
161  {
162    double *newzarray = new double[size];
163    if(this->wcsIsGood){
164      double *pix   = new double[size*3];
165      for(int i=0;i<size;i++){
166        pix[3*i]   = x;
167        pix[3*i+1] = y;
168        pix[3*i+2] = zarray[i];
169      }
170      double *world = new double[size*3];
171      pixToWCSMulti(this->wcs,pix,world,size);
172      delete [] pix;
173      for(int i=0;i<size;i++) newzarray[i] = this->specToVel(world[3*i+2]);
174      delete [] world;
175    }
176    else{
177      for(int i=0;i<size;i++) newzarray[i] = zarray[i];
178    }
179    return newzarray;
180  }
181
182  double FitsHeader::specToVel(const double &coord)
183  {
184    double vel;
185    if(power==1.0) vel =  coord*this->scale + this->offset;
186    else vel = pow( (coord*this->scale + this->offset), this->power);
187    return vel;
188  }
189
190  double FitsHeader::velToSpec(const float &velocity)
191  {
192    //   return velToCoord(this->wcs,velocity,this->spectralUnits);};
193    return (pow(velocity, 1./this->power) - this->offset) / this->scale;
194  }
195
196  std::string FitsHeader::getIAUName(double ra, double dec)
197  {
198    if(std::string(this->wcs->lngtyp)=="RA")
199      return getIAUNameEQ(ra, dec, this->wcs->equinox);
200    else
201      return getIAUNameGAL(ra, dec);
202  }
203
204  void FitsHeader::fixUnits(Param &par)
205  {
206    ///  Put the units for the FITS header into some sort of standard form.
207    ///
208    ///  We first get the desired spectral units from the Parameter set,
209    ///  and then transform the spectral units of the wcsprm struct to
210    ///  those units. If this doesn't work, we leave them as they are. If
211    ///  they are blank, we make them SPC and give an error message --
212    ///  this should hopefully NOT happen.
213    ///
214    ///  We also work out the units for the integrated flux. If there are
215    ///  three axes, we just append the spectral units to the flux units
216    ///  (removing "/beam" if it is present). If there are just two, we
217    ///  simply keep it the same, removing the "/beam".
218    ///
219    ///  \param par The parameter set telling us what the desired
220    ///             spectral units are.
221
222    // define spectral units from the param set
223    this->spectralUnits = par.getSpectralUnits();
224    double sc=1.;
225    double of=0.;
226    double po=1.;
227    //   if((this->wcsIsGood) && (this->naxis>2)){
228    if(this->wcsIsGood){
229      int status = wcsunits( this->wcs->cunit[this->wcs->spec],
230                             (char *)this->spectralUnits.c_str(),
231                             &sc, &of, &po);
232      if(status > 0){
233        std::stringstream errmsg;
234        errmsg << "WCSUNITS Error, Code = " << status
235               << ": " << wcsunits_errmsg[status] << "\n";
236        if(status == 10)
237          errmsg << "Tried to get conversion from \""
238                 << this->wcs->cunit[this->wcs->spec] << "\" to \""
239                 << this->spectralUnits.c_str() << "\".\n";
240        this->spectralUnits = this->wcs->cunit[this->wcs->spec];
241        if(this->spectralUnits==""){
242          errmsg << "Spectral units not specified. "
243                 << "For data presentation, we will use dummy units of \"SPC\"."
244                 << "\n"
245                 << "Please report this occurence -- it should not happen now! "
246                 << "In the meantime, you may want to set the CUNIT"
247                 << this->wcs->spec + 1 <<" keyword to make this work.\n";
248          this->spectralUnits = "SPC";
249        }
250        DUCHAMPERROR("fixUnits", errmsg.str());
251      }
252      // else{
253      //        std::cerr << "Converted " << this->wcs->cunit[this->wcs->spec] << " to " << this->spectralUnits << " and got offset="<<of << ", scale="<<sc <<", and power="<<po <<"\n";
254      // }
255    }
256    this->scale = sc;
257    this->offset= of;
258    this->power = po;
259
260    this->setIntFluxUnits();
261
262  }
263
264  bool FitsHeader::needBeamSize()
265  {
266    ///  A function that tells you whether the beam correction is
267    ///  needed. It checks to see whether the flux units string ends in
268    ///  "/beam" (in which case the beam size etc is needed and
269    ///  integrated fluxes need to be corrected). If we don't have any beam
270    ///  information, this will return false.
271    ///  /return True if FitsHeader::fluxUnits ends in "/beam". False
272    ///  otherwise.
273
274    int size = this->fluxUnits.size();
275    if(this->itsBeam.origin()==EMPTY) return false; // we have no beam to correct with!
276    else if(size<6) return false;
277    else {
278      std::string tailOfFluxUnits = makelower(this->fluxUnits.substr(size-5,size));
279      return (tailOfFluxUnits == "/beam");
280    }
281  }
282
283  void FitsHeader::setIntFluxUnits()
284  {
285
286    /// Work out the integrated flux units, based on the spectral
287    /// units. If flux is per beam, trim the /beam from the flux
288    /// units. Then, if as long as the image is 3D, multiply by the
289    /// spectral units.
290   
291    if(this->needBeamSize())
292      this->intFluxUnits = this->fluxUnits.substr(0,this->fluxUnits.size()-5);
293    else
294      this->intFluxUnits = this->fluxUnits;
295
296    if(!this->flag2D) this->intFluxUnits += std::string(" ") + this->spectralUnits;
297
298  }
299
300
301
302}
Note: See TracBrowser for help on using the repository browser.