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

Last change on this file since 508 was 508, checked in by MatthewWhiting, 16 years ago

Move the par.setOffsets call from getFITSdata to defineWCS, and fix up the allocation of arrays in getMetadata.

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