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

Last change on this file since 864 was 864, checked in by MatthewWhiting, 13 years ago

Fixing the logic in the testing of the spectral-axis type. If the axis is velocity but there is no rest frequency, then we can't convert to frequency as I've been doing! Instead we just use the type from the image, rather than some standard.

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