source: trunk/src/fitsHeader.cc @ 757

Last change on this file since 757 was 757, checked in by MatthewWhiting, 14 years ago

A few changes to get the writing of recon cubes right - the problem was when the flux units were changed. We need to change them back before the cube is written.

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