source: trunk/src/fitsHeader.cc @ 971

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

A bunch of changes aimed at streamlining the FITS file access at the start, particularly for the case of large images where we access a subsection (this can be slow to access). We now only open the file once, and keep the fitsfile pointer in the FitsHeader? class. Once the image access is finished the file is closed.

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