source: trunk/src/Cubes/saveImage.cc @ 946

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

Moving the writing of the mask cube to outside the if(!cube->pars().getFlagUsePrevious()) loop. This way we can change the specification of the mask without needing to
re-do the preprocessing & searching. Also changed the interface to getMomenMap, so that it returns the bool mask rather than taking it as a parameter.

File size: 20.5 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// saveImage.cc: Write a wavelet-reconstructed or smoothed array to a
3//               FITS file.
4// -----------------------------------------------------------------------
5// Copyright (C) 2006, Matthew Whiting, ATNF
6//
7// This program is free software; you can redistribute it and/or modify it
8// under the terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// Duchamp is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15// for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with Duchamp; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20//
21// Correspondence concerning Duchamp may be directed to:
22//    Internet email: Matthew.Whiting [at] atnf.csiro.au
23//    Postal address: Dr. Matthew Whiting
24//                    Australia Telescope National Facility, CSIRO
25//                    PO Box 76
26//                    Epping NSW 1710
27//                    AUSTRALIA
28// -----------------------------------------------------------------------
[3]29#include <iostream>
30#include <sstream>
31#include <string>
[643]32#include <string.h>
[394]33#include <wcslib/wcs.h>
34#include <wcslib/wcshdr.h>
[757]35#include <wcslib/wcsunits.h>
[146]36#define WCSLIB_GETWCSTAB
37// define this so that we don't try and redefine wtbarr
38// (this is a problem when using cfitsio v.3 and g++ v.4)
39
[66]40#include <fitsio.h>
[393]41#include <duchamp/duchamp.hh>
42#include <duchamp/Cubes/cubes.hh>
43#include <duchamp/PixelMap/Voxel.hh>
44#include <duchamp/PixelMap/Object3D.hh>
[3]45
[378]46namespace duchamp
[208]47{
48
[528]49  /// @brief Write FITS headers in correct format for reconstructed array output
[378]50  void writeReconHeaderInfo(fitsfile *fptr, Param &par, std::string nature);
[208]51
[528]52  /// @brief Write FITS headers in correct format for smoothed array output
[378]53  void writeSmoothHeaderInfo(fitsfile *fptr, Param &par);
[208]54
[528]55  /// @brief Write FITS headers in correct format for mask array output
[379]56  void writeMaskHeaderInfo(fitsfile *fptr, Param &par);
[670]57
58  /// @brief Write FITS headers in correct format for moment-0 array output
59  void writeMomentMapHeaderInfo(fitsfile *fptr, Param &par);
60
[379]61  //---------------------------------------------------------------------------
62
[670]63
[695]64  void duchampFITSerror(int status, std::string subroutine, std::string error)
[670]65  {
[695]66    if(status){
[913]67      DUCHAMPWARN(subroutine,error);
[695]68      fits_report_error(stderr, status);
69    }
70  }
71
72
73  OUTCOME Cube::saveMomentMapImage()
74  {
[670]75    /// @details
76    ///  A function to save the moment-0 map to a FITS file.
77   
78    int newbitpix = FLOAT_IMG;
[902]79    long *fpixel = new long[this->head.WCS().naxis];
80    for(int i=0;i<this->header().WCS().naxis;i++) fpixel[i]=1;
[670]81    int status = 0;  /* MUST initialize status */
82    fitsfile *fptr;         
83
84    std::string fileout = "!" + this->par.outputMomentMapFile();
85    // the ! is there so that it writes over an existing file.
86
87    status = 0;
[695]88    if(fits_create_file(&fptr,fileout.c_str(),&status)){
89      duchampFITSerror(status,"saveMomentMapImage","Error creating file:");
90      return FAILURE;
[670]91    }
92    else {
93
[902]94      if(this->writeBasicHeader(fptr, newbitpix,true)==FAILURE){
[913]95        DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[902]96        return FAILURE;
[670]97      }
98
99      writeMomentMapHeaderInfo(fptr, this->par);
100       
101      long size = this->axisDim[0] * this->axisDim[1];
102      float *momentMap = new float[size];
[946]103      std::vector<bool> detectionMap = this->getMomentMap(momentMap);
[670]104      status=0;
105      if(fits_write_pix(fptr, TFLOAT, fpixel, size, momentMap, &status)){
[695]106        duchampFITSerror(status,"saveMomentMapImage","Error writing data");
[670]107      }
108      status = 0;
109      if(fits_close_file(fptr, &status)){
[695]110        duchampFITSerror(status,"saveMomentMapImage","Error closing file");
[670]111      }
112
113      delete [] momentMap;
114
115    }
116
117    delete [] fpixel;
118
[695]119    return SUCCESS;
[670]120
121  }
122
[695]123  OUTCOME Cube::saveMaskCube()
[379]124  {
[528]125    /// @details
126    ///  A function to save a mask to a FITS file, indicating where the
127    ///  detections where made. The value of the detected pixels is
128    ///  determined by the flagMaskWithObjectNum parameter: if true,
129    ///  the value of the pixels is given by the corresponding object
130    ///  ID number; if false, they take the value 1 for all
131    ///  objects. Pixels not in a detected object have the value 0.
[379]132
133    int newbitpix = SHORT_IMG;
[643]134    char *comment = new char[FLEN_COMMENT];
[644]135    strcpy(comment,"");
[902]136    long *fpixel = new long[this->head.WCS().naxis];
[385]137    for(int i=0;i<this->header().WCS().naxis;i++) fpixel[i]=1;
[379]138    int status = 0;  /* MUST initialize status */
[900]139    fitsfile *fptrNew;         
[379]140
141    std::string fileout = "!" + this->par.outputMaskFile();
142    // the ! is there so that it writes over an existing file.
143
144    status = 0;
[695]145    if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
146      duchampFITSerror(status,"saveMask","Error creating file:");
147      return FAILURE;
[379]148    }
149    else {
[900]150      if(this->writeBasicHeader(fptrNew, newbitpix)==FAILURE){
[913]151        DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[695]152        return FAILURE;
[379]153      }
[900]154
155      writeMaskHeaderInfo(fptrNew, this->par);
156
[902]157      char *keyword = new char[FLEN_KEYWORD];
[521]158      std::string newunits;
159      if(this->par.getFlagMaskWithObjectNum())
160        newunits = "Object ID";
161      else
162        newunits = "Detection flag";
[644]163      strcpy(keyword,"BUNIT");
[695]164      if(fits_update_key(fptrNew, TSTRING, keyword, (char *)newunits.c_str(), comment, &status)){
165        duchampFITSerror(status,"saveMask","Error writing BUNIT header:");
[521]166      }
[379]167
168      delete [] comment;
[661]169      delete [] keyword;
[379]170       
171      short *mask = new short[this->numPixels];
[894]172      for(size_t i=0;i<this->numPixels;i++) mask[i]=0;
[623]173      std::vector<Detection>::iterator obj;
174      for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
175        std::vector<PixelInfo::Voxel> voxlist = obj->getPixelSet();
176        std::vector<PixelInfo::Voxel>::iterator vox;
177        for(vox=voxlist.begin();vox<voxlist.end();vox++){
[920]178          size_t pixelpos = vox->getX() + this->axisDim[0]*vox->getY() +
[623]179            this->axisDim[0]*this->axisDim[1]*vox->getZ();
180          if(this->par.getFlagMaskWithObjectNum()) mask[pixelpos] = obj->getID();
[521]181          else mask[pixelpos] = 1;
[379]182        }
183      }
184      status=0;
[695]185      if(fits_write_pix(fptrNew, TSHORT, fpixel, this->numPixels, mask, &status)){
186        duchampFITSerror(status,"saveMask","Error writing mask array:");
[379]187      }
188      status = 0;
[695]189      if(fits_close_file(fptrNew, &status)){
190        duchampFITSerror(status,"saveMask","Error closing file:");
[379]191      }
192
193      delete [] mask;
194
195    }
196
197    delete [] fpixel;
198
[695]199    return SUCCESS;
[379]200  }
201 
202  //---------------------------------------------------------------------------
203
[695]204  OUTCOME Cube::saveSmoothedCube()
[378]205  {
[528]206    /// @brief
207    ///   A function to save the smoothed arrays to a FITS file.
208    ///   Additional header keywords are written as well, indicating the
209    ///   width of the Hanning filter or the dimensions of the Gaussian
210    ///   kernel.
211    ///   The file is always written -- if the filename (as calculated
212    ///    based on the parameters) exists, then it is overwritten.
[3]213 
[378]214    float blankval = this->par.getBlankPixVal();
[3]215
[378]216    int status = 0;  /* MUST initialize status */
[900]217    fitsfile *fptrNew;         
[695]218
[378]219    if(this->par.getFlagOutputSmooth()){
220      std::string fileout = "!" + this->par.outputSmoothFile();
221      // the ! is there so that it writes over an existing file.
[3]222
[378]223      status = 0;
[695]224      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
225        duchampFITSerror(status,"saveSmoothedCube","Error creating smoothed FITS file:");
226        return FAILURE;
227      }
[378]228      else {
[46]229
[900]230          if(this->writeBasicHeader(fptrNew, -32)==FAILURE){
[913]231            DUCHAMPWARN("write Smoothed Cube", "Failure writing to header");
[900]232            return FAILURE;
233          }
234
[378]235        writeSmoothHeaderInfo(fptrNew, this->par);
[3]236
[103]237        if(this->par.getFlagBlankPix())
[578]238          fits_write_imgnull(fptrNew, TFLOAT, 1, this->numPixels, this->recon, &blankval, &status);
239        else
240          fits_write_img(fptrNew, TFLOAT, 1, this->numPixels, this->recon, &status);
[695]241        if(status){
242          duchampFITSerror(status,"saveSmothedCube","Error writing smoothed array:");
243          return FAILURE;
244        }
[3]245
[103]246        status = 0;
[695]247        if(fits_close_file(fptrNew, &status)){
248          duchampFITSerror(status,"saveSmoothedCube","Error closing file:");
249        }
[103]250      }
[378]251    }
252
[695]253    return SUCCESS;
254
[3]255  }
256
[379]257  //---------------------------------------------------------------------------
[103]258
[695]259  OUTCOME Cube::saveReconstructedCube()
[378]260  {
[528]261    /// @details
262    ///  A function to save the reconstructed and/or residual arrays.
263    ///   A number of header keywords are written as well, indicating the
264    ///    nature of the reconstruction that has been done.
265    ///   The file is always written -- if the filename (as calculated
266    ///    based on the recon parameters) exists, then it is overwritten.
[378]267 
268    float blankval = this->par.getBlankPixVal();
[71]269
[757]270    if(!this->reconAllocated){
[913]271      DUCHAMPERROR("saveReconCube","Have not allocated reconstructed array, so cannot save");
[757]272      return FAILURE;
273    }
274
[378]275    int status = 0;  /* MUST initialize status */
[900]276    fitsfile *fptrNew;         
[378]277 
278    if(this->par.getFlagOutputRecon()){
279      std::string fileout = "!" + this->par.outputReconFile();
280      // the ! is there so that it writes over an existing file.
281
282      status = 0;
[695]283      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
284        duchampFITSerror(status,"saveReconCube","Error creating file:");
285        return FAILURE;
286      }
[378]287      else
288        {
[900]289
290          if(this->writeBasicHeader(fptrNew, -32)==FAILURE){
[913]291            DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[695]292            return FAILURE;
293          }
[900]294         
[378]295          writeReconHeaderInfo(fptrNew, this->par, "recon");
296
[757]297          status=0;
[767]298          long *fpixel = new long[this->header().WCS().naxis];
[757]299          for(int i=0;i<this->numDim;i++) fpixel[i]=1;
300          long group=0;
[378]301          if(this->par.getFlagBlankPix())
[757]302            fits_write_imgnull_flt(fptrNew, group, 1, this->numPixels, this->recon, blankval, &status);
[578]303          else 
[757]304            fits_write_img_flt(fptrNew, group, 1, this->numPixels, this->recon, &status);
[695]305          if(status){
306            duchampFITSerror(status,"saveReconCube","Error writing reconstructed array:");
307            return FAILURE;
308          }
[757]309          delete [] fpixel;
[378]310
311          status = 0;
[695]312          if(fits_close_file(fptrNew, &status)){
313            duchampFITSerror(status,"saveReconCube","Error closing file:");
314          }
[103]315        }
[378]316    }
[3]317
[71]318
[378]319    if(this->par.getFlagOutputResid()){
[578]320      float *resid = new float[this->numPixels];
[894]321      for(size_t i=0;i<this->numPixels;i++)
[578]322        resid[i] = this->array[i] - this->recon[i];
323
[378]324      std::string fileout = "!" + this->par.outputResidFile();
325      // the ! is there so that it writes over an existing file.
326      status = 0;
[695]327      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
328        duchampFITSerror(status,"saveResidualCube","Error creating new file:");
329        return FAILURE;
330      }
[378]331      else
332        {
[900]333
334          if(this->writeBasicHeader(fptrNew, -32)==FAILURE){
[913]335            DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[695]336            return FAILURE;
337          }
[900]338
[378]339          writeReconHeaderInfo(fptrNew, this->par, "resid");
[71]340
[378]341          if(this->par.getFlagBlankPix())
[578]342            fits_write_imgnull(fptrNew, TFLOAT, 1, this->numPixels, resid, &blankval, &status);
343          else 
344            fits_write_img(fptrNew, TFLOAT, 1, this->numPixels, resid, &status);
[695]345          if(status){
346            duchampFITSerror(status,"saveResidualCube","Error writing reconstructed array:");
347            return FAILURE;
348          }
[71]349
[695]350          status=0;
351          if(fits_close_file(fptrNew, &status)){
352            duchampFITSerror(status,"saveResidualCube","Error closing file:");
353          }
[378]354        }
[578]355      delete [] resid;
[378]356    }
[86]357
[695]358    return SUCCESS;
[378]359  }
[71]360
[379]361  //---------------------------------------------------------------------------
[378]362
363  void writeReconHeaderInfo(fitsfile *fptr, Param &par, std::string nature)
364  {
[528]365    /// @details
366    ///   A simple function that writes all the necessary keywords and comments
367    ///    to the FITS header pointed to by fptr.
368    ///   The keyword names and comments are taken from duchamp.hh
369    ///   The parameter "nature" indicates what type of file is being written:
370    ///    should be either "recon" or "resid".
[378]371
372    int status = 0;
373    std::string explanation = "",ReconResid="";
374
375    fits_write_history(fptr, (char *)header_reconHistory1.c_str(), &status);
[71]376                                   
[378]377    fits_write_history(fptr, (char *)header_reconHistory2.c_str(), &status);
[71]378
[378]379    fits_write_history(fptr, (char *)header_reconHistory_input.c_str(), &status);
[71]380
[378]381    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
[105]382
[378]383    if(par.getFlagSubsection()){
384      fits_write_comment(fptr,(char *)header_reconSubsection_comment.c_str(),
385                         &status);
386      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
387                     (char *)par.getSubsection().c_str(),
388                     (char *)comment_subsection.c_str(), &status);
389    }
[105]390   
[378]391    fits_write_comment(fptr, (char *)header_atrous_comment.c_str(), &status);
[105]392
[378]393    float valf = par.getAtrousCut();
394    fits_write_key(fptr, TFLOAT, (char *)keyword_snrRecon.c_str(), &valf,
395                   (char *)comment_snrRecon.c_str(), &status);
[71]396
[378]397    int vali = par.getReconDim();
398    fits_write_key(fptr, TINT, (char *)keyword_reconDim.c_str(), &vali,
399                   (char *)comment_reconDim.c_str(), &status);
[103]400
[378]401    vali = par.getMinScale();
402    fits_write_key(fptr, TINT, (char *)keyword_scaleMin.c_str(), &vali,
403                   (char *)comment_scaleMin.c_str(), &status);
[71]404
[378]405    vali = par.getFilterCode();
406    fits_write_key(fptr, TINT, (char *)keyword_filterCode.c_str(), &vali,
407                   (char *)comment_filterCode.c_str(), &status);
[71]408
[378]409    if(nature == "recon"){
410      explanation = "Duchamp: This is the RECONSTRUCTED cube";
411      ReconResid = "RECON";
412    }
413    else if(nature == "resid"){
414      explanation = "Duchamp: This is the RESIDUAL cube";
415      ReconResid = "RESID";
416    }
[913]417    else DUCHAMPWARN("write_header_info","explanation not present");
[378]418    fits_write_comment(fptr, (char *)explanation.c_str(), &status);
419    fits_write_key(fptr, TSTRING, (char *)keyword_ReconResid.c_str(),
420                   (char *)ReconResid.c_str(),
421                   (char *)comment_ReconResid.c_str(), &status);
422
[71]423  }
424
[379]425  //---------------------------------------------------------------------------
426
[378]427  void writeSmoothHeaderInfo(fitsfile *fptr, Param &par)
428  {
[528]429    /// @details
430    ///   A simple function that writes all the necessary keywords and comments
431    ///    to the FITS header pointed to by fptr.
432    ///   The keyword names and comments are taken from duchamp.hh
[208]433
[378]434    int status = 0;
[208]435
[378]436    fits_write_history(fptr, (char *)header_smoothHistory.c_str(), &status);
[208]437    status = 0;
[378]438    fits_write_history(fptr, (char *)header_smoothHistory_input.c_str(),&status);
[208]439    status = 0;
[378]440    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
441
442    if(par.getFlagSubsection()){
443      status = 0;
444      fits_write_comment(fptr,(char *)header_smoothSubsection_comment.c_str(),
445                         &status);
446      status = 0;
447      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
448                     (char *)par.getSubsection().c_str(),
449                     (char *)comment_subsection.c_str(), &status);
450    }
[208]451   
[378]452    if(par.getSmoothType()=="spatial"){
453      // if kernMin is negative (not defined), make it equal to kernMaj
454      if(par.getKernMin() < 0) par.setKernMin(par.getKernMaj());
[285]455
[378]456      fits_write_key(fptr, TSTRING, (char *)keyword_smoothtype.c_str(),
457                     (char *)header_smoothSpatial.c_str(),
458                     (char *)comment_smoothtype.c_str(), &status);
459      float valf = par.getKernMaj();
460      fits_write_key(fptr, TFLOAT, (char *)keyword_kernmaj.c_str(), &valf,
461                     (char *)comment_kernmaj.c_str(), &status);
462      valf = par.getKernMin();
463      fits_write_key(fptr, TFLOAT, (char *)keyword_kernmin.c_str(), &valf,
464                     (char *)comment_kernmin.c_str(), &status);
465      valf = par.getKernPA();
466      fits_write_key(fptr, TFLOAT, (char *)keyword_kernpa.c_str(), &valf,
467                     (char *)comment_kernpa.c_str(), &status);
468    }
469    else if(par.getSmoothType()=="spectral"){
470      fits_write_key(fptr, TSTRING, (char *)keyword_smoothtype.c_str(),
471                     (char *)header_smoothSpectral.c_str(),
472                     (char *)comment_smoothtype.c_str(), &status);
473      int vali = par.getHanningWidth();
474      fits_write_key(fptr, TINT, (char *)keyword_hanningwidth.c_str(), &vali,
475                     (char *)comment_hanningwidth.c_str(), &status);
476    }
[277]477  }
[378]478
[379]479  //---------------------------------------------------------------------------
480
481  void writeMaskHeaderInfo(fitsfile *fptr, Param &par)
482  {
[528]483    /// @details
484    ///   A simple function that writes all the necessary keywords and comments
485    ///    to the FITS header pointed to by fptr.
486    ///   The keyword names and comments are taken from duchamp.hh
[379]487
488    int status = 0;
489
490    fits_write_history(fptr, (char *)header_maskHistory.c_str(), &status);
491    status = 0;
492    fits_write_history(fptr, (char *)header_maskHistory_input.c_str(),&status);
493    status = 0;
494    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
495
496    if(par.getFlagSubsection()){
497      status = 0;
498      fits_write_comment(fptr,(char *)header_maskSubsection_comment.c_str(),
499                         &status);
500      status = 0;
501      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
502                     (char *)par.getSubsection().c_str(),
503                     (char *)comment_subsection.c_str(), &status);
504    }
505  }
506
[670]507  //---------------------------------------------------------------------------
508
509  void writeMomentMapHeaderInfo(fitsfile *fptr, Param &par)
510  {
511    /// @details
512    ///   A simple function that writes all the necessary keywords and comments
513    ///    to the FITS header pointed to by fptr.
514    ///   The keyword names and comments are taken from duchamp.hh
515
516    int status = 0;
517
518    fits_write_history(fptr, (char *)header_moment0History.c_str(), &status);
519    status = 0;
520    fits_write_history(fptr, (char *)header_moment0History_input.c_str(),&status);
521    status = 0;
522    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
523
524    if(par.getFlagSubsection()){
525      status = 0;
526      fits_write_comment(fptr,(char *)header_moment0Subsection_comment.c_str(),
527                         &status);
528      status = 0;
529      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
530                     (char *)par.getSubsection().c_str(),
531                     (char *)comment_subsection.c_str(), &status);
532    }
533  }
534
[900]535
536  //---------------------------------------------------------------------------
537
[902]538  OUTCOME Cube::writeBasicHeader(fitsfile *fptr, int bitpix, bool is2D)
[900]539  {
540    char *header, *hptr, keyname[9];
541    int  i, nkeyrec, status = 0;
542   
[936]543    const size_t naxis=this->numDim;
544    long* naxes = new long[this->numDim];
545    for(size_t i=0;i<naxis;i++) naxes[i]=this->axisDim[i];
[902]546    if(is2D) naxes[this->head.WCS().spec]=1;
[900]547    // write the required header keywords
548    fits_write_imghdr(fptr, bitpix, naxis, naxes,  &status);
549
550    // Write beam information
551    this->head.beam().writeToFITS(fptr);
552
553    // Write bunit information
554    status = 0;
555    strcpy(keyname,"BUNIT");
556    if (fits_update_key(fptr, TSTRING, keyname, (char *)this->head.getFluxUnits().c_str(), NULL, &status)){
[913]557      DUCHAMPWARN("saveImage","Error writing bunit info:");
[900]558      fits_report_error(stderr, status);
559      return FAILURE;
560    }
561
562    // convert the wcsprm struct to a set of 80-char keys
563    if ((status = wcshdo(WCSHDO_all, this->head.getWCS(), &nkeyrec, &header))) {
[913]564      DUCHAMPWARN("saveImage","Could not convert WCS information to FITS header. WCS Error Code = "<<status<<": "<<wcs_errmsg[status]);
[900]565      return FAILURE;
566    }
567
568    hptr = header;
569    strncpy(keyname,hptr,8);
570    for (i = 0; i < nkeyrec; i++, hptr += 80) {
571      status=0;
572      if(fits_update_card(fptr,keyname,hptr,&status)){
[913]573        DUCHAMPWARN("saveImage","Error writing header card");
[900]574        fits_report_error(stderr,status);
575        return FAILURE;
576      }
577    }
578   
579    if(bitpix>0){
[903]580      if(this->par.getFlagBlankPix()){
581        strcpy(keyname,"BSCALE");
582        float bscale=this->head.getBscaleKeyword();
583        if(fits_update_key(fptr, TFLOAT, keyname, &bscale, NULL, &status)){
584          duchampFITSerror(status,"saveImage","Error writing BSCALE header:");
585        }
586        strcpy(keyname,"BZERO");
587        float bzero=this->head.getBzeroKeyword();
588        if(fits_update_key(fptr, TFLOAT, keyname, &bzero, NULL, &status)){
589          duchampFITSerror(status,"saveImage","Error writing BZERO header:");
590        }
591        strcpy(keyname,"BLANK");
592        int blank=this->head.getBlankKeyword();
593        if(fits_update_key(fptr, TINT, keyname, &blank, NULL, &status)){
594          duchampFITSerror(status,"saveImage","Error writing BLANK header:");
595        }
596        if(fits_set_imgnull(fptr, blank, &status)){
597          duchampFITSerror(status, "saveImage", "Error setting null value:");
598        }
599        if(fits_set_bscale(fptr, bscale, bzero, &status)){
600          duchampFITSerror(status,"saveImage","Error setting scale:");
601        }
[900]602      }
603    }
604
[936]605    delete [] naxes;
606
[900]607    return SUCCESS;
608
609  }
610
[208]611}
Note: See TracBrowser for help on using the repository browser.