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

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

A bunch of changes aimed at streamlining the FITS file access at the start, particularly for the case of large images where we access a subsection (this can be slow to access). We now only open the file once, and keep the fitsfile pointer in the FitsHeader? class. Once the image access is finished the file is closed.

File size: 10.7 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    this->head.openFITS(fname);
70
71    OUTCOME result = getMetadata(fname);
72   
73    if(result==SUCCESS){
74      // Convert the flux Units if the user has so requested
75      this->convertFluxUnits(this->head.getFluxUnits(),this->par.getNewFluxUnits());
76    }
77
78    this->head.closeFITS();
79
80    return result;
81  }
82  //--------------------------------------------------------------------
83
84  OUTCOME Cube::getMetadata(std::string fname)
85  {
86    /// @details
87    /// Read in the metadata associated with the cube from the file
88    ///  fname (assumed to be in FITS format).  Function is a front end
89    ///  to the I/O functions in the FitsIO/ directory.  This function
90    ///  will check that the file exists, report the dimensions and
91    ///  then get other functions to read the WCS and necessary header
92    ///  keywords. This function does not read in the data array --
93    ///  that is done by Cube::getCube(). Note that no conversion of
94    ///  flux units is done -- you need to call Cube::getMetadata() or
95    ///  do it separately.
96    ///  \param fname A std::string with name of FITS file.
97    ///  \return SUCCESS or FAILURE.
98
99    int numAxes, status = 0;  /* MUST initialize status */
100    fitsfile *fptr;         
101
102    // // Open the FITS file -- make sure it exists
103    // std::cerr << "Opening file...";
104    // system("date");
105    // status = 0;
106    // if( fits_open_file(&fptr,fname.c_str(),READONLY,&status) ){
107    //   fits_report_error(stderr, status);
108    //   if(((status==URL_PARSE_ERROR)||(status==BAD_NAXIS))
109    //   &&(this->pars().getFlagSubsection()))
110    //  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.");
111    //   return FAILURE;
112    // }
113
114    // std::cerr << " ..Done. Now reading number of dims...";
115    std::cerr << "Now reading number of dims...";
116    system("date");
117    // Read the size information -- number and lengths of all axes.
118    // Just use this for reporting purposes.
119    status = 0;
120    // if(fits_get_img_dim(fptr, &numAxes, &status)){
121    if(fits_get_img_dim(this->head.FPTR(), &numAxes, &status)){
122      fits_report_error(stderr, status);
123      return FAILURE;
124    }
125    std::cerr << " ..Done. Now reading axis sizes...";
126    system("date");
127    this->head.setNumAxes(numAxes);
128    long *dimAxes = new long[numAxes];
129    for(int i=0;i<numAxes;i++) dimAxes[i]=1;
130    status = 0;
131    // if(fits_get_img_size(fptr, numAxes, dimAxes, &status)){
132    if(fits_get_img_size(this->head.FPTR(), numAxes, dimAxes, &status)){
133      fits_report_error(stderr, status);
134      return FAILURE;
135    }
136
137    // Report the size of the FITS file
138    if(this->par.isVerbose()){
139      std::cout << "Dimensions of FITS file: ";
140      int dim = 0;
141      std::cout << dimAxes[dim];
142      while(dim+1<numAxes) std::cout << "x" << dimAxes[++dim];
143      std::cout << std::endl;
144    }
145
146
147    // Get the WCS information
148    std::cerr << "Reading WCS info...";
149    system("date");
150    // if(this->head.defineWCS(fname, this->par) == FAILURE) return FAILURE;
151    // if(this->head.defineWCS(fptr, this->par) == FAILURE) return FAILURE;
152    // if(this->head.defineWCS(this->head.FPTR(), this->par) == FAILURE) return FAILURE;
153    if(this->head.defineWCS(this->par) == FAILURE) return FAILURE;
154    std::cerr << "  ..Done.\n";
155
156    // Read the necessary header information, and copy some of it into the Param.
157    std::cerr << "Reading header info...";
158    system("date");
159    // if(this->head.readHeaderInfo(fname, this->par) == FAILURE){
160    // if(this->head.readHeaderInfo(fptr, this->par) == FAILURE){
161    // if(this->head.readHeaderInfo(this->head.FPTR(), this->par) == FAILURE){
162    if(this->head.readHeaderInfo(this->par) == FAILURE){
163     DUCHAMPWARN("Cube Reader", "Problems with metadata, but will press on...");
164    }
165    std::cerr << " ..Done.\n";
166    system("date");
167
168    if(!this->head.isWCS())
169      DUCHAMPWARN("Cube Reader","WCS is not good enough to be used.\n");
170
171    // std::cerr << " ..Done. Now closing file.\n";
172    // system("date");
173    // Close the FITS file.
174    // status = 0;
175    // fits_close_file(fptr, &status);
176    // if (status){
177    //   DUCHAMPWARN("Cube Reader","Error closing file: ");
178    //   fits_report_error(stderr, status);
179    // }
180
181    // allocate the dimension array in the Cube.
182    if(this->initialiseCube(dimAxes,false) == FAILURE) return FAILURE;
183
184    delete [] dimAxes;
185
186    return SUCCESS;
187
188  }
189  //--------------------------------------------------------------------
190
191
192  OUTCOME Cube::getCube(std::string fname)
193  {
194    /// @details
195    /// Read in a cube from the file fname (assumed to be in FITS
196    ///  format).  Function is a front end to the data I/O function in
197    ///  the FitsIO/ directory.  This function calls the getMetadata()
198    ///  function, then reads in the actual data array.
199    ///  \param fname A std::string with name of FITS file.
200    ///  \return SUCCESS or FAILURE.
201
202    std::cerr << "Opening file...";
203    system("date");
204    this->head.openFITS(fname);
205
206    if(this->getMetadata(fname) == FAILURE) return FAILURE;
207
208    // Get the data array from the FITS file.
209    // Report the dimensions of the data array that was read (this can be
210    //   different to the full FITS array).
211    if(this->par.isVerbose()) std::cout << "Reading data ... "<<std::flush;
212    // if(this->getFITSdata(fname) == FAILURE) return FAILURE;
213    // if(this->getFITSdata(this->head.FPTR()) == FAILURE) return FAILURE;
214    if(this->getFITSdata() == FAILURE) return FAILURE;
215
216    if(this->axisDim[2] == 1){
217      this->par.setMinChannels(0);
218    }
219
220    if(this->par.isVerbose()){
221      std::cout << "Done. Data array has dimensions: ";
222      std::cout << this->axisDim[0];
223      if(this->axisDim[1]>1) std::cout  <<"x"<< this->axisDim[1];
224      if(this->axisDim[2]>1) std::cout  <<"x"<< this->axisDim[2];
225      std::cout << "\n";
226    }   
227
228    // Convert the flux Units if the user has so requested
229    this->convertFluxUnits(this->head.getFluxUnits(),this->par.getNewFluxUnits(),ARRAY);
230
231    std::cerr << " ..Done. Now closing file.\n";
232    system("date");
233    this->head.closeFITS();
234
235    return SUCCESS;   
236
237  }
238  //--------------------------------------------------------------------
239
240
241  void Cube::convertFluxUnits(std::string oldUnit, std::string newUnit, ARRAYREF whichArray)
242  {
243    /// @details
244    ///  If the user has requested new flux units (via the input
245    ///  parameter newFluxUnits), this function converts the units
246    ///  given by BUNIT to those given by newFluxUnits. If no simple
247    ///  conversion can be found (by using wcsunits()) then nothing is
248    ///  done and the user is informed, otherwise the
249    ///  FitsHeader::fluxUnits parameter is updated and the pixel array
250    ///  is converted accordingly.
251
252    //    if(this->par.getNewFluxUnits()!=""){
253    if(newUnit!=""){
254
255      // std::string oldUnit = this->head.getFluxUnits();
256      // std::string newUnit = this->par.getNewFluxUnits();
257
258      if(oldUnit != newUnit){
259
260        if(this->par.isVerbose()){
261          std::cout << "Converting flux units from " << oldUnit << " to " << newUnit << "... ";
262          std::cout << std::flush;
263        }
264
265        double scale,offset,power;
266        int status = wcsunits(oldUnit.c_str(), newUnit.c_str(), &scale, &offset, &power);
267
268        if(status==0){
269       
270          this->head.setFluxUnits( newUnit );
271          this->head.setIntFluxUnits();
272
273          if(whichArray == ARRAY){
274            if(this->arrayAllocated){
275              for(size_t i=0;i<this->numPixels;i++)
276                if(!this->isBlank(i)) this->array[i] = pow(scale * this->array[i] + offset, power);
277            }
278          }
279          else if(whichArray==RECON){
280            if(this->reconAllocated){
281              for(size_t i=0;i<this->numPixels;i++)
282                if(!this->isBlank(i)) this->recon[i] = pow(scale * this->recon[i] + offset, power);
283            }
284          }
285          else if(whichArray==BASELINE){
286            if(this->baselineAllocated){
287              for(size_t i=0;i<this->numPixels;i++)
288                if(!this->isBlank(i)) this->baseline[i] = pow(scale * this->baseline[i] + offset, power);
289            }
290          }
291          if(this->par.isVerbose()) {
292            std::cout << " Done.\n";
293          }
294        }
295        else{
296          if(this->par.isVerbose()) std::cout << "\n";
297          DUCHAMPWARN("convertFluxUnits", "Could not convert units from " << oldUnit << " to " << newUnit << ". Leaving BUNIT as " << oldUnit);
298        }
299      }
300    }
301
302  }
303
304
305}
Note: See TracBrowser for help on using the repository browser.