source: tags/release-1.1.11/src/Cubes/outputSpectra.cc @ 1441

Last change on this file since 1441 was 783, checked in by MatthewWhiting, 13 years ago

Moving the function for writeSpectralData away from the files that depend on pgplot existing, so that we can write it in the absence of plotting.

File size: 16.1 KB
Line 
1// -----------------------------------------------------------------------
2// outputSpectra.cc: Print the spectra of the detected objects.
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 <fstream>
30#include <iomanip>
31#include <sstream>
32#include <string>
33#include <cpgplot.h>
34#include <math.h>
35#include <wcslib/wcs.h>
36#include <duchamp/param.hh>
37#include <duchamp/duchamp.hh>
38#include <duchamp/fitsHeader.hh>
39#include <duchamp/PixelMap/Object3D.hh>
40#include <duchamp/Cubes/cubes.hh>
41#include <duchamp/Cubes/plots.hh>
42#include <duchamp/Utils/utils.hh>
43#include <duchamp/Utils/mycpgplot.hh>
44
45using namespace mycpgplot;
46using namespace PixelInfo;
47
48namespace duchamp
49{
50
51  void getSmallVelRange(Detection &obj, FitsHeader head, float *minvel, float *maxvel);
52  void getSmallZRange(Detection &obj, float *minz, float *maxz);
53
54  std::string getIndivPlotName(std::string baseName, int objNum, int maxNumObj)
55  {
56    int width = int(floor(log10(float(maxNumObj))))+1;
57    if(baseName.substr(baseName.size()-3,baseName.size())==".ps"){
58      std::stringstream ss;
59      ss << baseName.substr(0,baseName.size()-3)
60         << "-" << std::setw(width) << std::setfill('0') << objNum
61         << ".ps";
62      return ss.str();
63    }
64    else{
65      std::stringstream ss;
66      ss << baseName
67         << "-" << std::setw(width) << std::setfill('0') << objNum
68         << ".ps";
69      return ss.str();
70    }
71  }
72
73  void Cube::outputSpectra()
74  {
75    ///  @details
76    /// The way to display individual detected objects. The standard way
77    /// is plot the full spectrum, plus a zoomed-in spectrum showing just
78    /// the object, plus the 0th-moment map. If there is no spectral
79    /// axis, just the 0th moment map is plotted (using
80    /// Cube::plotSource() rather than Cube::plotSpectrum()).
81    ///
82    /// It makes use of the SpectralPlot or CutoutPlot classes from
83    /// plots.h, which size everything correctly.
84    ///
85    /// The main choice for SpectralPlot() is whether to use the peak
86    /// pixel, in which case the spectrum is just that of the peak pixel,
87    /// or the sum, where the spectrum is summed over all spatial pixels
88    /// that are in the object.  If a reconstruction has been done, that
89    /// spectrum is plotted in red.  The limits of the detection are
90    /// marked in blue.  A 0th moment map of the detection is also
91    /// plotted, with a scale bar indicating the spatial scale.
92
93    if(this->fullCols.size()==0) this->setupColumns();
94    // in case cols haven't been set -- need the precisions for printing values.
95
96    std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
97
98    std::string spectrafile = this->par.getSpectraFile() + "/vcps";
99    if(this->getDimZ()<=1){
100      Plot::CutoutPlot newplot;
101      if(newplot.setUpPlot(spectrafile.c_str())>0) {
102
103        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
104          // for each object in the cube, assuming it is wanted:
105          if(objectChoice[nobj]) this->plotSource(this->objectList->at(nobj),newplot);
106        }// end of loop over objects.
107        cpgclos();
108       
109        if(this->par.getFlagUsePrevious()) std::cout << "\n";
110        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
111          if(objectChoice[nobj] && this->par.getFlagUsePrevious()){
112            std::cout << "  Will output individual plot to "
113                      << getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size()) << "\n";
114            Plot::CutoutPlot indivplot;
115            indivplot.setUpPlot(getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size())+"/vcps");
116            this->plotSource(this->objectList->at(nobj),indivplot);
117            cpgclos();
118          }
119        }               
120      }
121    }
122    else{
123      Plot::SpectralPlot newplot;
124      if(newplot.setUpPlot(spectrafile.c_str())>0) {
125
126        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
127          // for each object in the cube, assuming it is wanted:
128          if(objectChoice[nobj])  this->plotSpectrum(nobj,newplot);
129        }// end of loop over objects.
130        cpgclos();
131
132        if(this->par.getFlagUsePrevious()) std::cout << "\n";
133        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
134          if(objectChoice[nobj] && this->par.getFlagUsePrevious()){
135            std::cout << "  Will output individual plot to "
136                      << getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size()) << "\n";
137            Plot::SpectralPlot indivplot;
138            indivplot.setUpPlot(getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size())+"/vcps");
139            this->plotSpectrum(nobj,indivplot);
140            cpgclos();
141          }
142        }               
143
144      }
145     
146    }
147  }
148  //--------------------------------------------------------------------
149
150  void Cube::plotSpectrum(int objNum, Plot::SpectralPlot &plot)
151  {
152    ///  @details
153    /// The way to print out the spectrum of a Detection.
154    /// Makes use of the SpectralPlot class in plots.hh, which sizes
155    ///  everything correctly.
156    ///
157    /// The main choice for the user is whether to use the peak pixel, in
158    /// which case the spectrum is just that of the peak pixel, or the
159    /// sum, where the spectrum is summed over all spatial pixels that
160    /// are in the object.
161    ///
162    /// If a reconstruction has been done, that spectrum is plotted in
163    /// red, and if a baseline has been calculated that is also shown, in
164    /// yellow.  The spectral limits of the detection are marked in blue.
165    /// A 0th moment map of the detection is also plotted, with a scale
166    /// bar indicating the spatial size.
167    ///
168    /// \param objNum The number of the Detection to be plotted.
169    /// \param plot The SpectralPlot object defining the PGPLOT device
170    ///        to plot the spectrum on.
171
172    long zdim = this->axisDim[2];
173
174    this->objectList->at(objNum).calcFluxes(this->array, this->axisDim);
175
176    double minMWvel=0,maxMWvel=0,xval,yval,zval;
177    xval = double(this->objectList->at(objNum).getXcentre());
178    yval = double(this->objectList->at(objNum).getYcentre());
179    if(this->par.getFlagMW()){
180      zval = double(this->par.getMinMW());
181      minMWvel = this->head.pixToVel(xval,yval,zval);
182      zval = double(this->par.getMaxMW());
183      maxMWvel = this->head.pixToVel(xval,yval,zval);
184    }
185
186    float *specx  = new float[zdim];
187    float *specy  = new float[zdim];
188    float *specy2 = new float[zdim];
189    float *base   = new float[zdim];
190//     float *specx, *specy, *specy2, *base;
191
192    this->getSpectralArrays(objNum,specx,specy,specy2,base);
193
194    std::string fluxLabel = "Flux";
195    std::string fluxUnits = this->head.getFluxUnits();
196    std::string intFluxUnits;// = this->head.getIntFluxUnits();
197    // Rather than use the intFluxUnits from the header, which will be like Jy MHz,
198    // we just use the pixel units, removing the /beam if necessary.
199
200    if(fluxUnits.size()>5 &&
201       makelower(fluxUnits.substr(fluxUnits.size()-5,
202                                  fluxUnits.size()   )) == "/beam"){
203      intFluxUnits = fluxUnits.substr(0,fluxUnits.size()-5);
204    }
205    else intFluxUnits = fluxUnits;
206   
207
208    if(this->par.getSpectralMethod()=="sum"){
209      fluxLabel = "Integrated " + fluxLabel;
210      if(this->head.isWCS()) {
211        fluxLabel += " ["+intFluxUnits+"]";
212      }
213    }
214    else {// if(par.getSpectralMethod()=="peak"){
215      fluxLabel = "Peak " + fluxLabel;
216      if(this->head.isWCS()) fluxLabel += " ["+fluxUnits+"]";
217    }
218   
219    float vmax,vmin,width;
220    vmax = vmin = specx[0];
221    for(int i=1;i<zdim;i++){
222      if(specx[i]>vmax) vmax=specx[i];
223      if(specx[i]<vmin) vmin=specx[i];
224    }
225 
226    float max,min;
227    int loc=0;
228    if(this->par.getMinMW()>0) max = min = specy[0];
229    else max = min = specy[this->par.getMaxMW()+1];
230    for(int i=0;i<zdim;i++){
231      if(!this->par.isInMW(i)){
232        if(specy[i]>max) max=specy[i];
233        if(specy[i]<min){
234          min=specy[i];
235          loc = i;
236        }
237      }
238    }
239    // widen the ranges slightly so that the top & bottom & edges don't
240    // lie on the axes.
241    width = max - min;
242    max += width * 0.05;
243    min -= width * 0.05;
244    width = vmax - vmin;
245    vmax += width * 0.01;
246    vmin -= width * 0.01;
247
248    // now plot the resulting spectrum
249    std::string label;
250    if(this->head.isWCS()){
251      label = this->head.getSpectralDescription() + " [" +
252        this->head.getSpectralUnits() + "]";
253      plot.gotoHeader(label);
254    }
255    else plot.gotoHeader("Spectral pixel value");
256
257    if(this->head.isWCS()){
258      label = this->objectList->at(objNum).outputLabelWCS();
259      plot.firstHeaderLine(label);
260      label = this->objectList->at(objNum).outputLabelFluxes();
261      plot.secondHeaderLine(label);
262    }
263    label = this->objectList->at(objNum).outputLabelWidths();
264    plot.thirdHeaderLine(label);
265    label = this->objectList->at(objNum).outputLabelPix();
266    plot.fourthHeaderLine(label);
267   
268    plot.gotoMainSpectrum(vmin,vmax,min,max,fluxLabel);
269    cpgline(zdim,specx,specy);
270    if(this->par.getFlagBaseline()){
271      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
272      cpgline(zdim,specx,base);
273      cpgsci(FOREGND);
274    }
275    if(this->reconExists){
276      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
277      cpgline(zdim,specx,specy2);   
278      cpgsci(FOREGND);
279    }
280    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
281    if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),this->objectList->at(objNum).getVelMax());
282    else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax());
283
284    /**************************/
285    // ZOOM IN SPECTRALLY ON THE DETECTION.
286
287    float minvel,maxvel;
288    if(this->head.isWCS()) getSmallVelRange(this->objectList->at(objNum),this->head,&minvel,&maxvel);
289    else getSmallZRange(this->objectList->at(objNum),&minvel,&maxvel);
290
291    // Find new max & min flux values
292    std::swap(max,min);
293    int ct = 0;
294    for(int i=0;i<zdim;i++){
295      if((!this->par.isInMW(i))&&(specx[i]>=minvel)&&(specx[i]<=maxvel)){
296        ct++;
297        if(specy[i]>max) max=specy[i];
298        if(specy[i]<min) min=specy[i];
299      }
300    }
301    // widen the flux range slightly so that the top & bottom don't lie
302    // on the axes.
303    width = max - min;
304    max += width * 0.05;
305    min -= width * 0.05;
306
307    plot.gotoZoomSpectrum(minvel,maxvel,min,max);
308    cpgline(zdim,specx,specy);
309    if(this->par.getFlagBaseline()){
310      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
311      cpgline(zdim,specx,base);
312      cpgsci(FOREGND);
313    }
314    if(this->reconExists){
315      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
316      cpgline(zdim,specx,specy2);   
317      cpgsci(FOREGND);
318    }
319    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
320    if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),
321                                             this->objectList->at(objNum).getVelMax());
322    else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax());
323   
324    /**************************/
325
326    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
327    plot.gotoMap();
328    this->drawMomentCutout(this->objectList->at(objNum));
329
330    delete [] specx;
331    delete [] specy;
332    delete [] specy2;
333    delete [] base;
334 
335  }
336  //--------------------------------------------------------------------
337
338  void getSmallVelRange(Detection &obj, FitsHeader head,
339                        float *minvel, float *maxvel)
340  {
341    ///  @details
342    ///  Routine to calculate the velocity range for the zoomed-in region.
343    ///  This range should be the maximum of 20 pixels, or 3x the wdith of
344    ///   the detection.
345    ///  Need to :
346    ///      Calculate pixel width of a 3x-detection-width region.
347    ///      If smaller than 20, calculate velocities of central vel +- 10 pixels
348    ///      If not, use the 3x-detection-width
349    ///  Range returned via "minvel" and "maxvel" parameters.
350    ///  \param obj Detection under examination.
351    ///  \param head FitsHeader, containing the WCS information.
352    ///  \param minvel Returned value of minimum velocity
353    ///  \param maxvel Returned value of maximum velocity
354
355    double *pixcrd = new double[3];
356    double *world  = new double[3];
357    float minpix,maxpix;
358    // define new velocity extrema
359    //    -- make it 3x wider than the width of the detection.
360    *minvel = 0.5*(obj.getVelMin()+obj.getVelMax()) - 1.5*obj.getVelWidth();
361    *maxvel = 0.5*(obj.getVelMin()+obj.getVelMax()) + 1.5*obj.getVelWidth();
362    // Find velocity range in number of pixels:
363    world[0] = obj.getRA();
364    world[1] = obj.getDec();
365    world[2] = head.velToSpec(*minvel);
366    head.wcsToPix(world,pixcrd);
367    minpix = pixcrd[2];
368    world[2] = head.velToSpec(*maxvel);
369    head.wcsToPix(world,pixcrd);
370    maxpix = pixcrd[2];
371    if(maxpix<minpix) std::swap(maxpix,minpix);
372   
373    if((maxpix - minpix + 1) < 20){
374      pixcrd[0] = double(obj.getXcentre());
375      pixcrd[1] = double(obj.getYcentre());
376      pixcrd[2] = obj.getZcentre() - 10.;
377      head.pixToWCS(pixcrd,world);
378      //    *minvel = setVel_kms(wcs,world[2]);
379      *minvel = head.specToVel(world[2]);
380      pixcrd[2] = obj.getZcentre() + 10.;
381      head.pixToWCS(pixcrd,world);
382      //     *maxvel = setVel_kms(wcs,world[2]);
383      *maxvel = head.specToVel(world[2]);
384      if(*maxvel<*minvel) std::swap(*maxvel,*minvel);
385    }
386    delete [] pixcrd;
387    delete [] world;
388
389  }
390  //--------------------------------------------------------------------
391
392  void getSmallZRange(Detection &obj, float *minz, float *maxz)
393  {
394    ///  @details
395    ///  Routine to calculate the pixel range for the zoomed-in spectrum.
396    ///  This range should be the maximum of 20 pixels, or 3x the width
397    ///   of the detection.
398    ///  Need to :
399    ///      Calculate pixel width of a 3x-detection-width region.
400    ///       If smaller than 20, use central pixel +- 10 pixels
401    ///  Range returned via "minz" and "maxz" parameters.
402    ///  \param obj Detection under examination.
403    ///  \param minz Returned value of minimum z-pixel coordinate
404    ///  \param maxz Returned value of maximum z-pixel coordinate
405
406    *minz = 2.*obj.getZmin() - obj.getZmax();
407    *maxz = 2.*obj.getZmax() - obj.getZmin();
408   
409    if((*maxz - *minz + 1) < 20){
410      *minz = obj.getZcentre() - 10.;
411      *maxz = obj.getZcentre() + 10.;
412    }
413
414  }
415  //--------------------------------------------------------------------
416
417  void Cube::plotSource(Detection obj, Plot::CutoutPlot &plot)
418  {
419    ///  @details
420    /// The way to print out the 2d image cutout of a Detection.
421    /// Makes use of the CutoutPlot class in plots.hh, which sizes
422    ///  everything correctly.
423    ///
424    /// A 0th moment map of the detection is plotted, with a scale
425    /// bar indicating the spatial size.
426    ///
427    /// Basic information on the source is printed next to it as well.
428    ///
429    /// \param obj The Detection to be plotted.
430    /// \param plot The PGPLOT device to plot the spectrum on.
431
432    obj.calcFluxes(this->array, this->axisDim);
433
434    std::string label;
435    plot.gotoHeader();
436
437    if(this->head.isWCS()){
438      label = obj.outputLabelWCS();
439      plot.firstHeaderLine(label);
440      label = obj.outputLabelFluxes();
441      plot.secondHeaderLine(label);
442    }
443    label = obj.outputLabelWidths();
444    plot.thirdHeaderLine(label);
445    label = obj.outputLabelPix();
446    plot.fourthHeaderLine(label);
447   
448    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
449    plot.gotoMap();
450    this->drawMomentCutout(obj);
451
452  }
453
454}
Note: See TracBrowser for help on using the repository browser.