source: trunk/src/fitsHeader.cc @ 1133

Last change on this file since 1133 was 1133, checked in by MatthewWhiting, 11 years ago

Ticket #132 - New code to fit the ellipse to the moment-0 map thresholded at half its peak - this then provides FWHM esimates for major/minor axes. Also have adaptive units for these axes, scaling to get the numbers not too small and adjusting the units accordingly. 2D images also have the shape calculated too now.

File size: 11.2 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->fptr = 0;
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;
50    this->flag2D=false;
51    this->spectralUnits="";
52    this->spectralDescription=duchamp::duchampSpectralDescription[FREQUENCY];
53    this->originalFluxUnits="counts";
54    this->fluxUnits="counts";
55    this->intFluxUnits="counts";
56    this->scale=1.;
57    this->offset=0.;
58    this->power=1.;
59    this->itsBeam.empty();
60  }
61
62  FitsHeader::~FitsHeader()
63  {
64    /// @details Uses the WCSLIB function wcsvfree to clear the wcsprm struct.
65    wcsvfree(&nwcs,&wcs);
66  }
67
68  FitsHeader::FitsHeader(const FitsHeader& h)
69  {
70    operator=(h);
71  }
72
73  FitsHeader& FitsHeader::operator= (const FitsHeader& h)
74  {
75    if(this == &h) return *this;
76    this->fptr = h.fptr;
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;
84    this->flag2D        = h.flag2D;
85    this->spectralUnits = h.spectralUnits;
86    this->spectralType  = h.spectralType;
87    this->spectralDescription = h.spectralDescription;
88    this->originalFluxUnits = h.originalFluxUnits;
89    this->fluxUnits     = h.fluxUnits;
90    this->intFluxUnits  = h.intFluxUnits;
91    this->itsBeam       = h.itsBeam;
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  }
100
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
125  void FitsHeader::setWCS(struct wcsprm *w)
126  {
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
134    wcscopy(true, w, this->wcs);
135    wcsset(this->wcs);
136    if( (w->lng!=-1) && (w->lat!=-1) ) this->wcsIsGood = true;
137  }
138
139  struct wcsprm *FitsHeader::getWCS()
140  {
141    ///  A function that returns a properly initilized wcsprm object
142    ///  corresponding to the WCS.
143
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  }
151
152  int FitsHeader::wcsToPix(const double *world, double *pix)
153  {     
154    return wcsToPixSingle(this->wcs, world, pix); 
155  }
156  int FitsHeader::wcsToPix(const double *world, double *pix, const int npts)
157  {
158    return wcsToPixMulti(this->wcs, world, pix, npts); 
159  }
160  int FitsHeader::pixToWCS(const double *pix, double *world)
161  {   
162    return pixToWCSSingle(this->wcs, pix, world); 
163  }
164  int FitsHeader::pixToWCS(const double *pix, double *world, const int npts)
165  {
166    return pixToWCSMulti(this->wcs, pix,world, npts); 
167  }
168
169
170  double FitsHeader::pixToVel(double &x, double &y, double &z)
171  {
172    double vel;
173    if(this->wcsIsGood){
174      double *pix   = new double[3];
175      double *world = new double[3];
176      pix[0] = x; pix[1] = y; pix[2] = z;
177      pixToWCSSingle(this->wcs,pix,world);
178      vel = this->specToVel(world[2]);
179      delete [] pix;
180      delete [] world;
181    }
182    else vel = z;
183    return vel;
184  }
185
186  double* FitsHeader::pixToVel(double &x, double &y, double *zarray, int size)
187  {
188    double *newzarray = new double[size];
189    if(this->wcsIsGood){
190      double *pix   = new double[size*3];
191      for(int i=0;i<size;i++){
192        pix[3*i]   = x;
193        pix[3*i+1] = y;
194        pix[3*i+2] = zarray[i];
195      }
196      double *world = new double[size*3];
197      pixToWCSMulti(this->wcs,pix,world,size);
198      delete [] pix;
199      for(int i=0;i<size;i++) newzarray[i] = this->specToVel(world[3*i+2]);
200      delete [] world;
201    }
202    else{
203      for(int i=0;i<size;i++) newzarray[i] = zarray[i];
204    }
205    return newzarray;
206  }
207
208  double FitsHeader::specToVel(const double &coord)
209  {
210    double vel;
211    if(power==1.0) vel =  coord*this->scale + this->offset;
212    else vel = pow( (coord*this->scale + this->offset), this->power);
213    return vel;
214  }
215
216  double FitsHeader::velToSpec(const float &velocity)
217  {
218    //   return velToCoord(this->wcs,velocity,this->spectralUnits);};
219    return (pow(velocity, 1./this->power) - this->offset) / this->scale;
220  }
221
222  std::string FitsHeader::getIAUName(double ra, double dec)
223  {
224    if(std::string(this->wcs->lngtyp)=="RA")
225      return getIAUNameEQ(ra, dec, this->wcs->equinox);
226    else
227      return getIAUNameGAL(ra, dec);
228  }
229
230  void FitsHeader::fixSpectralUnits(std::string units)
231  {
232    ///  Put the units for the FITS header into some sort of standard form.
233    ///
234    ///  We first get the desired spectral units from the Parameter set,
235    ///  and then transform the spectral units of the wcsprm struct to
236    ///  those units. If this doesn't work, we leave them as they are. If
237    ///  they are blank, we make them SPC and give an error message --
238    ///  this should hopefully NOT happen.
239    ///
240    ///  We also work out the units for the integrated flux. If there are
241    ///  three axes, we just append the spectral units to the flux units
242    ///  (removing "/beam" if it is present). If there are just two, we
243    ///  simply keep it the same, removing the "/beam".
244    ///
245    ///  \param par The parameter set telling us what the desired
246    ///             spectral units are.
247
248
249    double sc=1.;
250    double of=0.;
251    double po=1.;
252 
253    this->spectralUnits = this->wcs->cunit[this->wcs->spec];
254
255    if(units != ""){
256
257      if(this->wcsIsGood){
258 
259        int status = wcsunits( this->wcs->cunit[this->wcs->spec], units.c_str(), &sc, &of, &po);
260
261        if(status > 0){
262          DUCHAMPERROR("fixSpectralUnits","Conversion of spectral units from '" << this->wcs->cunit[this->wcs->spec] << "' to '" << units
263                       << "' failed, wcslib code = " << status << ": " << wcsunits_errmsg[status]);
264          if(this->spectralUnits==""){
265            DUCHAMPERROR("fixSpectralUnits", "Spectral units not specified. For data presentation, we will use dummy units of \"SPC\".\n"
266                         << "Please report this occurence -- it should not happen! In the meantime, you may want to set the CUNIT"
267                         << this->wcs->spec + 1 <<" keyword to make this work.");
268            this->spectralUnits = "SPC";
269          }
270        }
271        else this->spectralUnits = units;
272      }
273    }
274    this->scale = sc;
275    this->offset= of;
276    this->power = po;
277   
278    this->setIntFluxUnits();
279
280  }
281
282  bool FitsHeader::needBeamSize()
283  {
284    ///  A function that tells you whether the beam correction is
285    ///  needed. It checks to see whether the flux units string ends in
286    ///  "/beam" (in which case the beam size etc is needed and
287    ///  integrated fluxes need to be corrected). If we don't have any beam
288    ///  information, this will return false.
289    ///  /return True if FitsHeader::fluxUnits ends in "/beam". False
290    ///  otherwise.
291
292    int size = this->fluxUnits.size();
293    if(this->itsBeam.origin()==EMPTY) return false; // we have no beam to correct with!
294    else if(size<6) return false;
295    else {
296      std::string tailOfFluxUnits = makelower(this->fluxUnits.substr(size-5,size));
297      return (tailOfFluxUnits == "/beam");
298    }
299  }
300
301  void FitsHeader::setIntFluxUnits()
302  {
303
304    /// Work out the integrated flux units, based on the spectral
305    /// units. If flux is per beam, trim the /beam from the flux
306    /// units. Then, if as long as the image is 3D, multiply by the
307    /// spectral units.
308   
309    if(this->needBeamSize())
310      this->intFluxUnits = this->fluxUnits.substr(0,this->fluxUnits.size()-5);
311    else
312      this->intFluxUnits = this->fluxUnits;
313
314    if(!this->flag2D) this->intFluxUnits += std::string(" ") + this->spectralUnits;
315
316  }
317
318  std::string FitsHeader::lngtype()
319  {
320    std::string lngtyp(this->wcs->lngtyp);
321    if(removeLeadingBlanks(lngtyp)==""){
322      lngtyp = this->wcs->ctype[this->wcs->lng];
323      return lngtyp.substr(0,4);
324    }
325    else return lngtyp;
326  }
327
328  std::string FitsHeader::lattype()
329  {
330    std::string lattyp(this->wcs->lattyp);
331    if(removeLeadingBlanks(lattyp)==""){
332      lattyp = this->wcs->ctype[this->wcs->lat];
333      return lattyp.substr(0,4);
334    }
335    else return lattyp;
336  }
337
338  float FitsHeader::getShapeScale()
339  {
340    // Returns a scale factor that will scale the reported size of the fitted ellipses to numbers that are sensible.
341    float scale=1.;
342    if(fabs(this->wcs->cdelt[this->wcs->lng])<0.01) scale=60.;
343    else if(fabs(this->wcs->cdelt[this->wcs->lng])<5.e-4) scale=3600.;
344    return scale;
345  }
346
347  std::string FitsHeader::getShapeUnits()
348  {
349    std::string units="deg";
350    if(fabs(this->wcs->cdelt[this->wcs->lng])<0.01) units="arcmin";
351    else if(fabs(this->wcs->cdelt[this->wcs->lng])<5.e-4) units="arcsec";
352    return units;
353  }
354
355
356}
Note: See TracBrowser for help on using the repository browser.