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

Last change on this file since 500 was 499, checked in by MatthewWhiting, 16 years ago

Included this change in [498] without comment, so blank change here. This is fixing a bug noted in #42.

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