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

Last change on this file since 1455 was 485, checked in by MatthewWhiting, 16 years ago

Some minor changes, primarily affecting the text written to screen.

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    if(makelower(fluxUnits.substr(fluxUnits.size()-5,
259                                  fluxUnits.size()   )) == "/beam"){
260      intFluxUnits = fluxUnits.substr(0,fluxUnits.size()-5);
261    }
262    else intFluxUnits = fluxUnits;
263   
264
265    if(this->par.getSpectralMethod()=="sum"){
266      fluxLabel = "Integrated " + fluxLabel;
267      if(this->head.isWCS()) {
268        fluxLabel += " ["+intFluxUnits+"]";
269      }
270    }
271    else {// if(par.getSpectralMethod()=="peak"){
272      fluxLabel = "Peak " + fluxLabel;
273      if(this->head.isWCS()) fluxLabel += " ["+fluxUnits+"]";
274    }
275   
276    float vmax,vmin,width;
277    vmax = vmin = specx[0];
278    for(int i=1;i<zdim;i++){
279      if(specx[i]>vmax) vmax=specx[i];
280      if(specx[i]<vmin) vmin=specx[i];
281    }
282 
283    float max,min;
284    int loc=0;
285    if(this->par.getMinMW()>0) max = min = specy[0];
286    else max = min = specy[this->par.getMaxMW()+1];
287    for(int i=0;i<zdim;i++){
288      if(!this->par.isInMW(i)){
289        if(specy[i]>max) max=specy[i];
290        if(specy[i]<min){
291          min=specy[i];
292          loc = i;
293        }
294      }
295    }
296    // widen the ranges slightly so that the top & bottom & edges don't
297    // lie on the axes.
298    width = max - min;
299    max += width * 0.05;
300    min -= width * 0.05;
301    width = vmax - vmin;
302    vmax += width * 0.01;
303    vmin -= width * 0.01;
304
305    // now plot the resulting spectrum
306    std::string label;
307    if(this->head.isWCS()){
308      label = this->head.getSpectralDescription() + " [" +
309        this->head.getSpectralUnits() + "]";
310      plot.gotoHeader(label);
311    }
312    else plot.gotoHeader("Spectral pixel value");
313
314    if(this->head.isWCS()){
315      label = this->objectList->at(objNum).outputLabelWCS();
316      plot.firstHeaderLine(label);
317      label = this->objectList->at(objNum).outputLabelFluxes();
318      plot.secondHeaderLine(label);
319    }
320    label = this->objectList->at(objNum).outputLabelWidths();
321    plot.thirdHeaderLine(label);
322    label = this->objectList->at(objNum).outputLabelPix();
323    plot.fourthHeaderLine(label);
324   
325    plot.gotoMainSpectrum(vmin,vmax,min,max,fluxLabel);
326    cpgline(zdim,specx,specy);
327    if(this->par.getFlagBaseline()){
328      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
329      cpgline(zdim,specx,base);
330      cpgsci(FOREGND);
331    }
332    if(this->reconExists){
333      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
334      cpgline(zdim,specx,specy2);   
335      cpgsci(FOREGND);
336    }
337    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
338    if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),this->objectList->at(objNum).getVelMax());
339    else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax());
340
341    /**************************/
342    // ZOOM IN SPECTRALLY ON THE DETECTION.
343
344    float minvel,maxvel;
345    if(this->head.isWCS()) getSmallVelRange(this->objectList->at(objNum),this->head,&minvel,&maxvel);
346    else getSmallZRange(this->objectList->at(objNum),&minvel,&maxvel);
347
348    // Find new max & min flux values
349    std::swap(max,min);
350    int ct = 0;
351    for(int i=0;i<zdim;i++){
352      if((!this->par.isInMW(i))&&(specx[i]>=minvel)&&(specx[i]<=maxvel)){
353        ct++;
354        if(specy[i]>max) max=specy[i];
355        if(specy[i]<min) min=specy[i];
356      }
357    }
358    // widen the flux range slightly so that the top & bottom don't lie
359    // on the axes.
360    width = max - min;
361    max += width * 0.05;
362    min -= width * 0.05;
363
364    plot.gotoZoomSpectrum(minvel,maxvel,min,max);
365    cpgline(zdim,specx,specy);
366    if(this->par.getFlagBaseline()){
367      cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
368      cpgline(zdim,specx,base);
369      cpgsci(FOREGND);
370    }
371    if(this->reconExists){
372      cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
373      cpgline(zdim,specx,specy2);   
374      cpgsci(FOREGND);
375    }
376    if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
377    if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),
378                                             this->objectList->at(objNum).getVelMax());
379    else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax());
380   
381    /**************************/
382
383    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
384    plot.gotoMap();
385    this->drawMomentCutout(this->objectList->at(objNum));
386
387    delete [] specx;
388    delete [] specy;
389    delete [] specy2;
390    delete [] base;
391 
392  }
393  //--------------------------------------------------------------------
394
395  void getSmallVelRange(Detection &obj, FitsHeader head,
396                        float *minvel, float *maxvel)
397  {
398    /**
399     *  Routine to calculate the velocity range for the zoomed-in region.
400     *  This range should be the maximum of 20 pixels, or 3x the wdith of
401     *   the detection.
402     *  Need to :
403     *      Calculate pixel width of a 3x-detection-width region.
404     *      If smaller than 20, calculate velocities of central vel +- 10 pixels
405     *      If not, use the 3x-detection-width
406     *  Range returned via "minvel" and "maxvel" parameters.
407     *  \param obj Detection under examination.
408     *  \param head FitsHeader, containing the WCS information.
409     *  \param minvel Returned value of minimum velocity
410     *  \param maxvel Returned value of maximum velocity
411     */
412
413    double *pixcrd = new double[3];
414    double *world  = new double[3];
415    float minpix,maxpix;
416    // define new velocity extrema
417    //    -- make it 3x wider than the width of the detection.
418    *minvel = 0.5*(obj.getVelMin()+obj.getVelMax()) - 1.5*obj.getVelWidth();
419    *maxvel = 0.5*(obj.getVelMin()+obj.getVelMax()) + 1.5*obj.getVelWidth();
420    // Find velocity range in number of pixels:
421    world[0] = obj.getRA();
422    world[1] = obj.getDec();
423    world[2] = head.velToSpec(*minvel);
424    head.wcsToPix(world,pixcrd);
425    minpix = pixcrd[2];
426    world[2] = head.velToSpec(*maxvel);
427    head.wcsToPix(world,pixcrd);
428    maxpix = pixcrd[2];
429    if(maxpix<minpix) std::swap(maxpix,minpix);
430   
431    if((maxpix - minpix + 1) < 20){
432      pixcrd[0] = double(obj.getXcentre());
433      pixcrd[1] = double(obj.getYcentre());
434      pixcrd[2] = obj.getZcentre() - 10.;
435      head.pixToWCS(pixcrd,world);
436      //    *minvel = setVel_kms(wcs,world[2]);
437      *minvel = head.specToVel(world[2]);
438      pixcrd[2] = obj.getZcentre() + 10.;
439      head.pixToWCS(pixcrd,world);
440      //     *maxvel = setVel_kms(wcs,world[2]);
441      *maxvel = head.specToVel(world[2]);
442      if(*maxvel<*minvel) std::swap(*maxvel,*minvel);
443    }
444    delete [] pixcrd;
445    delete [] world;
446
447  }
448  //--------------------------------------------------------------------
449
450  void getSmallZRange(Detection &obj, float *minz, float *maxz)
451  {
452    /**
453     *  Routine to calculate the pixel range for the zoomed-in spectrum.
454     *  This range should be the maximum of 20 pixels, or 3x the width
455     *   of the detection.
456     *  Need to :
457     *      Calculate pixel width of a 3x-detection-width region.
458     *       If smaller than 20, use central pixel +- 10 pixels
459     *  Range returned via "minz" and "maxz" parameters.
460     *  \param obj Detection under examination.
461     *  \param minz Returned value of minimum z-pixel coordinate
462     *  \param maxz Returned value of maximum z-pixel coordinate
463     */
464
465    *minz = 2.*obj.getZmin() - obj.getZmax();
466    *maxz = 2.*obj.getZmax() - obj.getZmin();
467   
468    if((*maxz - *minz + 1) < 20){
469      *minz = obj.getZcentre() - 10.;
470      *maxz = obj.getZcentre() + 10.;
471    }
472
473  }
474  //--------------------------------------------------------------------
475
476  void Cube::plotSource(Detection obj, Plot::CutoutPlot &plot)
477  {
478    /**
479     * The way to print out the 2d image cutout of a Detection.
480     * Makes use of the CutoutPlot class in plots.hh, which sizes
481     *  everything correctly.
482     *
483     * A 0th moment map of the detection is plotted, with a scale
484     * bar indicating the spatial size.
485     *
486     * Basic information on the source is printed next to it as well.
487     *
488     * \param obj The Detection to be plotted.
489     * \param plot The PGPLOT device to plot the spectrum on.
490     */
491
492    obj.calcFluxes(this->array, this->axisDim);
493
494    std::string label;
495    plot.gotoHeader();
496
497    if(this->head.isWCS()){
498      label = obj.outputLabelWCS();
499      plot.firstHeaderLine(label);
500      label = obj.outputLabelFluxes();
501      plot.secondHeaderLine(label);
502    }
503    label = obj.outputLabelWidths();
504    plot.thirdHeaderLine(label);
505    label = obj.outputLabelPix();
506    plot.fourthHeaderLine(label);
507   
508    // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
509    plot.gotoMap();
510    this->drawMomentCutout(obj);
511
512  }
513
514}
Note: See TracBrowser for help on using the repository browser.