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

Last change on this file since 634 was 634, checked in by MatthewWhiting, 15 years ago

Initialising some variables so that they don't get used uninitialised (not that they would, but it avoids pedantic compilation warnings!).

File size: 17.9 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      if(this->par.getFlagTextSpectra()){
147        if(this->par.isVerbose()) std::cout << "  Saving spectra to text file ... ";
148        this->writeSpectralData();
149        if(this->par.isVerbose()) std::cout << "Done.\n";
150      }
151    }
152  }
153  //--------------------------------------------------------------------
154
155  void Cube::writeSpectralData()
156  {
157    /// @details
158    ///  A function to write, in ascii form, the spectra of each
159    ///  detected object to a file. The file consists of a column for
160    ///  the spectral coordinates, and one column for each object
161    ///  showing the flux at that spectral position. The units are the
162    ///  same as those shown in the graphical output. The filename is
163    ///  given by the Param::spectraTextFile parameter in the Cube::par
164    ///  parameter set.
165
166    const int zdim = this->axisDim[2];
167    const int numObj = this->objectList->size();
168    float *specxOut = new float[zdim];
169    float *spectra = new float[numObj*zdim];
170   
171    for(int obj=0; obj<numObj; obj++){
172      float *temp = new float[zdim];
173      float *specx = new float[zdim];
174      float *recon = new float[zdim];
175      float *base = new float[zdim];
176      this->getSpectralArrays(obj, specx, temp, recon, base);
177      for(int z=0;z<zdim;z++) spectra[obj*zdim+z] = temp[z];
178      if(obj==0) for(int z=0;z<zdim;z++) specxOut[z] = specx[z];
179      delete [] specx;
180      delete [] recon;
181      delete [] base;
182      delete [] temp;
183    }
184   
185    std::ofstream fspec(this->par.getSpectraTextFile().c_str());
186    fspec.setf(std::ios::fixed);
187
188    for(int z=0;z<zdim;z++){
189     
190      fspec << std::setprecision(8);
191      fspec << specxOut[z] << "  ";
192      for(int obj=0;obj<numObj; obj++) {
193        fspec << spectra[obj*zdim+z] << "  ";
194      }
195      fspec << "\n";
196
197    }
198    fspec.close();
199
200    delete [] spectra;
201    delete [] specxOut;
202
203  }
204  //--------------------------------------------------------------------
205
206  void Cube::plotSpectrum(int objNum, Plot::SpectralPlot &plot)
207  {
208    ///  @details
209    /// The way to print out the spectrum of a Detection.
210    /// Makes use of the SpectralPlot class in plots.hh, which sizes
211    ///  everything correctly.
212    ///
213    /// The main choice for the user is whether to use the peak pixel, in
214    /// which case the spectrum is just that of the peak pixel, or the
215    /// sum, where the spectrum is summed over all spatial pixels that
216    /// are in the object.
217    ///
218    /// If a reconstruction has been done, that spectrum is plotted in
219    /// red, and if a baseline has been calculated that is also shown, in
220    /// yellow.  The spectral limits of the detection are marked in blue.
221    /// A 0th moment map of the detection is also plotted, with a scale
222    /// bar indicating the spatial size.
223    ///
224    /// \param objNum The number of the Detection to be plotted.
225    /// \param plot The SpectralPlot object defining the PGPLOT device
226    ///        to plot the spectrum on.
227
228    long zdim = this->axisDim[2];
229
230    this->objectList->at(objNum).calcFluxes(this->array, this->axisDim);
231
232    double minMWvel=0,maxMWvel=0,xval,yval,zval;
233    xval = double(this->objectList->at(objNum).getXcentre());
234    yval = double(this->objectList->at(objNum).getYcentre());
235    if(this->par.getFlagMW()){
236      zval = double(this->par.getMinMW());
237      minMWvel = this->head.pixToVel(xval,yval,zval);
238      zval = double(this->par.getMaxMW());
239      maxMWvel = this->head.pixToVel(xval,yval,zval);
240    }
241
242    float *specx  = new float[zdim];
243    float *specy  = new float[zdim];
244    float *specy2 = new float[zdim];
245    float *base   = new float[zdim];
246//     float *specx, *specy, *specy2, *base;
247
248    this->getSpectralArrays(objNum,specx,specy,specy2,base);
249
250    std::string fluxLabel = "Flux";
251    std::string fluxUnits = this->head.getFluxUnits();
252    std::string intFluxUnits;// = this->head.getIntFluxUnits();
253    // Rather than use the intFluxUnits from the header, which will be like Jy MHz,
254    // we just use the pixel units, removing the /beam if necessary.
255
256    if(fluxUnits.size()>5 &&
257       makelower(fluxUnits.substr(fluxUnits.size()-5,
258                                  fluxUnits.size()   )) == "/beam"){
259      intFluxUnits = fluxUnits.substr(0,fluxUnits.size()-5);
260    }
261    else intFluxUnits = fluxUnits;
262   
263
264    if(this->par.getSpectralMethod()=="sum"){
265      fluxLabel = "Integrated " + fluxLabel;
266      if(this->head.isWCS()) {
267        fluxLabel += " ["+intFluxUnits+"]";
268      }
269    }
270    else {// if(par.getSpectralMethod()=="peak"){
271      fluxLabel = "Peak " + fluxLabel;
272      if(this->head.isWCS()) fluxLabel += " ["+fluxUnits+"]";
273    }
274   
275    float vmax,vmin,width;
276    vmax = vmin = specx[0];
277    for(int i=1;i<zdim;i++){
278      if(specx[i]>vmax) vmax=specx[i];
279      if(specx[i]<vmin) vmin=specx[i];
280    }
281 
282    float max,min;
283    int loc=0;
284    if(this->par.getMinMW()>0) max = min = specy[0];
285    else max = min = specy[this->par.getMaxMW()+1];
286    for(int i=0;i<zdim;i++){
287      if(!this->par.isInMW(i)){
288        if(specy[i]>max) max=specy[i];
289        if(specy[i]<min){
290          min=specy[i];
291          loc = i;
292        }
293      }
294    }
295    // widen the ranges slightly so that the top & bottom & edges don't
296    // lie on the axes.
297    width = max - min;
298    max += width * 0.05;
299    min -= width * 0.05;
300    width = vmax - vmin;
301    vmax += width * 0.01;
302    vmin -= width * 0.01;
303
304    // now plot the resulting spectrum
305    std::string label;
306    if(this->head.isWCS()){
307      label = this->head.getSpectralDescription() + " [" +
308        this->head.getSpectralUnits() + "]";
309      plot.gotoHeader(label);
310    }
311    else plot.gotoHeader("Spectral pixel value");
312
313    if(this->head.isWCS()){
314      label = this->objectList->at(objNum).outputLabelWCS();
315      plot.firstHeaderLine(label);
316      label = this->objectList->at(objNum).outputLabelFluxes();
317      plot.secondHeaderLine(label);
318    }
319    label = this->objectList->at(objNum).outputLabelWidths();
320    plot.thirdHeaderLine(label);
321    label = this->objectList->at(objNum).outputLabelPix();
322    plot.fourthHeaderLine(label);
323   
324    plot.gotoMainSpectrum(vmin,vmax,min,max,fluxLabel);
325    cpgline(zdim,specx,specy);
326    if(this->par.getFlagBaseline()){
327      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
328      cpgline(zdim,specx,base);
329      cpgsci(FOREGND);
330    }
331    if(this->reconExists){
332      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
333      cpgline(zdim,specx,specy2);   
334      cpgsci(FOREGND);
335    }
336    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
337    if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),this->objectList->at(objNum).getVelMax());
338    else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax());
339
340    /**************************/
341    // ZOOM IN SPECTRALLY ON THE DETECTION.
342
343    float minvel,maxvel;
344    if(this->head.isWCS()) getSmallVelRange(this->objectList->at(objNum),this->head,&minvel,&maxvel);
345    else getSmallZRange(this->objectList->at(objNum),&minvel,&maxvel);
346
347    // Find new max & min flux values
348    std::swap(max,min);
349    int ct = 0;
350    for(int i=0;i<zdim;i++){
351      if((!this->par.isInMW(i))&&(specx[i]>=minvel)&&(specx[i]<=maxvel)){
352        ct++;
353        if(specy[i]>max) max=specy[i];
354        if(specy[i]<min) min=specy[i];
355      }
356    }
357    // widen the flux range slightly so that the top & bottom don't lie
358    // on the axes.
359    width = max - min;
360    max += width * 0.05;
361    min -= width * 0.05;
362
363    plot.gotoZoomSpectrum(minvel,maxvel,min,max);
364    cpgline(zdim,specx,specy);
365    if(this->par.getFlagBaseline()){
366      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
367      cpgline(zdim,specx,base);
368      cpgsci(FOREGND);
369    }
370    if(this->reconExists){
371      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
372      cpgline(zdim,specx,specy2);   
373      cpgsci(FOREGND);
374    }
375    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
376    if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),
377                                             this->objectList->at(objNum).getVelMax());
378    else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax());
379   
380    /**************************/
381
382    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
383    plot.gotoMap();
384    this->drawMomentCutout(this->objectList->at(objNum));
385
386    delete [] specx;
387    delete [] specy;
388    delete [] specy2;
389    delete [] base;
390 
391  }
392  //--------------------------------------------------------------------
393
394  void getSmallVelRange(Detection &obj, FitsHeader head,
395                        float *minvel, float *maxvel)
396  {
397    ///  @details
398    ///  Routine to calculate the velocity range for the zoomed-in region.
399    ///  This range should be the maximum of 20 pixels, or 3x the wdith of
400    ///   the detection.
401    ///  Need to :
402    ///      Calculate pixel width of a 3x-detection-width region.
403    ///      If smaller than 20, calculate velocities of central vel +- 10 pixels
404    ///      If not, use the 3x-detection-width
405    ///  Range returned via "minvel" and "maxvel" parameters.
406    ///  \param obj Detection under examination.
407    ///  \param head FitsHeader, containing the WCS information.
408    ///  \param minvel Returned value of minimum velocity
409    ///  \param maxvel Returned value of maximum velocity
410
411    double *pixcrd = new double[3];
412    double *world  = new double[3];
413    float minpix,maxpix;
414    // define new velocity extrema
415    //    -- make it 3x wider than the width of the detection.
416    *minvel = 0.5*(obj.getVelMin()+obj.getVelMax()) - 1.5*obj.getVelWidth();
417    *maxvel = 0.5*(obj.getVelMin()+obj.getVelMax()) + 1.5*obj.getVelWidth();
418    // Find velocity range in number of pixels:
419    world[0] = obj.getRA();
420    world[1] = obj.getDec();
421    world[2] = head.velToSpec(*minvel);
422    head.wcsToPix(world,pixcrd);
423    minpix = pixcrd[2];
424    world[2] = head.velToSpec(*maxvel);
425    head.wcsToPix(world,pixcrd);
426    maxpix = pixcrd[2];
427    if(maxpix<minpix) std::swap(maxpix,minpix);
428   
429    if((maxpix - minpix + 1) < 20){
430      pixcrd[0] = double(obj.getXcentre());
431      pixcrd[1] = double(obj.getYcentre());
432      pixcrd[2] = obj.getZcentre() - 10.;
433      head.pixToWCS(pixcrd,world);
434      //    *minvel = setVel_kms(wcs,world[2]);
435      *minvel = head.specToVel(world[2]);
436      pixcrd[2] = obj.getZcentre() + 10.;
437      head.pixToWCS(pixcrd,world);
438      //     *maxvel = setVel_kms(wcs,world[2]);
439      *maxvel = head.specToVel(world[2]);
440      if(*maxvel<*minvel) std::swap(*maxvel,*minvel);
441    }
442    delete [] pixcrd;
443    delete [] world;
444
445  }
446  //--------------------------------------------------------------------
447
448  void getSmallZRange(Detection &obj, float *minz, float *maxz)
449  {
450    ///  @details
451    ///  Routine to calculate the pixel range for the zoomed-in spectrum.
452    ///  This range should be the maximum of 20 pixels, or 3x the width
453    ///   of the detection.
454    ///  Need to :
455    ///      Calculate pixel width of a 3x-detection-width region.
456    ///       If smaller than 20, use central pixel +- 10 pixels
457    ///  Range returned via "minz" and "maxz" parameters.
458    ///  \param obj Detection under examination.
459    ///  \param minz Returned value of minimum z-pixel coordinate
460    ///  \param maxz Returned value of maximum z-pixel coordinate
461
462    *minz = 2.*obj.getZmin() - obj.getZmax();
463    *maxz = 2.*obj.getZmax() - obj.getZmin();
464   
465    if((*maxz - *minz + 1) < 20){
466      *minz = obj.getZcentre() - 10.;
467      *maxz = obj.getZcentre() + 10.;
468    }
469
470  }
471  //--------------------------------------------------------------------
472
473  void Cube::plotSource(Detection obj, Plot::CutoutPlot &plot)
474  {
475    ///  @details
476    /// The way to print out the 2d image cutout of a Detection.
477    /// Makes use of the CutoutPlot class in plots.hh, which sizes
478    ///  everything correctly.
479    ///
480    /// A 0th moment map of the detection is plotted, with a scale
481    /// bar indicating the spatial size.
482    ///
483    /// Basic information on the source is printed next to it as well.
484    ///
485    /// \param obj The Detection to be plotted.
486    /// \param plot The PGPLOT device to plot the spectrum on.
487
488    obj.calcFluxes(this->array, this->axisDim);
489
490    std::string label;
491    plot.gotoHeader();
492
493    if(this->head.isWCS()){
494      label = obj.outputLabelWCS();
495      plot.firstHeaderLine(label);
496      label = obj.outputLabelFluxes();
497      plot.secondHeaderLine(label);
498    }
499    label = obj.outputLabelWidths();
500    plot.thirdHeaderLine(label);
501    label = obj.outputLabelPix();
502    plot.fourthHeaderLine(label);
503   
504    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
505    plot.gotoMap();
506    this->drawMomentCutout(obj);
507
508  }
509
510}
Note: See TracBrowser for help on using the repository browser.