source: trunk/src/fitsHeader.cc @ 788

Last change on this file since 788 was 788, checked in by MatthewWhiting, 13 years ago

First part of dealing with #110. Have defined a Beam & DuchampBeam? class and use these to hold the beam information. FitsHeader? holds the one that we work with, and copies it to Param for use with outputs. Parameters will be taken into account if no header information is present. Still need to add code to deal with the case of neither being present (the beam being EMPTY) and how that affects the integrated flux calculations.

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