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

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

Getting the spectral units conversion working properly:

  • Changing the default to be ""
  • Renaming fixUnits to fixSpectralUnits and changing its interface (it just accepts a string now as a parameter)
  • Simplifying the error handling
  • Getting the ordering of checking spectral types and the translation right. We now check the spectral type (when trying to translate) before adding the ?s
File size: 11.5 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      DUCHAMPWARN("Cube Reader","Error whilst reading FITS header to string: ");
92      fits_report_error(stderr, status);
93      return FAILURE;
94    }
95
96    // Close the FITS file -- not needed any more in this function.
97    status = 0;
98    fits_close_file(fptr, &status);
99    if (status){
100      DUCHAMPWARN("Cube Reader","Error closing file: ");
101      fits_report_error(stderr, status);
102    }
103 
104    // Define a temporary, local version of the WCS
105    struct wcsprm *localwcs;
106    localwcs = (struct wcsprm *)calloc(1,sizeof(struct wcsprm));
107    localwcs->flag=-1;
108
109    // Initialise this temporary wcsprm structure
110    status = wcsini(true, numAxes, localwcs);
111    if(status){
112      DUCHAMPERROR("Cube Reader","wcsini failed! Code=" << status << ": " << wcs_errmsg[status]);
113      return FAILURE;
114    }
115
116    this->naxis=0;
117    for(int i=0;i<numAxes;i++)
118      if(dimAxes[i]>1) this->naxis++;
119
120    int relax=1; // for wcspih -- admit all recognised informal WCS extensions
121    int ctrl=2;  // for wcspih -- report each rejected card and its reason for rejection
122    int localnwcs, nreject;
123    // Parse the FITS header to fill in the wcsprm structure
124    status=wcspih(hdr, nkeys, relax, ctrl, &nreject, &localnwcs, &localwcs);
125    if(status){
126      // if here, something went wrong -- report what.
127      DUCHAMPWARN("Cube Reader","wcspih failed!\nWCSLIB error code=" << status << ": " << wcs_errmsg[status]);
128    }
129    else{ 
130      int stat[NWCSFIX];
131      // Applies all necessary corrections to the wcsprm structure
132      //  (missing cards, non-standard units or spectral types, ...)
133      status = wcsfix(1, (const int*)dimAxes, localwcs, stat);
134      if(status) {
135        std::stringstream errmsg;
136        errmsg << "wcsfix failed with function status returns of:\n";
137        for(int i=0; i<NWCSFIX; i++)
138          if (stat[i] > 0)
139            errmsg << i+1 << ": WCSFIX error code=" << stat[i] << ": "
140                   << wcsfix_errmsg[stat[i]] << std::endl;
141        DUCHAMPWARN("Cube Reader", errmsg);
142      }
143      // Set up the wcsprm struct. Report if something goes wrong.
144      status = wcsset(localwcs);
145      if(status){
146        DUCHAMPWARN("Cube Reader","wcsset failed with error code=" << status <<": "<<wcs_errmsg[status]);
147      }
148      else{
149
150        int stat[NWCSFIX];
151        // Re-do the corrections to account for things like NCP projections
152        status = wcsfix(1, (const int*)dimAxes, localwcs, stat);
153        if(status) {
154          std::stringstream errmsg;
155          errmsg << "wcsfix failed with function status returns of:\n";
156          for(int i=0; i<NWCSFIX; i++)
157            if (stat[i] > 0)
158              errmsg << i+1 << ": WCSFIX error code=" << stat[i] << ": "
159                     << wcsfix_errmsg[stat[i]] << std::endl;
160          DUCHAMPWARN("Cube Reader", errmsg );
161        }
162
163//      if(localwcs->spec>=0){ //if there is a spectral axis
164
165//        int index = localwcs->spec;
166//        std::string desiredType="",specType = localwcs->ctype[index];
167//        std::string shortType = specType.substr(0,4);
168//        if(shortType=="VELO" || shortType=="VOPT" || shortType=="ZOPT"
169//           || shortType=="VRAD" || shortType=="BETA"){
170//          if(localwcs->restfrq != 0){
171//            // Set the spectral axis to a standard specification: VELO-F2V
172//            desiredType = duchampVelocityType;
173//            if(localwcs->restwav == 0)
174//              localwcs->restwav = 299792458.0 /  localwcs->restfrq;
175//            this->spectralDescription = duchampSpectralDescription[VELOCITY];
176//          }
177//          else{
178//            // No rest frequency defined, so just use given specification
179//            desiredType = specType;
180//            this->spectralDescription = duchampSpectralDescription[VELOCITY];
181//          }
182//        }
183//        else if (shortType=="FREQ" && localwcs->restfrq!=0){
184//          // No rest frequency defined, so put spectral dimension in frequency.
185//          // Set the spectral axis to a standard specification: FREQ
186//          DUCHAMPWARN("Cube Reader", "No rest frequency defined. Using frequency units in spectral axis.");
187//          desiredType = duchampFrequencyType;
188//          par.setSpectralUnits("MHz");
189//          if(strcmp(localwcs->cunit[index],"")==0){
190//            DUCHAMPWARN("Cube Reader", "No frequency unit given. Assuming frequency axis is in Hz.");
191//            strcpy(localwcs->cunit[index],"Hz");
192//          }
193//          this->spectralDescription = duchampSpectralDescription[FREQUENCY];
194//        }
195//        else {
196//          desiredType = duchampFrequencyType;
197//          par.setSpectralUnits("MHz");
198//          if(strcmp(localwcs->cunit[index],"")==0){
199//            DUCHAMPWARN("Cube Reader", "No frequency unit given. Assuming frequency axis is in Hz.");
200//            strcpy(localwcs->cunit[index],"Hz");
201//          }
202//          this->spectralDescription = duchampSpectralDescription[FREQUENCY];
203//        }     
204
205//        // Now we need to make sure the spectral axis has the correct setup.
206//        //  We use wcssptr to translate it if it is not of the desired type,
207//        //  or if the spectral units are not defined.
208
209//        bool needToTranslate = false;
210
211//        if(strncmp(specType.c_str(),desiredType.c_str(),4)!=0)
212//          needToTranslate = true;
213
214//        std::string blankstring = "";
215//        if(strcmp(localwcs->cunit[localwcs->spec],blankstring.c_str())==0)
216//          needToTranslate = true;
217
218//        if(needToTranslate){
219
220//          if(strcmp(localwcs->ctype[localwcs->spec],"VELO")==0)
221//            strcpy(localwcs->ctype[localwcs->spec],"VELO-F2V");
222
223//          index = localwcs->spec;
224       
225//          status = wcssptr(localwcs, &index, (char *)desiredType.c_str());
226//          if(status){
227//            DUCHAMPWARN("Cube Reader","WCSSPTR failed when converting from type \"" << specType << "\" to type \"" << desiredType << " with code=" << status << ": " << wcs_errmsg[status]);
228//          }
229
230//        }
231   
232//      } // end of if(localwcs->spec>=0)
233//      else if(localwcs->naxis>2){
234
235//        par.setSpectralUnits( wcs->cunit[2] );
236//        this->spectralDescription = wcs->ctype[2];
237
238//      }
239
240        char stype[5],scode[5],sname[22],units[8],ptype,xtype;
241        int restreq;
242        struct wcserr *err;
243
244        if(par.getSpectralType()!=""){ // User wants to convert the spectral type
245
246          std::string desiredType = par.getSpectralType();
247         
248          status = spctype((char *)desiredType.c_str(),stype,scode,sname,units,&ptype,&xtype,&restreq,&err);
249          if(status){
250            DUCHAMPERROR("Cube Reader", "Spectral type " << desiredType << " is not a valid spectral type. No translation done.");
251          }
252          else{
253
254          if(desiredType.size()<4){
255            DUCHAMPERROR("Cube Reader", "Spectral Type " << desiredType << " requested, but this is too short. No translation done");
256          }
257          else{
258            if(desiredType.size()<8){
259              if(desiredType.size()==4) desiredType+="-???";
260              else while (desiredType.size()<8) desiredType+="?";
261            }
262          }
263            //    std::cerr << "User requested type " << par.getSpectralType() << " which we interpret as " << desiredType << "\n";
264            if(par.getRestFrequency()>0.){
265              //            std::cerr << "Changing rest frequency from " << localwcs->restfrq << " to " << par.getRestFrequency() <<"\n";
266              localwcs->restfrq = par.getRestFrequency();
267            }
268            status = wcssptr(localwcs, &(localwcs->spec), (char *)desiredType.c_str());
269            if(status){
270              DUCHAMPWARN("Cube Reader","WCSSPTR failed when converting from type \"" << localwcs->ctype[localwcs->spec]
271                          << "\" to type \"" << desiredType << " with code=" << status << ": " << wcs_errmsg[status]);
272            }
273            else if(par.getRestFrequency()>0.) par.setFlagRestFrequencyUsed(true);
274
275
276          }
277
278        }
279
280         
281        status = spctype(localwcs->ctype[localwcs->spec],stype,scode,sname,units,&ptype,&xtype,&restreq,&err);
282//      std::cerr << localwcs->ctype[localwcs->spec] << " --> " << stype << "|" << scode << "|" << sname << "|"
283//                << units << "|" << ptype << "|" << xtype << "|" << restreq << "\n";
284
285        this->spectralType  = stype;
286        this->spectralDescription = sname;
287
288        // Save the wcs to the FitsHeader class that is running this function
289        this->setWCS(localwcs);
290        this->setNWCS(localnwcs);
291 
292        // Now that the WCS is defined, use it to set the offsets in the Param set
293        par.setOffsets(localwcs);
294
295      }
296    }
297
298    // work out whether the array is 2dimensional
299    if(localwcs->naxis==2) this->flag2D = true;
300    else{
301      int numDim=0;
302      for(int i=0;i<numAxes;i++) if(dimAxes[i]>1) numDim++;
303      this->flag2D = (numDim<=2);
304    }
305
306    // clean up allocated memory
307    wcsvfree(&localnwcs,&localwcs);
308    wcsfree(localwcs);
309    free(localwcs);
310    free(hdr);
311    delete [] dimAxes;
312
313    return SUCCESS;
314
315  }
316
317}
Note: See TracBrowser for help on using the repository browser.