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

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

Tickets #193 & #195 - Implementing channel flagging. Still a lot of commented-out code, plus the MW code is still present (although not used anywhere). Also making use of the new plotting classes.

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