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

Last change on this file since 1364 was 1361, checked in by MatthewWhiting, 10 years ago

Ticket #219 - largely addressing the problem. When doing negative + baseline modes, need to undo the inversion & baseline removal in two steps, so that we get the right sequencing of parameterisation and inversion of values. Also removing the reInvert() function, as it is no longer used.

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