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

Last change on this file since 642 was 573, checked in by MatthewWhiting, 15 years ago

Fix related to ticket #56. I added a new call to wcsfix in wcsIO.cc that should tidy up any NCP-related issues. But the real bug was in plotting.cc, where the moment map was being calculated for blank channels as well. This meant that for the blank channels outside the universe, the transformation was being applied and causing the error. By limiting to only non-blank channels, we can avoid that.

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 <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    ///   A function that reads the WCS header information from the
50    ///    FITS file given by fname
51    ///   It will also sort out the spectral axis, and covert to the correct
52    ///    velocity type, or frequency type if need be.
53    ///   It calls FitsHeader::readBUNIT so that the Integrated Flux units can
54    ///    be calculated by FitsHeader::fixUnits.
55    /// \param fname Fits file to read.
56    /// \param par Param set to help fix the units with.
57
58    fitsfile *fptr;
59    int numAxes;
60    int noComments = 1; //so that fits_hdr2str will ignore COMMENT, HISTORY etc
61    int nExc = 0,nkeys;
62    char *hdr;
63
64    // Open the FITS file
65    int status = 0;
66    if( fits_open_file(&fptr,fname.c_str(),READONLY,&status) ){
67      fits_report_error(stderr, status);
68      return FAILURE;
69    }
70
71    // Get the dimensions of the FITS file -- number of axes and size of each.
72    status = 0;
73    if(fits_get_img_dim(fptr, &numAxes, &status)){
74      fits_report_error(stderr, status);
75      return FAILURE;
76    }
77    long *dimAxes = new long[numAxes];
78    for(int i=0;i<numAxes;i++) dimAxes[i]=1;
79    status = 0;
80    if(fits_get_img_size(fptr, numAxes, dimAxes, &status)){
81      fits_report_error(stderr, status);
82      return FAILURE;
83    }
84
85    // Read in the entire PHU of the FITS file to a std::string.
86    // This will be read by the wcslib functions to extract the WCS.
87    status = 0;
88    fits_hdr2str(fptr, noComments, NULL, nExc, &hdr, &nkeys, &status);
89    if( status ){
90      duchampWarning("Cube Reader",
91                     "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      duchampWarning("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      std::stringstream errmsg;
113      errmsg << "wcsini failed! Code=" << status
114             << ": " << wcs_errmsg[status] << std::endl;
115      duchampError("Cube Reader",errmsg.str());
116      return FAILURE;
117    }
118
119    this->naxis=0;
120    for(int i=0;i<numAxes;i++)
121      if(dimAxes[i]>1) this->naxis++;
122
123    int relax=1; // for wcspih -- admit all recognised informal WCS extensions
124    int ctrl=2;  // for wcspih -- report each rejected card and its reason for 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      // Set up the wcsprm struct. Report if something goes wrong.
151      status = wcsset(localwcs);
152      if(status){
153        std::stringstream errmsg;
154        errmsg<<"wcsset failed!\n"
155              <<"WCSLIB error code=" << status
156              <<": "<<wcs_errmsg[status] << std::endl;
157        duchampWarning("Cube Reader",errmsg.str());
158      }
159      else{
160
161        int stat[NWCSFIX];
162        // Re-do the corrections to account for things like NCP projections
163        status = wcsfix(1, (const int*)dimAxes, localwcs, stat);
164        if(status) {
165          std::stringstream errmsg;
166          errmsg << "wcsfix failed:\n";
167          errmsg << "Function status returns are:\n";
168          for(int i=0; i<NWCSFIX; i++)
169            if (stat[i] > 0)
170              errmsg << i+1 << ": WCSFIX error code=" << stat[i] << ": "
171                     << wcsfix_errmsg[stat[i]] << std::endl;
172          duchampWarning("Cube Reader", errmsg.str() );
173        }
174
175        if(localwcs->spec>=0){ //if there is a spectral axis
176
177          int index = localwcs->spec;
178          std::string desiredType,specType = localwcs->ctype[index];
179          std::string shortType = specType.substr(0,4);
180          if(shortType=="VELO" || shortType=="VOPT" || shortType=="ZOPT"
181             || shortType=="VRAD" || shortType=="BETA"){
182            if(localwcs->restfrq != 0){
183              // Set the spectral axis to a standard specification: VELO-F2V
184              desiredType = duchampVelocityType;
185              if(localwcs->restwav == 0)
186                localwcs->restwav = 299792458.0 /  localwcs->restfrq;
187              this->spectralDescription = duchampSpectralDescription[VELOCITY];
188            }
189            else{
190              // No rest frequency defined, so put spectral dimension in frequency.
191              // Set the spectral axis to a standard specification: FREQ
192              duchampWarning("Cube Reader",
193                             "No rest frequency defined. Using frequency units in spectral axis.\n");
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          else {
205            desiredType = duchampFrequencyType;
206            par.setSpectralUnits("MHz");
207            if(strcmp(localwcs->cunit[index],"")==0){
208              duchampWarning("Cube Reader",
209                             "No frequency unit given. Assuming frequency axis is in Hz.\n");
210              strcpy(localwcs->cunit[index],"Hz");
211            }
212            this->spectralDescription = duchampSpectralDescription[FREQUENCY];
213          }     
214
215          // Now we need to make sure the spectral axis has the correct setup.
216          //  We use wcssptr to translate it if it is not of the desired type,
217          //  or if the spectral units are not defined.
218
219          bool needToTranslate = false;
220
221          //       if(strncmp(specType.c_str(),desiredType.c_str(),4)!=0)
222          //    needToTranslate = true;
223
224          std::string blankstring = "";
225          if(strcmp(localwcs->cunit[localwcs->spec],blankstring.c_str())==0)
226            needToTranslate = true;
227
228          if(needToTranslate){
229
230            if(strcmp(localwcs->ctype[localwcs->spec],"VELO")==0)
231              strcpy(localwcs->ctype[localwcs->spec],"VELO-F2V");
232
233            index = localwcs->spec;
234       
235            status = wcssptr(localwcs, &index, (char *)desiredType.c_str());
236            if(status){
237              std::stringstream errmsg;
238              errmsg<< "WCSSPTR failed! Code=" << status << ": "
239                    << wcs_errmsg[status] << std::endl
240                    << "(wanted to convert from type \"" << specType
241                    << "\" to type \"" << desiredType << "\")\n";
242              duchampWarning("Cube Reader",errmsg.str());
243
244            }
245
246          }
247   
248        } // end of if(localwcs->spec>=0)
249        else if(localwcs->naxis>2){
250
251          par.setSpectralUnits( wcs->cunit[2] );
252          this->spectralDescription = wcs->ctype[2];
253
254        }
255         
256        // Save the wcs to the FitsHeader class that is running this function
257        this->setWCS(localwcs);
258        this->setNWCS(localnwcs);
259 
260        // Now that the WCS is defined, use it to set the offsets in the Param set
261        par.setOffsets(localwcs);
262
263      }
264    }
265
266    // work out whether the array is 2dimensional
267    if(localwcs->naxis==2) this->flag2D = true;
268    else{
269      int numDim=0;
270      for(int i=0;i<numAxes;i++) if(dimAxes[i]>1) numDim++;
271      this->flag2D = (numDim<=2);
272    }
273
274    // clean up allocated memory
275    wcsvfree(&localnwcs,&localwcs);
276    wcsfree(localwcs);
277    free(localwcs);
278    free(hdr);
279    delete [] dimAxes;
280
281    // Get the brightness unit, so that we can set the units for the
282    //  integrated flux when we go to fixUnits.
283    this->readBUNIT(fname);
284
285    if(this->wcs->spec>=0) this->fixUnits(par);
286
287    return SUCCESS;
288
289  }
290
291}
Note: See TracBrowser for help on using the repository browser.