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

Last change on this file since 1429 was 1429, checked in by MatthewWhiting, 7 years ago

Fixing #525, where we need to define xloc & yloc for both strands of
the if clause. This stops us having a WCS error.

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