source: trunk/src/Cubes/outputSpectra.cc @ 1133

Last change on this file since 1133 was 1133, checked in by MatthewWhiting, 11 years ago

Ticket #132 - New code to fit the ellipse to the moment-0 map thresholded at half its peak - this then provides FWHM esimates for major/minor axes. Also have adaptive units for these axes, scaling to get the numbers not too small and adjusting the units accordingly. 2D images also have the shape calculated too now.

File size: 13.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/cubeUtils.hh>
42#include <duchamp/Cubes/plots.hh>
43#include <duchamp/Utils/utils.hh>
44#include <duchamp/Utils/mycpgplot.hh>
45
46using namespace mycpgplot;
47using namespace PixelInfo;
48
49namespace duchamp
50{
51
52  std::string getIndivPlotName(std::string baseName, int objNum, int maxNumObj)
53  {
54    int width = int(floor(log10(float(maxNumObj))))+1;
55    if(baseName.substr(baseName.size()-3,baseName.size())==".ps"){
56      std::stringstream ss;
57      ss << baseName.substr(0,baseName.size()-3)
58         << "-" << std::setw(width) << std::setfill('0') << objNum
59         << ".ps";
60      return ss.str();
61    }
62    else{
63      std::stringstream ss;
64      ss << baseName
65         << "-" << std::setw(width) << std::setfill('0') << objNum
66         << ".ps";
67      return ss.str();
68    }
69  }
70
71  void Cube::outputSpectra()
72  {
73    ///  @details
74    /// The way to display individual detected objects. The standard way
75    /// is plot the full spectrum, plus a zoomed-in spectrum showing just
76    /// the object, plus the 0th-moment map. If there is no spectral
77    /// axis, just the 0th moment map is plotted (using
78    /// Cube::plotSource() rather than Cube::plotSpectrum()).
79    ///
80    /// It makes use of the SpectralPlot or CutoutPlot classes from
81    /// plots.h, which size everything correctly.
82    ///
83    /// The main choice for SpectralPlot() is whether to use the peak
84    /// pixel, in which case the spectrum is just that of the peak pixel,
85    /// or the sum, where the spectrum is summed over all spatial pixels
86    /// that are in the object.  If a reconstruction has been done, that
87    /// spectrum is plotted in red.  The limits of the detection are
88    /// marked in blue.  A 0th moment map of the detection is also
89    /// plotted, with a scale bar indicating the spatial scale.
90
91    if(this->fullCols.size()==0) this->setupColumns();
92    // in case cols haven't been set -- need the precisions for printing values.
93
94    std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
95
96    std::string spectrafile = this->par.getSpectraFile() + "/vcps";
97    if(this->getDimZ()<=1){
98      Plot::CutoutPlot newplot;
99      if(newplot.setUpPlot(spectrafile.c_str())>0) {
100
101        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
102          // for each object in the cube, assuming it is wanted:
103          if(objectChoice[nobj]) this->plotSource(this->objectList->at(nobj),newplot);
104        }// end of loop over objects.
105        cpgclos();
106       
107        if(this->par.getFlagUsePrevious()) std::cout << "\n";
108        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
109          if(objectChoice[nobj] && this->par.getFlagUsePrevious()){
110            std::cout << "  Will output individual plot to "
111                      << getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size()) << "\n";
112            Plot::CutoutPlot indivplot;
113            indivplot.setUpPlot(getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size())+"/vcps");
114            this->plotSource(this->objectList->at(nobj),indivplot);
115            cpgclos();
116          }
117        }               
118      }
119    }
120    else{
121      Plot::SpectralPlot newplot;
122      if(newplot.setUpPlot(spectrafile.c_str())>0) {
123
124        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
125          // for each object in the cube, assuming it is wanted:
126          if(objectChoice[nobj])  this->plotSpectrum(nobj,newplot);
127        }// end of loop over objects.
128        cpgclos();
129
130        if(this->par.getFlagUsePrevious()) std::cout << "\n";
131        for(size_t nobj=0;nobj<this->objectList->size();nobj++){
132          if(objectChoice[nobj] && this->par.getFlagUsePrevious()){
133            std::cout << "  Will output individual plot to "
134                      << getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size()) << "\n";
135            Plot::SpectralPlot indivplot;
136            indivplot.setUpPlot(getIndivPlotName(this->par.getSpectraFile(),nobj+1,this->objectList->size())+"/vcps");
137            this->plotSpectrum(nobj,indivplot);
138            cpgclos();
139          }
140        }               
141
142      }
143     
144    }
145  }
146  //--------------------------------------------------------------------
147
148  void Cube::plotSpectrum(int objNum, Plot::SpectralPlot &plot)
149  {
150    ///  @details
151    /// The way to print out the spectrum of a Detection.
152    /// Makes use of the SpectralPlot class in plots.hh, which sizes
153    ///  everything correctly.
154    ///
155    /// The main choice for the user is whether to use the peak pixel, in
156    /// which case the spectrum is just that of the peak pixel, or the
157    /// sum, where the spectrum is summed over all spatial pixels that
158    /// are in the object.
159    ///
160    /// If a reconstruction has been done, that spectrum is plotted in
161    /// red, and if a baseline has been calculated that is also shown, in
162    /// yellow.  The spectral limits of the detection are marked in blue.
163    /// A 0th moment map of the detection is also plotted, with a scale
164    /// bar indicating the spatial size.
165    ///
166    /// \param objNum The number of the Detection to be plotted.
167    /// \param plot The SpectralPlot object defining the PGPLOT device
168    ///        to plot the spectrum on.
169
170    long zdim = this->axisDim[2];
171
172    this->objectList->at(objNum).calcFluxes(this->array, this->axisDim);
173
174    double minMWvel=0,maxMWvel=0,xval,yval,zval;
175    xval = double(this->objectList->at(objNum).getXcentre());
176    yval = double(this->objectList->at(objNum).getYcentre());
177    if(this->par.getFlagMW()){
178      zval = double(this->par.getMinMW());
179      minMWvel = this->head.pixToVel(xval,yval,zval);
180      zval = double(this->par.getMaxMW());
181      maxMWvel = this->head.pixToVel(xval,yval,zval);
182    }
183
184    float *specx  = new float[zdim];
185    float *specy  = new float[zdim];
186    float *specy2 = new float[zdim];
187    float *base   = new float[zdim];
188//     float *specx, *specy, *specy2, *base;
189
190    this->getSpectralArrays(objNum,specx,specy,specy2,base);
191
192    std::string fluxLabel = "Flux";
193    std::string fluxUnits = this->head.getFluxUnits();
194    std::string intFluxUnits;// = this->head.getIntFluxUnits();
195    // Rather than use the intFluxUnits from the header, which will be like Jy MHz,
196    // we just use the pixel units, removing the /beam if necessary.
197
198    if(fluxUnits.size()>5 &&
199       makelower(fluxUnits.substr(fluxUnits.size()-5,
200                                  fluxUnits.size()   )) == "/beam"){
201      intFluxUnits = fluxUnits.substr(0,fluxUnits.size()-5);
202    }
203    else intFluxUnits = fluxUnits;
204   
205
206    if(this->par.getSpectralMethod()=="sum"){
207      fluxLabel = "Integrated " + fluxLabel;
208      if(this->head.isWCS()) {
209        fluxLabel += " ["+intFluxUnits+"]";
210      }
211    }
212    else {// if(par.getSpectralMethod()=="peak"){
213      fluxLabel = "Peak " + fluxLabel;
214      if(this->head.isWCS()) fluxLabel += " ["+fluxUnits+"]";
215    }
216   
217    float vmax,vmin,width;
218    vmax = vmin = specx[0];
219    for(int i=1;i<zdim;i++){
220      if(specx[i]>vmax) vmax=specx[i];
221      if(specx[i]<vmin) vmin=specx[i];
222    }
223 
224    float max,min;
225    int loc=0;
226    if(this->par.getMinMW()>0) max = min = specy[0];
227    else max = min = specy[this->par.getMaxMW()+1];
228    for(int i=0;i<zdim;i++){
229      if(!this->par.isInMW(i)){
230        if(specy[i]>max) max=specy[i];
231        if(specy[i]<min){
232          min=specy[i];
233          loc = i;
234        }
235      }
236    }
237    // widen the ranges slightly so that the top & bottom & edges don't
238    // lie on the axes.
239    width = max - min;
240    max += width * 0.05;
241    min -= width * 0.05;
242    width = vmax - vmin;
243    vmax += width * 0.01;
244    vmin -= width * 0.01;
245
246    // now plot the resulting spectrum
247    std::string label;
248    if(this->head.isWCS()){
249      label = this->head.getSpectralDescription() + " [" +
250        this->head.getSpectralUnits() + "]";
251      plot.gotoHeader(label);
252    }
253    else plot.gotoHeader("Spectral pixel value");
254
255    if(this->head.isWCS()){
256      label = this->objectList->at(objNum).outputLabelWCS();
257      plot.firstHeaderLine(label);
258      label = this->objectList->at(objNum).outputLabelFluxes();
259      plot.secondHeaderLine(label);
260    }
261    label = this->objectList->at(objNum).outputLabelWidths(this->head);
262    plot.thirdHeaderLine(label);
263    label = this->objectList->at(objNum).outputLabelPix();
264    plot.fourthHeaderLine(label);
265   
266    plot.gotoMainSpectrum(vmin,vmax,min,max,fluxLabel);
267    cpgline(zdim,specx,specy);
268    if(this->par.getFlagBaseline()){
269      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
270      cpgline(zdim,specx,base);
271      cpgsci(FOREGND);
272    }
273    if(this->reconExists){
274      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
275      cpgline(zdim,specx,specy2);   
276      cpgsci(FOREGND);
277    }
278    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
279    drawSpectralRange(plot,this->objectList->at(objNum),this->head);
280
281    if(this->par.getSpectralMethod()=="peak")
282      plot.drawThresholds(this->par,this->Stats);
283
284    /**************************/
285    // ZOOM IN SPECTRALLY ON THE DETECTION.
286
287    double 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        if(this->par.getFlagBaseline()){
300          if(base[i]>max) max=base[i];
301          if(base[i]<min) min=base[i];
302        }
303        if(this->reconExists){
304          if(specy2[i]>max) max=specy2[i];
305          if(specy2[i]<min) min=specy2[i];
306        }
307      }
308    }
309    // widen the flux range slightly so that the top & bottom don't lie
310    // on the axes.
311    width = max - min;
312    max += width * 0.05;
313    min -= width * 0.05;
314
315    plot.gotoZoomSpectrum(minvel,maxvel,min,max);
316    cpgline(zdim,specx,specy);
317    if(this->par.getFlagBaseline()){
318      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
319      cpgline(zdim,specx,base);
320      cpgsci(FOREGND);
321    }
322    if(this->reconExists){
323      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
324      cpgline(zdim,specx,specy2);   
325      cpgsci(FOREGND);
326    }
327    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
328    drawSpectralRange(plot,this->objectList->at(objNum),this->head);
329   
330    if(this->par.getSpectralMethod()=="peak")
331      plot.drawThresholds(this->par,this->Stats);
332
333    /**************************/
334
335    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
336    if(this->numNondegDim>1){
337      plot.gotoMap();
338      this->drawMomentCutout(this->objectList->at(objNum));
339    }
340
341    delete [] specx;
342    delete [] specy;
343    delete [] specy2;
344    delete [] base;
345 
346  }
347  //--------------------------------------------------------------------
348
349
350  void Cube::plotSource(Detection obj, Plot::CutoutPlot &plot)
351  {
352    ///  @details
353    /// The way to print out the 2d image cutout of a Detection.
354    /// Makes use of the CutoutPlot class in plots.hh, which sizes
355    ///  everything correctly.
356    ///
357    /// A 0th moment map of the detection is plotted, with a scale
358    /// bar indicating the spatial size.
359    ///
360    /// Basic information on the source is printed next to it as well.
361    ///
362    /// \param obj The Detection to be plotted.
363    /// \param plot The PGPLOT device to plot the spectrum on.
364
365    obj.calcFluxes(this->array, this->axisDim);
366
367    std::string label;
368    plot.gotoHeader();
369
370    if(this->head.isWCS()){
371      label = obj.outputLabelWCS();
372      plot.firstHeaderLine(label);
373      label = obj.outputLabelFluxes();
374      plot.secondHeaderLine(label);
375    }
376    label = obj.outputLabelWidths(this->head);
377    plot.thirdHeaderLine(label);
378    label = obj.outputLabelPix();
379    plot.fourthHeaderLine(label);
380   
381    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
382    plot.gotoMap();
383    this->drawMomentCutout(obj);
384
385  }
386
387}
Note: See TracBrowser for help on using the repository browser.