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

Last change on this file since 757 was 757, checked in by MatthewWhiting, 14 years ago

A few changes to get the writing of recon cubes right - the problem was when the flux units were changed. We need to change them back before the cube is written.

File size: 25.1 KB
Line 
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// -----------------------------------------------------------------------
29#include <iostream>
30#include <sstream>
31#include <string>
32#include <string.h>
33#include <wcslib/wcs.h>
34#include <wcslib/wcshdr.h>
35#include <wcslib/wcsunits.h>
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
40#include <fitsio.h>
41#include <duchamp/duchamp.hh>
42#include <duchamp/Cubes/cubes.hh>
43#include <duchamp/PixelMap/Voxel.hh>
44#include <duchamp/PixelMap/Object3D.hh>
45
46namespace duchamp
47{
48
49  /// @brief Write FITS headers in correct format for reconstructed array output
50  void writeReconHeaderInfo(fitsfile *fptr, Param &par, std::string nature);
51
52  /// @brief Write FITS headers in correct format for smoothed array output
53  void writeSmoothHeaderInfo(fitsfile *fptr, Param &par);
54
55  /// @brief Write FITS headers in correct format for mask array output
56  void writeMaskHeaderInfo(fitsfile *fptr, Param &par);
57
58  /// @brief Write FITS headers in correct format for moment-0 array output
59  void writeMomentMapHeaderInfo(fitsfile *fptr, Param &par);
60
61  //---------------------------------------------------------------------------
62
63  char *numerateKeyword(std::string key, int num)
64  {
65    /// @details A utility function to combine a keyword and a
66    /// value, to produce a relevant FITS keyword for a given
67    /// axis. For example numerateKeyword(CRPIX,1) returns CRPIX1.
68    std::stringstream ss;
69    ss << key << num;
70    return (char *)ss.str().c_str();
71  }
72
73  void duchampFITSerror(int status, std::string subroutine, std::string error)
74  {
75    if(status){
76      duchampError(subroutine,error);
77      fits_report_error(stderr, status);
78    }
79  }
80
81
82  OUTCOME Cube::saveMomentMapImage()
83  {
84    /// @details
85    ///  A function to save the moment-0 map to a FITS file.
86   
87    int newbitpix = FLOAT_IMG;
88    char *comment = new char[FLEN_COMMENT];
89    strcpy(comment,"");
90    long *fpixel = new long[2];
91    for(int i=0;i<2;i++) fpixel[i]=1;
92    int status = 0;  /* MUST initialize status */
93    fitsfile *fptr;         
94
95    std::string fileout = "!" + this->par.outputMomentMapFile();
96    // the ! is there so that it writes over an existing file.
97    char *keyword = new char[FLEN_KEYWORD];
98
99    status = 0;
100    if(fits_create_file(&fptr,fileout.c_str(),&status)){
101      duchampFITSerror(status,"saveMomentMapImage","Error creating file:");
102      return FAILURE;
103    }
104    else {
105      status = 0;
106      long *dim = new long[2];
107      for (uint i = 0; i < 2; i++) dim[i] = this->axisDim[i];
108      if (fits_create_img(fptr, newbitpix, 2, dim, &status)) {
109        duchampFITSerror(status,"saveMomentMapImage","Error creating image:");
110      }
111
112      if(!this->par.getFlagUsingBeam()){   // if the cube has beam info, copy it
113        float bmaj=this->head.getBmajKeyword(), bmin=this->head.getBminKeyword(), bpa=this->head.getBpaKeyword();
114        status = 0;
115        strcpy(keyword,"BMAJ");
116        if (fits_update_key(fptr, TFLOAT, keyword, &bmaj, NULL, &status)){
117          duchampFITSerror(status,"saveMomentMapImage","Error saving beam info:");
118        }
119        status = 0;
120        strcpy(keyword,"BMIN");
121        if (fits_update_key(fptr, TFLOAT, keyword, &bmin, NULL, &status)){
122          duchampFITSerror(status,"saveMomentMapImage","Error saving beam info:");
123        }
124        status = 0;
125        strcpy(keyword,"BPA");
126        if (fits_update_key(fptr, TFLOAT, keyword, &bpa, NULL, &status)){
127          duchampFITSerror(status,"saveMomentMapImage","Error saving beam info:");
128        }
129      }                 
130      status = 0;
131      strcpy(keyword,"EQUINOX");
132      if (fits_update_key(fptr, TFLOAT, keyword, &this->head.WCS().equinox, NULL, &status)){
133        duchampFITSerror(status,"saveMomentMapImage","Error saving equinox:");
134      }
135      status = 0;
136      strcpy(keyword,"BUNIT");
137      if (fits_update_key(fptr, TSTRING, keyword, (char *)this->head.getIntFluxUnits().c_str(),  NULL, &status)){
138        duchampFITSerror(status,"saveMomentMapImage","Error saving BUNIT:");
139      }
140      float val;
141      int axisNumbers[2];
142      axisNumbers[0] = this->head.WCS().lng;
143      axisNumbers[1] = this->head.WCS().lat;
144      for (uint d = 0; d < 2; d++) {
145        int i = axisNumbers[d];
146        status = 0;
147        if (fits_update_key(fptr, TSTRING, numerateKeyword("CTYPE", d + 1), this->head.WCS().ctype[i],  NULL, &status)){
148          duchampFITSerror(status,"saveMomentMapImage","Error saving CTYPE:");
149        }
150        status = 0;
151        if (fits_update_key(fptr, TSTRING, numerateKeyword("CUNIT", d + 1), this->head.WCS().cunit[i],  NULL, &status)){
152          duchampFITSerror(status,"saveMomentMapImage","Error saving CUNIT:");
153        }
154        status = 0;
155        val = this->head.WCS().crval[i];
156        if (fits_update_key(fptr, TFLOAT, numerateKeyword("CRVAL", d + 1), &val, NULL, &status)){
157          duchampFITSerror(status,"saveMomentMapImage","Error saving CRVAL:");
158        }
159        val = this->head.WCS().cdelt[i];
160        status = 0;
161        if (fits_update_key(fptr, TFLOAT, numerateKeyword("CDELT", d + 1), &val, NULL, &status)){
162          duchampFITSerror(status,"saveMomentMapImage","Error saving CDELT:");
163        }
164        val = this->head.WCS().crpix[i];
165        status = 0;
166        if (fits_update_key(fptr, TFLOAT, numerateKeyword("CRPIX", d + 1), &val, NULL, &status)){
167          duchampFITSerror(status,"saveMomentMapImage","Error saving CRPIX:");
168        }
169        val = this->head.WCS().crota[i];
170        status = 0;
171        if (fits_update_key(fptr, TFLOAT, numerateKeyword("CROTA", d + 1), &val, NULL, &status)){
172          duchampFITSerror(status,"saveMomentMapImage","Error saving CROTA:");
173        }
174      }
175
176      delete [] comment;
177      delete [] keyword;
178
179      writeMomentMapHeaderInfo(fptr, this->par);
180       
181      long size = this->axisDim[0] * this->axisDim[1];
182      float *momentMap = new float[size];
183      std::vector<bool> detectionMap;
184      this->getMomentMap(momentMap,detectionMap);
185      status=0;
186      if(fits_write_pix(fptr, TFLOAT, fpixel, size, momentMap, &status)){
187        duchampFITSerror(status,"saveMomentMapImage","Error writing data");
188      }
189      status = 0;
190      if(fits_close_file(fptr, &status)){
191        duchampFITSerror(status,"saveMomentMapImage","Error closing file");
192      }
193
194      delete [] momentMap;
195
196    }
197
198    delete [] fpixel;
199
200    return SUCCESS;
201
202  }
203
204  OUTCOME Cube::saveMaskCube()
205  {
206    /// @details
207    ///  A function to save a mask to a FITS file, indicating where the
208    ///  detections where made. The value of the detected pixels is
209    ///  determined by the flagMaskWithObjectNum parameter: if true,
210    ///  the value of the pixels is given by the corresponding object
211    ///  ID number; if false, they take the value 1 for all
212    ///  objects. Pixels not in a detected object have the value 0.
213
214    int newbitpix = SHORT_IMG;
215    char *comment = new char[FLEN_COMMENT];
216    strcpy(comment,"");
217    long *fpixel = new long[this->header().WCS().naxis];
218    for(int i=0;i<this->header().WCS().naxis;i++) fpixel[i]=1;
219    int status = 0;  /* MUST initialize status */
220    fitsfile *fptrOld, *fptrNew;         
221    if(fits_open_file(&fptrOld,this->par.getImageFile().c_str(),READONLY,&status)){
222      duchampFITSerror(status,"saveMask","Error opening existing file:");
223      return FAILURE;
224    }
225
226    std::string fileout = "!" + this->par.outputMaskFile();
227    // the ! is there so that it writes over an existing file.
228
229    status = 0;
230    if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
231      duchampFITSerror(status,"saveMask","Error creating file:");
232      return FAILURE;
233    }
234    else {
235      status = 0;
236      if(fits_movabs_hdu(fptrOld, 1, NULL, &status)){
237        duchampFITSerror(status,"saveMask","Error accessing existing file's header:");
238        return FAILURE;
239      }
240      status = 0;
241      fits_copy_header(fptrOld, fptrNew, &status);
242      if (status){
243        duchampFITSerror(status,"saveMask","Error copying header to new file:");
244        fits_report_error(stderr, status);
245        return FAILURE;
246      }
247      status = 0;
248      char *keyword = new char[FLEN_KEYWORD];
249      strcpy(keyword,"BITPIX");
250      strcpy(comment,"number of bits per data pixel");
251      if(fits_update_key(fptrNew, TINT, keyword, &newbitpix, comment, &status)){
252        duchampFITSerror(status,"saveMask","Error writing BITPIX header:");
253      }
254      float bscale=1., bzero=0.;
255      strcpy(comment,"");
256      strcpy(keyword,"BSCALE");
257      if(fits_update_key(fptrNew, TFLOAT, keyword, &bscale, comment, &status)){
258        duchampFITSerror(status,"saveMask","Error writing BSCALE header:");
259      }
260      strcpy(keyword,"BZERO");
261      if(fits_update_key(fptrNew, TFLOAT, keyword, &bzero, comment, &status)){
262        duchampFITSerror(status,"saveMask","Error writing BZERO header:");
263      }
264      if(fits_set_bscale(fptrNew, 1, 0, &status)){
265        duchampFITSerror(status,"saveMask","Error setting scale:");
266      }
267      std::string newunits;
268      if(this->par.getFlagMaskWithObjectNum())
269        newunits = "Object ID";
270      else
271        newunits = "Detection flag";
272      strcpy(keyword,"BUNIT");
273      if(fits_update_key(fptrNew, TSTRING, keyword, (char *)newunits.c_str(), comment, &status)){
274        duchampFITSerror(status,"saveMask","Error writing BUNIT header:");
275      }
276      long dud;
277      // Need to correct the dimensions, if we have subsectioned the image
278      if(this->par.getFlagSubsection()){
279        std::stringstream naxis;
280        fits_read_key(fptrOld, TLONG, (char *)naxis.str().c_str(), &dud, comment, &status);
281        fits_update_key(fptrNew, TLONG, (char *)naxis.str().c_str(),
282                        &(this->axisDim[0]), comment, &status);
283        naxis.str("");
284        naxis << "NAXIS" << this->head.WCS().lat;
285        fits_read_key(fptrOld, TLONG, (char *)naxis.str().c_str(), &dud, comment, &status);
286        fits_update_key(fptrNew, TLONG, (char *)naxis.str().c_str(),
287                        &(this->axisDim[1]), comment, &status);
288        naxis.str("");
289        naxis << "NAXIS" << this->head.WCS().spec;
290        fits_read_key(fptrOld, TLONG, (char *)naxis.str().c_str(), &dud, comment, &status);
291        fits_update_key(fptrNew, TLONG, (char *)naxis.str().c_str(),
292                        &(this->axisDim[2]), comment, &status);
293      }
294
295      delete [] comment;
296      delete [] keyword;
297
298      writeMaskHeaderInfo(fptrNew, this->par);
299       
300      short *mask = new short[this->numPixels];
301      for(int i=0;i<this->numPixels;i++) mask[i]=0;
302      std::vector<Detection>::iterator obj;
303      for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
304        std::vector<PixelInfo::Voxel> voxlist = obj->getPixelSet();
305        std::vector<PixelInfo::Voxel>::iterator vox;
306        for(vox=voxlist.begin();vox<voxlist.end();vox++){
307          int pixelpos = vox->getX() + this->axisDim[0]*vox->getY() +
308            this->axisDim[0]*this->axisDim[1]*vox->getZ();
309          if(this->par.getFlagMaskWithObjectNum()) mask[pixelpos] = obj->getID();
310          else mask[pixelpos] = 1;
311        }
312      }
313      status=0;
314      if(fits_write_pix(fptrNew, TSHORT, fpixel, this->numPixels, mask, &status)){
315        duchampFITSerror(status,"saveMask","Error writing mask array:");
316      }
317      status = 0;
318      if(fits_close_file(fptrNew, &status)){
319        duchampFITSerror(status,"saveMask","Error closing file:");
320      }
321
322      delete [] mask;
323
324    }
325
326    delete [] fpixel;
327
328    return SUCCESS;
329  }
330 
331  //---------------------------------------------------------------------------
332
333  OUTCOME Cube::saveSmoothedCube()
334  {
335    /// @brief
336    ///   A function to save the smoothed arrays to a FITS file.
337    ///   Additional header keywords are written as well, indicating the
338    ///   width of the Hanning filter or the dimensions of the Gaussian
339    ///   kernel.
340    ///   The file is always written -- if the filename (as calculated
341    ///    based on the parameters) exists, then it is overwritten.
342 
343    float blankval = this->par.getBlankPixVal();
344
345    int status = 0;  /* MUST initialize status */
346    fitsfile *fptrOld, *fptrNew;         
347    if(fits_open_file(&fptrOld,this->par.getFullImageFile().c_str(),READONLY,&status)){
348      duchampFITSerror(status,"saveSmoothedCube", "Error opening existing file:");
349      return FAILURE;
350    }
351
352    if(this->par.getFlagOutputSmooth()){
353      std::string fileout = "!" + this->par.outputSmoothFile();
354      // the ! is there so that it writes over an existing file.
355
356      status = 0;
357      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
358        duchampFITSerror(status,"saveSmoothedCube","Error creating smoothed FITS file:");
359        return FAILURE;
360      }
361      else {
362        status = 0;
363        if(fits_movabs_hdu(fptrOld, 1, NULL, &status)){
364          duchampFITSerror(status,"saveSmoothedCube","Error accessing existing file's header:");
365          return FAILURE;
366        }
367        status = 0;
368        if(fits_copy_header(fptrOld, fptrNew, &status)){
369          duchampFITSerror(status,"saveSmoothedCube","Error copying header info:");
370          return FAILURE;
371        }
372
373        writeSmoothHeaderInfo(fptrNew, this->par);
374
375        if(this->par.getFlagBlankPix())
376          fits_write_imgnull(fptrNew, TFLOAT, 1, this->numPixels, this->recon, &blankval, &status);
377        else
378          fits_write_img(fptrNew, TFLOAT, 1, this->numPixels, this->recon, &status);
379        if(status){
380          duchampFITSerror(status,"saveSmothedCube","Error writing smoothed array:");
381          return FAILURE;
382        }
383
384        status = 0;
385        if(fits_close_file(fptrNew, &status)){
386          duchampFITSerror(status,"saveSmoothedCube","Error closing file:");
387        }
388      }
389    }
390
391    return SUCCESS;
392
393  }
394
395  //---------------------------------------------------------------------------
396
397  OUTCOME Cube::saveReconstructedCube()
398  {
399    /// @details
400    ///  A function to save the reconstructed and/or residual arrays.
401    ///   A number of header keywords are written as well, indicating the
402    ///    nature of the reconstruction that has been done.
403    ///   The file is always written -- if the filename (as calculated
404    ///    based on the recon parameters) exists, then it is overwritten.
405 
406    float blankval = this->par.getBlankPixVal();
407
408    if(!this->reconAllocated){
409      duchampError("saveReconCube","Have not allocated reconstructed array, so cannot save");
410      return FAILURE;
411    }
412
413    int status = 0;  /* MUST initialize status */
414    fitsfile *fptrOld, *fptrNew;         
415    if(fits_open_file(&fptrOld,this->par.getFullImageFile().c_str(),READONLY,&status)){
416      duchampFITSerror(status,"saveReconCube","Error opening existing file:");
417      return FAILURE;
418    }
419
420    if(this->head.getFluxUnits()!=this->head.getOrigFluxUnits()){
421      // we have changed the flux units - need to change back
422      double scale,offset,power;
423      int status = wcsunits(this->head.getFluxUnits().c_str(), this->head.getOrigFluxUnits().c_str(), &scale, &offset, &power);
424      if(status==0){
425        for(int i=0;i<this->numPixels;i++)
426          if(!this->isBlank(i)){
427            this->array[i] = pow(scale * this->array[i] + offset, power);
428            this->recon[i] = pow(scale * this->recon[i] + offset, power);
429          }
430        }
431    }
432 
433    if(this->par.getFlagOutputRecon()){
434      std::string fileout = "!" + this->par.outputReconFile();
435      // the ! is there so that it writes over an existing file.
436
437      status = 0;
438      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
439        duchampFITSerror(status,"saveReconCube","Error creating file:");
440        return FAILURE;
441      }
442      else
443        {
444          status = 0;
445          if(fits_movabs_hdu(fptrOld, 1, NULL, &status)){
446            duchampFITSerror(status,"saveReconCube","Error accessing existing file's header:");
447            return FAILURE;
448          }
449          status = 0;
450          if(fits_copy_header(fptrOld, fptrNew, &status)){
451            duchampFITSerror(status,"saveReconCube","Error copying header:");
452            return FAILURE;
453          }
454
455          writeReconHeaderInfo(fptrNew, this->par, "recon");
456
457          status=0;
458          long *fpixel = new long[this->numDim];
459          for(int i=0;i<this->numDim;i++) fpixel[i]=1;
460          long group=0;
461          if(this->par.getFlagBlankPix())
462            // fits_write_imgnull(fptrNew, TFLOAT, 1, this->numPixels, this->recon, &blankval, &status);
463            fits_write_imgnull_flt(fptrNew, group, 1, this->numPixels, this->recon, blankval, &status);
464          //        fits_write_pixnull(fptrNew, TFLOAT, fpixel, this->numPixels, this->recon, &blankval, &status);
465          else 
466            // fits_write_img(fptrNew, TFLOAT, 1, this->numPixels, this->recon, &status);
467            fits_write_img_flt(fptrNew, group, 1, this->numPixels, this->recon, &status);
468          //        fits_write_pix(fptrNew, TFLOAT, fpixel, this->numPixels, this->recon, &status);
469          if(status){
470            duchampFITSerror(status,"saveReconCube","Error writing reconstructed array:");
471            return FAILURE;
472          }
473          delete [] fpixel;
474
475          status = 0;
476          if(fits_close_file(fptrNew, &status)){
477            duchampFITSerror(status,"saveReconCube","Error closing file:");
478          }
479        }
480    }
481
482
483    if(this->par.getFlagOutputResid()){
484      float *resid = new float[this->numPixels];
485      for(int i=0;i<this->numPixels;i++)
486        resid[i] = this->array[i] - this->recon[i];
487
488      std::string fileout = "!" + this->par.outputResidFile();
489      // the ! is there so that it writes over an existing file.
490      status = 0;
491      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
492        duchampFITSerror(status,"saveResidualCube","Error creating new file:");
493        return FAILURE;
494      }
495      else
496        {
497          status = 0;
498          if(fits_movabs_hdu(fptrOld, 1, NULL, &status)){
499            duchampFITSerror(status,"saveResidualCube","Error accessing existing file's header:");
500            return FAILURE;
501          }
502          status = 0;
503          if(fits_copy_header(fptrOld, fptrNew, &status)){
504            duchampFITSerror(status,"saveResidualCube","Error copying header:");
505            return FAILURE;
506          }
507          writeReconHeaderInfo(fptrNew, this->par, "resid");
508
509          if(this->par.getFlagBlankPix())
510            fits_write_imgnull(fptrNew, TFLOAT, 1, this->numPixels, resid, &blankval, &status);
511          else 
512            fits_write_img(fptrNew, TFLOAT, 1, this->numPixels, resid, &status);
513          if(status){
514            duchampFITSerror(status,"saveResidualCube","Error writing reconstructed array:");
515            return FAILURE;
516          }
517
518          status=0;
519          if(fits_close_file(fptrNew, &status)){
520            duchampFITSerror(status,"saveResidualCube","Error closing file:");
521          }
522        }
523      delete [] resid;
524    }
525
526    return SUCCESS;
527  }
528
529  //---------------------------------------------------------------------------
530
531  void writeReconHeaderInfo(fitsfile *fptr, Param &par, std::string nature)
532  {
533    /// @details
534    ///   A simple function that writes all the necessary keywords and comments
535    ///    to the FITS header pointed to by fptr.
536    ///   The keyword names and comments are taken from duchamp.hh
537    ///   The parameter "nature" indicates what type of file is being written:
538    ///    should be either "recon" or "resid".
539
540    int status = 0;
541    std::string explanation = "",ReconResid="";
542
543    fits_write_history(fptr, (char *)header_reconHistory1.c_str(), &status);
544                                   
545    fits_write_history(fptr, (char *)header_reconHistory2.c_str(), &status);
546
547    fits_write_history(fptr, (char *)header_reconHistory_input.c_str(), &status);
548
549    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
550
551    if(par.getFlagSubsection()){
552      fits_write_comment(fptr,(char *)header_reconSubsection_comment.c_str(),
553                         &status);
554      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
555                     (char *)par.getSubsection().c_str(),
556                     (char *)comment_subsection.c_str(), &status);
557    }
558   
559    fits_write_comment(fptr, (char *)header_atrous_comment.c_str(), &status);
560
561    float valf = par.getAtrousCut();
562    fits_write_key(fptr, TFLOAT, (char *)keyword_snrRecon.c_str(), &valf,
563                   (char *)comment_snrRecon.c_str(), &status);
564
565    int vali = par.getReconDim();
566    fits_write_key(fptr, TINT, (char *)keyword_reconDim.c_str(), &vali,
567                   (char *)comment_reconDim.c_str(), &status);
568
569    vali = par.getMinScale();
570    fits_write_key(fptr, TINT, (char *)keyword_scaleMin.c_str(), &vali,
571                   (char *)comment_scaleMin.c_str(), &status);
572
573    vali = par.getFilterCode();
574    fits_write_key(fptr, TINT, (char *)keyword_filterCode.c_str(), &vali,
575                   (char *)comment_filterCode.c_str(), &status);
576
577    if(nature == "recon"){
578      explanation = "Duchamp: This is the RECONSTRUCTED cube";
579      ReconResid = "RECON";
580    }
581    else if(nature == "resid"){
582      explanation = "Duchamp: This is the RESIDUAL cube";
583      ReconResid = "RESID";
584    }
585    else duchampWarning("write_header_info","explanation not present!\n");
586    fits_write_comment(fptr, (char *)explanation.c_str(), &status);
587    fits_write_key(fptr, TSTRING, (char *)keyword_ReconResid.c_str(),
588                   (char *)ReconResid.c_str(),
589                   (char *)comment_ReconResid.c_str(), &status);
590
591  }
592
593  //---------------------------------------------------------------------------
594
595  void writeSmoothHeaderInfo(fitsfile *fptr, Param &par)
596  {
597    /// @details
598    ///   A simple function that writes all the necessary keywords and comments
599    ///    to the FITS header pointed to by fptr.
600    ///   The keyword names and comments are taken from duchamp.hh
601
602    int status = 0;
603
604    fits_write_history(fptr, (char *)header_smoothHistory.c_str(), &status);
605    status = 0;
606    fits_write_history(fptr, (char *)header_smoothHistory_input.c_str(),&status);
607    status = 0;
608    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
609
610    if(par.getFlagSubsection()){
611      status = 0;
612      fits_write_comment(fptr,(char *)header_smoothSubsection_comment.c_str(),
613                         &status);
614      status = 0;
615      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
616                     (char *)par.getSubsection().c_str(),
617                     (char *)comment_subsection.c_str(), &status);
618    }
619   
620    if(par.getSmoothType()=="spatial"){
621      // if kernMin is negative (not defined), make it equal to kernMaj
622      if(par.getKernMin() < 0) par.setKernMin(par.getKernMaj());
623
624      fits_write_key(fptr, TSTRING, (char *)keyword_smoothtype.c_str(),
625                     (char *)header_smoothSpatial.c_str(),
626                     (char *)comment_smoothtype.c_str(), &status);
627      float valf = par.getKernMaj();
628      fits_write_key(fptr, TFLOAT, (char *)keyword_kernmaj.c_str(), &valf,
629                     (char *)comment_kernmaj.c_str(), &status);
630      valf = par.getKernMin();
631      fits_write_key(fptr, TFLOAT, (char *)keyword_kernmin.c_str(), &valf,
632                     (char *)comment_kernmin.c_str(), &status);
633      valf = par.getKernPA();
634      fits_write_key(fptr, TFLOAT, (char *)keyword_kernpa.c_str(), &valf,
635                     (char *)comment_kernpa.c_str(), &status);
636    }
637    else if(par.getSmoothType()=="spectral"){
638      fits_write_key(fptr, TSTRING, (char *)keyword_smoothtype.c_str(),
639                     (char *)header_smoothSpectral.c_str(),
640                     (char *)comment_smoothtype.c_str(), &status);
641      int vali = par.getHanningWidth();
642      fits_write_key(fptr, TINT, (char *)keyword_hanningwidth.c_str(), &vali,
643                     (char *)comment_hanningwidth.c_str(), &status);
644    }
645  }
646
647  //---------------------------------------------------------------------------
648
649  void writeMaskHeaderInfo(fitsfile *fptr, Param &par)
650  {
651    /// @details
652    ///   A simple function that writes all the necessary keywords and comments
653    ///    to the FITS header pointed to by fptr.
654    ///   The keyword names and comments are taken from duchamp.hh
655
656    int status = 0;
657
658    fits_write_history(fptr, (char *)header_maskHistory.c_str(), &status);
659    status = 0;
660    fits_write_history(fptr, (char *)header_maskHistory_input.c_str(),&status);
661    status = 0;
662    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
663
664    if(par.getFlagSubsection()){
665      status = 0;
666      fits_write_comment(fptr,(char *)header_maskSubsection_comment.c_str(),
667                         &status);
668      status = 0;
669      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
670                     (char *)par.getSubsection().c_str(),
671                     (char *)comment_subsection.c_str(), &status);
672    }
673  }
674
675  //---------------------------------------------------------------------------
676
677  void writeMomentMapHeaderInfo(fitsfile *fptr, Param &par)
678  {
679    /// @details
680    ///   A simple function that writes all the necessary keywords and comments
681    ///    to the FITS header pointed to by fptr.
682    ///   The keyword names and comments are taken from duchamp.hh
683
684    int status = 0;
685
686    fits_write_history(fptr, (char *)header_moment0History.c_str(), &status);
687    status = 0;
688    fits_write_history(fptr, (char *)header_moment0History_input.c_str(),&status);
689    status = 0;
690    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
691
692    if(par.getFlagSubsection()){
693      status = 0;
694      fits_write_comment(fptr,(char *)header_moment0Subsection_comment.c_str(),
695                         &status);
696      status = 0;
697      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
698                     (char *)par.getSubsection().c_str(),
699                     (char *)comment_subsection.c_str(), &status);
700    }
701  }
702
703}
Note: See TracBrowser for help on using the repository browser.