source: trunk/src/Cubes/getImage.cc @ 965

Last change on this file since 965 was 945, checked in by MatthewWhiting, 12 years ago

Getting the warning/error reporting right when reading in the header keywords. Now we just proceed without triggering a failure, even if the BUNIT or beam information is
not present. And the absence of a BLANK keyword is only registered if we want to do trimming.

File size: 9.2 KB
Line 
1// -----------------------------------------------------------------------
2// getImage.cc: Read in a FITS file to a Cube object.
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 <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/param.hh>
42#include <duchamp/fitsHeader.hh>
43#include <duchamp/Cubes/cubes.hh>
44
45namespace duchamp
46{
47
48  std::string imageType[4] = {"point", "spectrum", "image", "cube"};
49
50  OUTCOME Cube::getMetadata()
51  { 
52    ///  @details
53    /// A front-end to the Cube::getMetadata() function, that does
54    ///  subsection checks. Does the flux unit conversion if the user
55    ///  has requested it. Assumes the Param is set up properly.
56
57    // int exists;
58    // fits_file_exists(fname.c_str(),&exists,&status);
59    // if(exists<=0){
60    //   fits_report_error(stderr, status);
61    //   DUCHAMPERROR("Cube Reader", Requested image (" << fname << ") does not exist!);
62    //   return FAILURE;
63    // }
64    if(this->par.checkImageExists() == FAILURE) return FAILURE;
65
66    std::string fname = par.getImageFile();
67    if(par.getFlagSubsection()) fname+=par.getSubsection();
68
69    OUTCOME result = getMetadata(fname);
70   
71    if(result==SUCCESS){
72      // Convert the flux Units if the user has so requested
73      this->convertFluxUnits(this->head.getFluxUnits(),this->par.getNewFluxUnits());
74    }
75
76    return result;
77  }
78  //--------------------------------------------------------------------
79
80  OUTCOME Cube::getMetadata(std::string fname)
81  {
82    /// @details
83    /// Read in the metadata associated with the cube from the file
84    ///  fname (assumed to be in FITS format).  Function is a front end
85    ///  to the I/O functions in the FitsIO/ directory.  This function
86    ///  will check that the file exists, report the dimensions and
87    ///  then get other functions to read the WCS and necessary header
88    ///  keywords. This function does not read in the data array --
89    ///  that is done by Cube::getCube(). Note that no conversion of
90    ///  flux units is done -- you need to call Cube::getMetadata() or
91    ///  do it separately.
92    ///  \param fname A std::string with name of FITS file.
93    ///  \return SUCCESS or FAILURE.
94
95    int numAxes, status = 0;  /* MUST initialize status */
96    fitsfile *fptr;         
97
98    // Open the FITS file -- make sure it exists
99    status = 0;
100    if( fits_open_file(&fptr,fname.c_str(),READONLY,&status) ){
101      fits_report_error(stderr, status);
102      if(((status==URL_PARSE_ERROR)||(status==BAD_NAXIS))
103         &&(this->pars().getFlagSubsection()))
104        DUCHAMPERROR("Cube Reader", "It may be that the subsection you've entered is invalid. Either it has the wrong number of axes, or one axis has too large a range.");
105      return FAILURE;
106    }
107
108    // Read the size information -- number and lengths of all axes.
109    // Just use this for reporting purposes.
110    status = 0;
111    if(fits_get_img_dim(fptr, &numAxes, &status)){
112      fits_report_error(stderr, status);
113      return FAILURE;
114    }
115    this->head.setNumAxes(numAxes);
116    long *dimAxes = new long[numAxes];
117    for(int i=0;i<numAxes;i++) dimAxes[i]=1;
118    status = 0;
119    if(fits_get_img_size(fptr, numAxes, dimAxes, &status)){
120      fits_report_error(stderr, status);
121      return FAILURE;
122    }
123
124    // Close the FITS file.
125    status = 0;
126    fits_close_file(fptr, &status);
127    if (status){
128      DUCHAMPWARN("Cube Reader","Error closing file: ");
129      fits_report_error(stderr, status);
130    }
131
132    // Report the size of the FITS file
133    if(this->par.isVerbose()){
134      std::cout << "Dimensions of FITS file: ";
135      int dim = 0;
136      std::cout << dimAxes[dim];
137      while(dim+1<numAxes) std::cout << "x" << dimAxes[++dim];
138      std::cout << std::endl;
139    }
140
141
142    // Get the WCS information
143    if(this->head.defineWCS(fname, this->par) == FAILURE) return FAILURE;
144
145    // Read the necessary header information, and copy some of it into the Param.
146    if(this->head.readHeaderInfo(fname, this->par) == FAILURE){
147      DUCHAMPWARN("Cube Reader", "Problems with metadata, but will press on...");
148    }
149
150    if(!this->head.isWCS())
151      DUCHAMPWARN("Cube Reader","WCS is not good enough to be used.\n");
152
153    // allocate the dimension array in the Cube.
154    if(this->initialiseCube(dimAxes,false) == FAILURE) return FAILURE;
155
156    delete [] dimAxes;
157
158    return SUCCESS;
159
160  }
161  //--------------------------------------------------------------------
162
163
164  OUTCOME Cube::getCube(std::string fname)
165  {
166    /// @details
167    /// Read in a cube from the file fname (assumed to be in FITS
168    ///  format).  Function is a front end to the data I/O function in
169    ///  the FitsIO/ directory.  This function calls the getMetadata()
170    ///  function, then reads in the actual data array.
171    ///  \param fname A std::string with name of FITS file.
172    ///  \return SUCCESS or FAILURE.
173
174    if(this->getMetadata(fname) == FAILURE) return FAILURE;
175
176    // Get the data array from the FITS file.
177    // Report the dimensions of the data array that was read (this can be
178    //   different to the full FITS array).
179    if(this->par.isVerbose()) std::cout << "Reading data ... "<<std::flush;
180    if(this->getFITSdata(fname) == FAILURE) return FAILURE;
181
182    if(this->axisDim[2] == 1){
183      this->par.setMinChannels(0);
184    }
185
186    if(this->par.isVerbose()){
187      std::cout << "Done. Data array has dimensions: ";
188      std::cout << this->axisDim[0];
189      if(this->axisDim[1]>1) std::cout  <<"x"<< this->axisDim[1];
190      if(this->axisDim[2]>1) std::cout  <<"x"<< this->axisDim[2];
191      std::cout << "\n";
192    }   
193
194    // Convert the flux Units if the user has so requested
195    this->convertFluxUnits(this->head.getFluxUnits(),this->par.getNewFluxUnits(),ARRAY);
196
197    return SUCCESS;   
198
199  }
200  //--------------------------------------------------------------------
201
202
203  void Cube::convertFluxUnits(std::string oldUnit, std::string newUnit, ARRAYREF whichArray)
204  {
205    /// @details
206    ///  If the user has requested new flux units (via the input
207    ///  parameter newFluxUnits), this function converts the units
208    ///  given by BUNIT to those given by newFluxUnits. If no simple
209    ///  conversion can be found (by using wcsunits()) then nothing is
210    ///  done and the user is informed, otherwise the
211    ///  FitsHeader::fluxUnits parameter is updated and the pixel array
212    ///  is converted accordingly.
213
214    //    if(this->par.getNewFluxUnits()!=""){
215    if(newUnit!=""){
216
217      // std::string oldUnit = this->head.getFluxUnits();
218      // std::string newUnit = this->par.getNewFluxUnits();
219
220      if(oldUnit != newUnit){
221
222        if(this->par.isVerbose()){
223          std::cout << "Converting flux units from " << oldUnit << " to " << newUnit << "... ";
224          std::cout << std::flush;
225        }
226
227        double scale,offset,power;
228        int status = wcsunits(oldUnit.c_str(), newUnit.c_str(), &scale, &offset, &power);
229
230        if(status==0){
231       
232          this->head.setFluxUnits( newUnit );
233          this->head.setIntFluxUnits();
234
235          if(whichArray == ARRAY){
236            if(this->arrayAllocated){
237              for(size_t i=0;i<this->numPixels;i++)
238                if(!this->isBlank(i)) this->array[i] = pow(scale * this->array[i] + offset, power);
239            }
240          }
241          else if(whichArray==RECON){
242            if(this->reconAllocated){
243              for(size_t i=0;i<this->numPixels;i++)
244                if(!this->isBlank(i)) this->recon[i] = pow(scale * this->recon[i] + offset, power);
245            }
246          }
247          else if(whichArray==BASELINE){
248            if(this->baselineAllocated){
249              for(size_t i=0;i<this->numPixels;i++)
250                if(!this->isBlank(i)) this->baseline[i] = pow(scale * this->baseline[i] + offset, power);
251            }
252          }
253          if(this->par.isVerbose()) {
254            std::cout << " Done.\n";
255          }
256        }
257        else{
258          if(this->par.isVerbose()) std::cout << "\n";
259          DUCHAMPWARN("convertFluxUnits", "Could not convert units from " << oldUnit << " to " << newUnit << ". Leaving BUNIT as " << oldUnit);
260        }
261      }
262    }
263
264  }
265
266
267}
Note: See TracBrowser for help on using the repository browser.