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

Last change on this file since 326 was 321, checked in by MatthewWhiting, 17 years ago
  • Solved most of the problem from ticket #12, where the integrated flux was being calculated differently on different machines. Now casting the spatial size of a detection to a double.
  • Solved ticket #13 as well, to allow compilation when PGPLOT is not available. Included moving cpgIsPS() to mycpgplot.cc.
File size: 12.1 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 <iomanip>
30#include <sstream>
31#include <string>
32#include <cpgplot.h>
33#include <math.h>
34#include <wcs.h>
35#include <param.hh>
36#include <duchamp.hh>
37#include <fitsHeader.hh>
38#include <PixelMap/Object3D.hh>
39#include <Cubes/cubes.hh>
40#include <Cubes/plots.hh>
41#include <Utils/utils.hh>
42#include <Utils/mycpgplot.hh>
43
44using namespace mycpgplot;
45using namespace PixelInfo;
46
47void getSmallVelRange(Detection &obj, FitsHeader head, float *minvel, float *maxvel);
48void getSmallZRange(Detection &obj, float *minz, float *maxz);
49
50void Cube::outputSpectra()
51{
52  /**
53   * The way to print out the spectra of the detected objects.
54   * Make use of the SpectralPlot class in plots.h, which sizes everything
55   *   correctly.
56   * Main choice is whether to use the peak pixel, in which case the
57   *  spectrum is just that of the peak pixel, or the sum, where the
58   *  spectrum is summed over all spatial pixels that are in the object.
59   * If a reconstruction has been done, that spectrum is plotted in red.
60   * The limits of the detection are marked in blue.
61   * A 0th moment map of the detection is also plotted, with a scale bar
62   *  indicating the spatial scale.
63   */
64
65  if(this->fullCols.size()==0) this->setupColumns();
66  // in case cols haven't been set -- need the precisions for printing values.
67
68  std::string spectrafile = this->par.getSpectraFile() + "/vcps";
69  Plot::SpectralPlot newplot;
70  if(newplot.setUpPlot(spectrafile.c_str())>0) {
71
72    for(int nobj=0;nobj<this->objectList->size();nobj++){
73      // for each object in the cube:
74      this->plotSpectrum(this->objectList->at(nobj),newplot);
75     
76    }// end of loop over objects.
77
78    cpgclos();
79  }
80}
81
82void Cube::plotSpectrum(Detection obj, Plot::SpectralPlot &plot)
83{
84  /**
85   * The way to print out the spectrum of a Detection.
86   * Makes use of the SpectralPlot class in plots.hh, which sizes
87   *  everything correctly.
88   *
89   * The main choice for the user is whether to use the peak pixel, in
90   * which case the spectrum is just that of the peak pixel, or the
91   * sum, where the spectrum is summed over all spatial pixels that
92   * are in the object.
93   *
94   * If a reconstruction has been done, that spectrum is plotted in
95   * red, and if a baseline has been calculated that is also shown, in
96   * yellow.  The spectral limits of the detection are marked in blue.
97   * A 0th moment map of the detection is also plotted, with a scale
98   * bar indicating the spatial size.
99   *
100   * \param obj The Detection to be plotted.
101   * \param plot The PGPLOT device to plot the spectrum on.
102   */
103
104  long xdim = this->axisDim[0];
105  long ydim = this->axisDim[1];
106  long zdim = this->axisDim[2];
107  float beam = this->par.getBeamSize();
108
109  obj.calcFluxes(this->array, this->axisDim);
110
111  double minMWvel,maxMWvel,xval,yval,zval;
112  xval = double(obj.getXcentre());
113  yval = double(obj.getYcentre());
114  if(this->par.getFlagMW()){
115    zval = double(this->par.getMinMW());
116    minMWvel = this->head.pixToVel(xval,yval,zval);
117    zval = double(this->par.getMaxMW());
118    maxMWvel = this->head.pixToVel(xval,yval,zval);
119  }
120
121  float *specx  = new float[zdim];
122  float *specy  = new float[zdim];
123  for(int i=0;i<zdim;i++) specy[i] = 0.;
124  float *specy2 = new float[zdim];
125  for(int i=0;i<zdim;i++) specy2[i] = 0.;
126  float *base   = new float[zdim];
127  for(int i=0;i<zdim;i++) base[i] = 0.;
128
129  for(int i=0;i<zdim;i++) specy[i] = 0.;
130  if(this->par.getFlagATrous()) 
131    for(int i=0;i<zdim;i++) specy2[i] = 0.;
132   
133  if(this->head.isWCS())
134    for(zval=0;zval<zdim;zval++)
135      specx[int(zval)] = this->head.pixToVel(xval,yval,zval);
136  else
137    for(zval=0;zval<zdim;zval++) specx[int(zval)] = zval;
138
139  std::string fluxLabel = "Flux";
140
141  if(this->par.getSpectralMethod()=="sum"){
142    fluxLabel = "Integrated " + fluxLabel;
143    if(this->head.isWCS())
144      fluxLabel += " ["+this->head.getIntFluxUnits()+"]";
145    bool *done = new bool[xdim*ydim];
146    for(int i=0;i<xdim*ydim;i++) done[i]=false;
147    std::vector<Voxel> voxlist = obj.pixels().getPixelSet();
148    for(int pix=0;pix<voxlist.size();pix++){
149      int pos = voxlist[pix].getX() + xdim * voxlist[pix].getY();
150      if(!done[pos]){
151        done[pos] = true;
152        for(int z=0;z<zdim;z++){
153          if(!(this->isBlank(pos+z*xdim*ydim))){
154            specy[z] += this->array[pos + z*xdim*ydim] / beam;
155            if(this->reconExists)
156              specy2[z] += this->recon[pos + z*xdim*ydim] / beam;
157            if(this->par.getFlagBaseline())
158              base[z] += this->baseline[pos + z*xdim*ydim] / beam;
159          }         
160        }
161      }
162    }
163    delete [] done;
164  }
165  else {// if(par.getSpectralMethod()=="peak"){
166    fluxLabel = "Peak " + fluxLabel;
167    if(this->head.isWCS()) fluxLabel += " ["+this->head.getFluxUnits()+"]";
168    int pos = obj.getXPeak() + xdim*obj.getYPeak();
169    for(int z=0;z<zdim;z++){
170      specy[z] = this->array[pos + z*xdim*ydim];
171      if(this->reconExists)
172        specy2[z] = this->recon[pos + z*xdim*ydim];
173      if(this->par.getFlagBaseline())
174        base[z] = this->baseline[pos + z*xdim*ydim];
175    }
176  }
177   
178  float vmax,vmin,width;
179  vmax = vmin = specx[0];
180  for(int i=1;i<zdim;i++){
181    if(specx[i]>vmax) vmax=specx[i];
182    if(specx[i]<vmin) vmin=specx[i];
183  }
184 
185  float max,min;
186  int loc=0;
187  if(this->par.getMinMW()>0) max = min = specy[0];
188  else max = min = specx[this->par.getMaxMW()+1];
189  for(int i=0;i<zdim;i++){
190    if(!this->par.isInMW(i)){
191      if(specy[i]>max) max=specy[i];
192      if(specy[i]<min){
193        min=specy[i];
194        loc = i;
195      }
196    }
197  }
198  // widen the ranges slightly so that the top & bottom & edges don't
199  // lie on the axes.
200  width = max - min;
201  max += width * 0.05;
202  min -= width * 0.05;
203  width = vmax -vmin;
204  vmax += width * 0.01;
205  vmin -= width * 0.01;
206
207  // now plot the resulting spectrum
208  std::string label;
209  if(this->head.isWCS()){
210    label = this->head.getSpectralDescription() + " [" +
211      this->head.getSpectralUnits() + "]";
212    plot.gotoHeader(label);
213  }
214  else plot.gotoHeader("Spectral pixel value");
215
216  if(this->head.isWCS()){
217    label = obj.outputLabelWCS();
218    plot.firstHeaderLine(label);
219    label = obj.outputLabelFluxes();
220    plot.secondHeaderLine(label);
221  }
222  label = obj.outputLabelWidths();
223  plot.thirdHeaderLine(label);
224  label = obj.outputLabelPix();
225  plot.fourthHeaderLine(label);
226   
227  plot.gotoMainSpectrum(vmin,vmax,min,max,fluxLabel);
228  cpgline(zdim,specx,specy);
229  if(this->par.getFlagBaseline()){
230    cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
231    cpgline(zdim,specx,base);
232    cpgsci(FOREGND);
233  }
234  if(this->reconExists){
235    cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
236    cpgline(zdim,specx,specy2);   
237    cpgsci(FOREGND);
238  }
239  if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
240  if(this->head.isWCS()) plot.drawVelRange(obj.getVelMin(),obj.getVelMax());
241  else plot.drawVelRange(obj.getZmin(),obj.getZmax());
242
243  /**************************/
244  // ZOOM IN SPECTRALLY ON THE DETECTION.
245
246  float minvel,maxvel;
247  if(this->head.isWCS()) getSmallVelRange(obj,this->head,&minvel,&maxvel);
248  else getSmallZRange(obj,&minvel,&maxvel);
249
250  // Find new max & min flux values
251  std::swap(max,min);
252  int ct = 0;
253  for(int i=0;i<zdim;i++){
254    if((!this->par.isInMW(i))&&(specx[i]>=minvel)&&(specx[i]<=maxvel)){
255      ct++;
256      if(specy[i]>max) max=specy[i];
257      if(specy[i]<min) min=specy[i];
258    }
259  }
260  // widen the flux range slightly so that the top & bottom don't lie
261  // on the axes.
262  width = max - min;
263  max += width * 0.05;
264  min -= width * 0.05;
265
266  plot.gotoZoomSpectrum(minvel,maxvel,min,max);
267  cpgline(zdim,specx,specy);
268  if(this->par.getFlagBaseline()){
269    cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
270    cpgline(zdim,specx,base);
271    cpgsci(FOREGND);
272  }
273  if(this->reconExists){
274    cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
275    cpgline(zdim,specx,specy2);   
276    cpgsci(FOREGND);
277  }
278  if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel);
279  if(this->head.isWCS()) plot.drawVelRange(obj.getVelMin(),obj.getVelMax());
280  else plot.drawVelRange(obj.getZmin(),obj.getZmax());
281   
282  /**************************/
283
284  // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS
285  plot.gotoMap();
286  this->drawMomentCutout(obj);
287
288  delete [] specx;
289  delete [] specy;
290  delete [] specy2;
291  delete [] base;
292 
293}
294
295
296void getSmallVelRange(Detection &obj, FitsHeader head,
297                      float *minvel, float *maxvel)
298{
299  /**
300   *  Routine to calculate the velocity range for the zoomed-in region.
301   *  This range should be the maximum of 20 pixels, or 3x the wdith of
302   *   the detection.
303   *  Need to :
304   *      Calculate pixel width of a 3x-detection-width region.
305   *      If smaller than 20, calculate velocities of central vel +- 10 pixels
306   *      If not, use the 3x-detection-width
307   *  Range returned via "minvel" and "maxvel" parameters.
308   *  \param obj Detection under examination.
309   *  \param head FitsHeader, containing the WCS information.
310   *  \param minvel Returned value of minimum velocity
311   *  \param maxvel Returned value of maximum velocity
312   */
313
314  double *pixcrd = new double[3];
315  double *world  = new double[3];
316  float minpix,maxpix;
317  // define new velocity extrema
318  //    -- make it 3x wider than the width of the detection.
319  *minvel = 0.5*(obj.getVelMin()+obj.getVelMax()) - 1.5*obj.getVelWidth();
320  *maxvel = 0.5*(obj.getVelMin()+obj.getVelMax()) + 1.5*obj.getVelWidth();
321  // Find velocity range in number of pixels:
322  world[0] = obj.getRA();
323  world[1] = obj.getDec();
324  world[2] = head.velToSpec(*minvel);
325  head.wcsToPix(world,pixcrd);
326  minpix = pixcrd[2];
327  world[2] = head.velToSpec(*maxvel);
328  head.wcsToPix(world,pixcrd);
329  maxpix = pixcrd[2];
330  if(maxpix<minpix) std::swap(maxpix,minpix);
331   
332  if((maxpix - minpix + 1) < 20){
333    pixcrd[0] = double(obj.getXcentre());
334    pixcrd[1] = double(obj.getYcentre());
335    pixcrd[2] = obj.getZcentre() - 10.;
336    head.pixToWCS(pixcrd,world);
337    //    *minvel = setVel_kms(wcs,world[2]);
338    *minvel = head.specToVel(world[2]);
339    pixcrd[2] = obj.getZcentre() + 10.;
340    head.pixToWCS(pixcrd,world);
341    //     *maxvel = setVel_kms(wcs,world[2]);
342    *maxvel = head.specToVel(world[2]);
343    if(*maxvel<*minvel) std::swap(*maxvel,*minvel);
344  }
345  delete [] pixcrd;
346  delete [] world;
347
348}
349
350void getSmallZRange(Detection &obj, float *minz, float *maxz)
351{
352  /**
353   *  Routine to calculate the pixel range for the zoomed-in spectrum.
354   *  This range should be the maximum of 20 pixels, or 3x the width
355   *   of the detection.
356   *  Need to :
357   *      Calculate pixel width of a 3x-detection-width region.
358   *       If smaller than 20, use central pixel +- 10 pixels
359   *  Range returned via "minz" and "maxz" parameters.
360   *  \param obj Detection under examination.
361   *  \param minz Returned value of minimum z-pixel coordinate
362   *  \param maxz Returned value of maximum z-pixel coordinate
363   */
364
365  *minz = 2.*obj.getZmin() - obj.getZmax();
366  *maxz = 2.*obj.getZmax() - obj.getZmin();
367   
368  if((*maxz - *minz + 1) < 20){
369    *minz = obj.getZcentre() - 10.;
370    *maxz = obj.getZcentre() + 10.;
371  }
372
373}
Note: See TracBrowser for help on using the repository browser.