source: trunk/src/FitsIO/wcsIO.cc @ 356

Last change on this file since 356 was 356, checked in by MatthewWhiting, 17 years ago

Mostly changes related to the spectral WCS axis:

  • Altered wcsIO.cc so that it deals with the spectral axis and its units a bit better. Takes into account the WCS type.
  • Introduced an isSpecOK() function in Detection class so that we can better tell if we need to do spectral things, rather than just looking at the number of dimensions.

Few other minor changes as well.

File size: 8.6 KB
Line 
1// -----------------------------------------------------------------------
2// wcsIO.cc: Get the World Coordinate System for a particular FITS file.
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 <string>
30#include <stdlib.h>
31#include <wcs.h>
32#include <wcshdr.h>
33#include <fitshdr.h>
34#include <wcsfix.h>
35#include <wcsunits.h>
36#define WCSLIB_GETWCSTAB // define this so that we don't try and redefine
37                         //  wtbarr (this is a problem when using gcc v.4+
38#include <fitsio.h>
39#include <math.h>
40#include <duchamp.hh>
41#include <fitsHeader.hh>
42#include <Cubes/cubes.hh>
43
44int FitsHeader::defineWCS(std::string fname, Param &par)
45{
46  /**
47   *   A function that reads the WCS header information from the
48   *    FITS file given by fname
49   *   It will also sort out the spectral axis, and covert to the correct
50   *    velocity type, or frequency type if need be.
51   *   It calls FitsHeader::readBUNIT so that the Integrated Flux units can
52   *    be calculated by FitsHeader::fixUnits.
53   * \param fname Fits file to read.
54   * \param par Param set to help fix the units with.
55   */
56
57  fitsfile *fptr;
58  int numAxes;
59  int noComments = 1; //so that fits_hdr2str will ignore COMMENT, HISTORY etc
60  int nExc = 0,nkeys;
61  char *hdr;
62
63  // Open the FITS file
64  int status = 0;
65  if( fits_open_file(&fptr,fname.c_str(),READONLY,&status) ){
66    fits_report_error(stderr, status);
67    return FAILURE;
68  }
69
70  // Get the dimensions of the FITS file -- number of axes and size of each.
71  status = 0;
72  if(fits_get_img_dim(fptr, &numAxes, &status)){
73    fits_report_error(stderr, status);
74    return FAILURE;
75  }
76  long *dimAxes = new long[numAxes];
77  for(int i=0;i<numAxes;i++) dimAxes[i]=1;
78  status = 0;
79  if(fits_get_img_size(fptr, numAxes, dimAxes, &status)){
80    fits_report_error(stderr, status);
81    return FAILURE;
82  }
83
84  // Read in the entire PHU of the FITS file to a std::string.
85  // This will be read by the wcslib functions to extract the WCS.
86  status = 0;
87  fits_hdr2str(fptr, noComments, NULL, nExc, &hdr, &nkeys, &status);
88  if( status ){
89    duchampWarning("Cube Reader",
90                   "Error whilst reading FITS header to string: ");
91    fits_report_error(stderr, status);
92    return FAILURE;
93  }
94
95  // Close the FITS file -- not needed any more in this function.
96  status = 0;
97  fits_close_file(fptr, &status);
98  if (status){
99    duchampWarning("Cube Reader","Error closing file: ");
100    fits_report_error(stderr, status);
101  }
102 
103  // Define a temporary, local version of the WCS
104  struct wcsprm *localwcs;
105  localwcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
106  localwcs->flag=-1;
107
108  // Initialise this temporary wcsprm structure
109  status = wcsini(true, numAxes, localwcs);
110  if(status){
111    std::stringstream errmsg;
112    errmsg << "wcsini failed! Code=" << status
113           << ": " << wcs_errmsg[status] << std::endl;
114    duchampError("Cube Reader",errmsg.str());
115    return FAILURE;
116  }
117
118  this->naxis=0;
119  for(int i=0;i<numAxes;i++)
120    if(dimAxes[i]>1) this->naxis++;
121
122  int relax=1; // for wcspih -- admit all recognised informal WCS extensions
123  int ctrl=2;  // for wcspih -- report each rejected card and its reason for
124               //               rejection
125  int localnwcs, nreject;
126  // Parse the FITS header to fill in the wcsprm structure
127  status=wcspih(hdr, nkeys, relax, ctrl, &nreject, &localnwcs, &localwcs);
128  if(status){
129    // if here, something went wrong -- report what.
130    std::stringstream errmsg;
131    errmsg << "wcspih failed!\nWCSLIB error code=" << status
132           << ": " << wcs_errmsg[status] << std::endl;
133    duchampWarning("Cube Reader",errmsg.str());
134  }
135  else{ 
136    int stat[NWCSFIX];
137    // Applies all necessary corrections to the wcsprm structure
138    //  (missing cards, non-standard units or spectral types, ...)
139    status = wcsfix(1, (const int*)dimAxes, localwcs, stat);
140    if(status) {
141      std::stringstream errmsg;
142      errmsg << "wcsfix failed:\n";
143      errmsg << "Function status returns are:\n";
144      for(int i=0; i<NWCSFIX; i++)
145        if (stat[i] > 0)
146          errmsg << i+1 << ": WCSFIX error code=" << stat[i] << ": "
147                 << wcsfix_errmsg[stat[i]] << std::endl;
148      duchampWarning("Cube Reader", errmsg.str() );
149    }
150
151    // Set up the wcsprm struct. Report if something goes wrong.
152    status = wcsset(localwcs);
153    if(status){
154      std::stringstream errmsg;
155      errmsg<<"wcsset failed!\n"
156            <<"WCSLIB error code=" << status
157            <<": "<<wcs_errmsg[status] << std::endl;
158      duchampWarning("Cube Reader",errmsg.str());
159    }
160
161    if(localwcs->spec>=0){ //if there is a spectral axis
162
163      int index = localwcs->spec;
164      std::string desiredType,specType = localwcs->ctype[index];
165      std::string shortType = specType.substr(0,4);
166      if(shortType=="VELO" || shortType=="VOPT" || shortType=="ZOPT" || shortType=="VRAD" || shortType=="BETA"){
167        if(localwcs->restfrq != 0){
168          // Set the spectral axis to a standard specification: VELO-F2V
169          desiredType = duchampVelocityType;
170          if(localwcs->restwav == 0)
171            localwcs->restwav = 299792458.0 /  localwcs->restfrq;
172          this->spectralDescription = duchampSpectralDescription[VELOCITY];
173        }
174        else{
175          // No rest frequency defined, so put spectral dimension in frequency.
176          // Set the spectral axis to a standard specification: FREQ
177          duchampWarning("Cube Reader",
178                         "No rest frequency defined. Using frequency units in spectral axis.\n");
179          desiredType = duchampFrequencyType;
180          par.setSpectralUnits("MHz");
181          if(strcmp(localwcs->cunit[index],"")==0){
182            duchampWarning("Cube Reader",
183                           "No frequency unit given. Assuming frequency axis is in Hz.\n");
184            strcpy(localwcs->cunit[index],"Hz");
185          }
186          this->spectralDescription = duchampSpectralDescription[FREQUENCY];
187        }
188      }
189      else {
190        desiredType = duchampFrequencyType;
191        par.setSpectralUnits("MHz");
192        if(strcmp(localwcs->cunit[index],"")==0){
193          duchampWarning("Cube Reader",
194          "No frequency unit given. Assuming frequency axis is in Hz.\n");
195          strcpy(localwcs->cunit[index],"Hz");
196        }
197        this->spectralDescription = duchampSpectralDescription[FREQUENCY];
198      }
199
200      // Now we need to make sure the spectral axis has the correct setup.
201      //  We use wcssptr to translate it if it is not of the desired type,
202      //  or if the spectral units are not defined.
203
204      std::cerr << specType << "\n";
205
206      bool needToTranslate = false;
207
208//       if(strncmp(specType.c_str(),desiredType.c_str(),4)!=0)
209//      needToTranslate = true;
210
211      std::string blankstring = "";
212      if(strcmp(localwcs->cunit[localwcs->spec],blankstring.c_str())==0)
213        needToTranslate = true;
214
215      if(needToTranslate){
216
217        if(strcmp(localwcs->ctype[localwcs->spec],"VELO")==0)
218          strcpy(localwcs->ctype[localwcs->spec],"VELO-F2V");
219
220        index = localwcs->spec;
221       
222        status = wcssptr(localwcs, &index, (char *)desiredType.c_str());
223        if(status){
224          std::stringstream errmsg;
225          errmsg<< "WCSSPTR failed! Code=" << status << ": "
226                << wcs_errmsg[status] << std::endl
227                << "(wanted to convert from type \"" << specType
228                << "\" to type \"" << desiredType << "\")\n";
229          duchampWarning("Cube Reader",errmsg.str());
230
231        }
232
233      }
234   
235  } // end of if(localwcs->spec>=0)
236   
237    // Save the wcs to the FitsHeader class that is running this function
238    this->setWCS(localwcs);
239    this->setNWCS(localnwcs);
240
241  }
242
243  // clean up allocated memory
244  wcsvfree(&localnwcs,&localwcs);
245  wcsfree(localwcs);
246  free(localwcs);
247  free(hdr);
248  delete [] dimAxes;
249
250  // Get the brightness unit, so that we can set the units for the
251  //  integrated flux when we go to fixUnits.
252  this->readBUNIT(fname);
253
254  if(localwcs->spec>=0) this->fixUnits(par);
255
256  return SUCCESS;
257
258}
Note: See TracBrowser for help on using the repository browser.