source: tags/release-1.1.7/src/Cubes/outputSpectra.cc @ 1455

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

Including the recent minor changes to 1.1.7.

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(uint 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(uint 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(uint 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(uint 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,maxMWvel,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.