source: branches/OptimisedGrowerTesting/src/fitsHeader.cc @ 1441

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

New wcs-pix conversion functions, that don't require you to provide C-arrays when converting a single location.

File size: 12.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->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="";
54    this->fluxUnits="";
55    this->intFluxUnits="";
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(double xWorld, double yWorld, double zWorld, double &xPix, double &yPix, double &zPix)
153  {
154      double world[3],pix[3];
155      world[0]=xWorld;
156      world[1]=yWorld;
157      world[2]=zWorld;
158      int returnval = wcsToPixSingle(this->wcs, world, pix);
159      if(returnval==0){
160          xPix=pix[0];
161          yPix=pix[1];
162          zPix=pix[2];
163      }
164      else {
165          xPix=-1.;
166          yPix=-1.;
167          zPix=-1.;
168      }
169      return returnval;
170  }
171  int FitsHeader::wcsToPix(const double *world, double *pix)
172  {     
173    return wcsToPixSingle(this->wcs, world, pix); 
174  }
175  int FitsHeader::wcsToPix(const double *world, double *pix, const int npts)
176  {
177    return wcsToPixMulti(this->wcs, world, pix, npts); 
178  }
179  int FitsHeader::pixToWCS(double xPix, double yPix, double zPix, double &xWorld, double &yWorld, double &zWorld)
180  {
181      double world[3],pix[3];
182      pix[0]=xPix;
183      pix[1]=yPix;
184      pix[2]=zPix;
185      int returnval = pixToWCSSingle(this->wcs, pix, world);
186      if(returnval==0){
187          xWorld=world[0];
188          yWorld=world[1];
189          zWorld=world[2];
190      }
191      else {
192          xWorld=-1.;
193          yWorld=-1.;
194          zWorld=-1.;
195      }
196      return returnval;
197  }
198  int FitsHeader::pixToWCS(const double *pix, double *world)
199  {   
200    return pixToWCSSingle(this->wcs, pix, world); 
201  }
202  int FitsHeader::pixToWCS(const double *pix, double *world, const int npts)
203  {
204    return pixToWCSMulti(this->wcs, pix,world, npts); 
205  }
206
207
208  double FitsHeader::pixToVel(double &x, double &y, double &z)
209  {
210    double vel;
211    if(this->wcsIsGood){
212      double *pix   = new double[3];
213      double *world = new double[3];
214      pix[0] = x; pix[1] = y; pix[2] = z;
215      pixToWCSSingle(this->wcs,pix,world);
216      vel = this->specToVel(world[2]);
217      delete [] pix;
218      delete [] world;
219    }
220    else vel = z;
221    return vel;
222  }
223
224  double* FitsHeader::pixToVel(double &x, double &y, double *zarray, int size)
225  {
226    double *newzarray = new double[size];
227    if(this->wcsIsGood){
228      double *pix   = new double[size*3];
229      for(int i=0;i<size;i++){
230        pix[3*i]   = x;
231        pix[3*i+1] = y;
232        pix[3*i+2] = zarray[i];
233      }
234      double *world = new double[size*3];
235      pixToWCSMulti(this->wcs,pix,world,size);
236      delete [] pix;
237      for(int i=0;i<size;i++) newzarray[i] = this->specToVel(world[3*i+2]);
238      delete [] world;
239    }
240    else{
241      for(int i=0;i<size;i++) newzarray[i] = zarray[i];
242    }
243    return newzarray;
244  }
245
246  double FitsHeader::specToVel(const double &coord)
247  {
248    double vel;
249    if(power==1.0) vel =  coord*this->scale + this->offset;
250    else vel = pow( (coord*this->scale + this->offset), this->power);
251    return vel;
252  }
253
254  double FitsHeader::velToSpec(const float &velocity)
255  {
256    //   return velToCoord(this->wcs,velocity,this->spectralUnits);};
257    return (pow(velocity, 1./this->power) - this->offset) / this->scale;
258  }
259
260  std::string FitsHeader::getIAUName(double ra, double dec)
261  {
262    if(std::string(this->wcs->lngtyp)=="RA")
263      return getIAUNameEQ(ra, dec, this->wcs->equinox);
264    else
265      return getIAUNameGAL(ra, dec);
266  }
267
268  void FitsHeader::fixSpectralUnits(std::string units)
269  {
270    ///  Put the units for the FITS header into some sort of standard form.
271    ///
272    ///  We first get the desired spectral units from the Parameter set,
273    ///  and then transform the spectral units of the wcsprm struct to
274    ///  those units. If this doesn't work, we leave them as they are. If
275    ///  they are blank, we make them SPC and give an error message --
276    ///  this should hopefully NOT happen.
277    ///
278    ///  We also work out the units for the integrated flux. If there are
279    ///  three axes, we just append the spectral units to the flux units
280    ///  (removing "/beam" if it is present). If there are just two, we
281    ///  simply keep it the same, removing the "/beam".
282    ///
283    ///  \param par The parameter set telling us what the desired
284    ///             spectral units are.
285
286
287    double sc=1.;
288    double of=0.;
289    double po=1.;
290 
291    this->spectralUnits = this->wcs->cunit[this->wcs->spec];
292
293    if(units != ""){
294
295      if(this->wcsIsGood){
296 
297        int status = wcsunits( this->wcs->cunit[this->wcs->spec], units.c_str(), &sc, &of, &po);
298
299        if(status > 0){
300          DUCHAMPERROR("fixSpectralUnits","Conversion of spectral units from '" << this->wcs->cunit[this->wcs->spec] << "' to '" << units
301                       << "' failed, wcslib code = " << status << ": " << wcsunits_errmsg[status]);
302          if(this->spectralUnits==""){
303            DUCHAMPERROR("fixSpectralUnits", "Spectral units not specified. For data presentation, we will use dummy units of \"SPC\".\n"
304                         << "Please report this occurence -- it should not happen! In the meantime, you may want to set the CUNIT"
305                         << this->wcs->spec + 1 <<" keyword to make this work.");
306            this->spectralUnits = "SPC";
307          }
308        }
309        else this->spectralUnits = units;
310      }
311    }
312    this->scale = sc;
313    this->offset= of;
314    this->power = po;
315   
316  }
317
318  bool FitsHeader::needBeamSize()
319  {
320    ///  A function that tells you whether the beam correction is
321    ///  needed. It checks to see whether the flux units string ends in
322    ///  "/beam" (in which case the beam size etc is needed and
323    ///  integrated fluxes need to be corrected). If we don't have any beam
324    ///  information, this will return false.
325    ///  /return True if FitsHeader::fluxUnits ends in "/beam". False
326    ///  otherwise.
327
328    int size = this->fluxUnits.size();
329    if(this->itsBeam.origin()==EMPTY) return false; // we have no beam to correct with!
330    else if(size<6) return false;
331    else {
332      std::string tailOfFluxUnits = makelower(this->fluxUnits.substr(size-5,size));
333      return (tailOfFluxUnits == "/beam");
334    }
335  }
336
337  void FitsHeader::setIntFluxUnits()
338  {
339
340    /// Work out the integrated flux units, based on the spectral
341    /// units. If flux is per beam, trim the /beam from the flux
342    /// units. Then, if as long as the image is 3D, multiply by the
343    /// spectral units.
344   
345    if(this->needBeamSize())
346      this->intFluxUnits = this->fluxUnits.substr(0,this->fluxUnits.size()-5);
347    else
348      this->intFluxUnits = this->fluxUnits;
349
350    if(!this->flag2D) this->intFluxUnits += std::string(" ") + this->spectralUnits;
351
352  }
353
354  std::string FitsHeader::lngtype()
355  {
356    std::string lngtyp(this->wcs->lngtyp);
357    if(removeLeadingBlanks(lngtyp)==""){
358      lngtyp = this->wcs->ctype[this->wcs->lng];
359      return lngtyp.substr(0,4);
360    }
361    else return lngtyp;
362  }
363
364  std::string FitsHeader::lattype()
365  {
366    std::string lattyp(this->wcs->lattyp);
367    if(removeLeadingBlanks(lattyp)==""){
368      lattyp = this->wcs->ctype[this->wcs->lat];
369      return lattyp.substr(0,4);
370    }
371    else return lattyp;
372  }
373
374  float FitsHeader::getShapeScale()
375  {
376    // Returns a scale factor that will scale the reported size of the fitted ellipses to numbers that are sensible.
377      float scale;
378      float cdelt = fabs(this->wcs->cdelt[this->wcs->lng]);
379      if(cdelt>0.01) scale =1.;
380      else if(cdelt<1.e-3) scale=3600.;
381      else scale = 60.;
382      return scale;
383  }
384
385  std::string FitsHeader::getShapeUnits()
386  {
387      std::string units="deg";
388      float cdelt = fabs(this->wcs->cdelt[this->wcs->lng]);
389      if(cdelt>0.01) units="deg";
390      else if(cdelt<1.e-3) units="arcsec";
391      else units="arcmin";
392      return units;
393  }
394
395
396}
Note: See TracBrowser for help on using the repository browser.