source: trunk/src/Cubes/spectraUtils.cc @ 987

Last change on this file since 987 was 985, checked in by MatthewWhiting, 12 years ago

Ticket #148: Enabling output of the spectrum highlighting the detections that have been made, as well as the final objects. This is to replace the moment map output that is not possible in 1D mode. Some functions
have been moved around (from outputSpectra to spectraUtils) and a new class added to plots.hh

File size: 14.9 KB
Line 
1// -----------------------------------------------------------------------
2// spectraUtils.cc: Utility functions to obtain & manipulate spectra
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 <vector>
34#include <math.h>
35#include <wcslib/wcs.h>
36#include <duchamp/Cubes/cubeUtils.hh>
37#include <duchamp/param.hh>
38#include <duchamp/duchamp.hh>
39#include <duchamp/fitsHeader.hh>
40#include <duchamp/PixelMap/Object3D.hh>
41#include <duchamp/Cubes/cubes.hh>
42#include <duchamp/Utils/utils.hh>
43
44using namespace PixelInfo;
45
46namespace duchamp
47{
48
49  void getSpecAbscissae(Detection &object, FitsHeader &head, size_t zdim, float *abscissae)
50  {
51    /// @details
52    ///  A function that returns an array of
53    ///  frequency/velocity/channel/etc values (that can be used as the
54    ///  abscissae on the spectral plot).
55    ///  \param object The object on which our spectrum is centered (in
56    ///  case the spectral value changes with x & y
57    ///  \param head The FitsHeader set of parameters that determine the coordinate transformation.
58    ///  \param zdim The length of the spectral axis
59    ///  \param abscissae The array of spectral values -- must be allocated first
60
61    getSpecAbscissae(head,object.getXcentre(),object.getYcentre(),zdim, abscissae);
62  }
63
64  void getSpecAbscissae(FitsHeader &head, float xpt, float ypt, size_t zdim, float *abscissae)
65  {
66    /// @details
67    ///  A function that returns an array of
68    ///  frequency/velocity/channel/etc values (that can be used as the
69    ///  horizontal axis on the spectral plot).
70    ///  \param head The FitsHeader set of parameters that determine the coordinate transformation.
71    ///  \param xpt The x-value of the spatial position on which our spectrum is centred.
72    ///  \param ypt The y-value of the spatial position on which our spectrum is centred.
73    ///  \param zdim The length of the spectral axis
74    ///  \param abscissae The array of spectral values -- must be allocated first.
75
76    if(head.isWCS()){
77      double xval = double(xpt);
78      double yval = double(ypt);
79      for(double zval=0;zval<zdim;zval++)
80        abscissae[int(zval)] = head.pixToVel(xval,yval,zval);
81    }
82    else
83      for(double zval=0;zval<zdim;zval++) abscissae[int(zval)] = zval;
84
85  }
86  //--------------------------------------------------------------------
87
88  void getIntSpec(Detection &object, float *fluxArray, size_t *dimArray, std::vector<bool> mask,
89                  float beamCorrection, float *spec)
90  {
91    /// @details
92    ///  The base function that extracts an integrated spectrum for a
93    ///  given object from a pixel array. The spectrum is returned as
94    ///  the integrated flux, corrected for the beam using the given
95    ///  correction factor.
96    ///   \param object The Detection in question
97    ///   \param fluxArray The full array of pixel values.
98    ///   \param dimArray The axis dimensions for the fluxArray
99    ///   \param mask A mask array indicating whether given pixels are valid
100    ///   \param beamCorrection How much to divide the summed spectrum
101    ///   by to return the integrated flux.
102    ///   \param spec The integrated spectrum for the object -- must be allocated first.
103
104    for(size_t i=0;i<dimArray[2];i++) spec[i] = 0.;
105    size_t xySize = dimArray[0]*dimArray[1];
106    bool *done = new bool[xySize];
107    for(size_t i=0;i<xySize;i++) done[i]=false;
108    std::vector<Voxel> voxlist = object.getPixelSet();
109    std::vector<Voxel>::iterator vox;
110    for(vox=voxlist.begin();vox<voxlist.end();vox++){
111      size_t pos = vox->getX() + dimArray[0] * vox->getY();
112      if(!done[pos]){
113        done[pos] = true;
114        for(size_t z=0;z<dimArray[2];z++){
115          if(mask[pos+z*xySize]){
116            spec[z] += fluxArray[pos + z*xySize] / beamCorrection;
117          }         
118        }
119      }
120    }
121    delete [] done;
122
123  }
124  //--------------------------------------------------------------------
125
126  void getPeakSpec(Detection &object, float *fluxArray, size_t *dimArray, bool *mask, float *spec)
127  {
128    /// @details
129    ///  The base function that extracts an peak spectrum for a
130    ///  given object from a pixel array. The spectrum is returned as
131    ///  the integrated flux, corrected for the beam using the given
132    ///  correction factor.
133    ///   \param object The Detection in question
134    ///   \param fluxArray The full array of pixel values.
135    ///   \param dimArray The axis dimensions for the fluxArray
136    ///   \param mask A mask array indicating whether given pixels are valid
137    ///   \param spec The peak spectrum for the object -- must be allocated first
138
139    if((object.getXPeak()<0 || object.getXPeak()>=int(dimArray[0])) || (object.getYPeak()<0 || object.getYPeak()>=int(dimArray[1]))){
140      DUCHAMPWARN("getPeakSpec","Object peak outside array boundaries");
141      for (size_t z=0;z<dimArray[2];z++) spec[z]=0.;
142    }
143    else{
144      size_t xySize = dimArray[0]*dimArray[1];
145      size_t pos = object.getXPeak() + dimArray[0]*object.getYPeak();
146      for(size_t z=0;z<dimArray[2];z++){
147        if(mask[pos + z*xySize])
148          spec[z] = fluxArray[pos + z*xySize];
149      }
150    }
151  }
152  //--------------------------------------------------------------------
153
154
155  void Cube::getSpectralArrays(int objNum, float *specx, float *specy,
156                               float *specRecon, float *specBase)
157  {
158    /// @details
159    ///  A utility function that goes and calculates, for a given
160    ///  Detection, the spectral arrays, according to whether we want
161    ///  the peak or integrated flux. The arrays can be used by
162    ///  Cube::plotSpectrum() and Cube::writeSpectralData(). The arrays
163    ///  calculated are listed below. Their length is given by the
164    ///  length of the Cube's spectral dimension.
165    ///
166    ///  Note that the arrays need to be allocated prior to calling
167    ///  this function.
168    ///
169    ///  \param objNum The number of the object under
170    ///         consideration. If negative, we extract the single
171    ///         spectrum at (x,y)=(0,0) (useful for the 1D case).
172    ///  \param specx The array of frequency/velocity/channel/etc
173    ///         values (the x-axis on the spectral plot).
174    ///  \param specy The array of flux values, matching the specx
175    ///         array.
176    ///  \param specRecon The reconstructed or smoothed array, done in
177    ///         the same way as specy.
178    ///  \param specBase The fitted baseline values, done in the same
179    ///         way as specy.
180
181    size_t xdim = this->axisDim[0];
182    size_t ydim = this->axisDim[1];
183    size_t zdim = this->axisDim[2];
184       
185    for(size_t i=0;i<zdim;i++){
186      specy[i]     = 0.;
187      specRecon[i] = 0.;
188      specBase[i]  = 0.;
189    }
190
191    double xloc,yloc;
192    size_t spatpos=0;
193    std::vector<Voxel> voxlist;
194    if(objNum>=0){
195      if(this->par.getSpectralMethod()=="sum"){
196        xloc=double(this->objectList->at(objNum).getXcentre());
197        yloc=double(this->objectList->at(objNum).getYcentre());
198        voxlist = this->objectList->at(objNum).getPixelSet();
199      }
200      else{
201        spatpos = this->objectList->at(objNum).getXPeak() +
202        xdim*this->objectList->at(objNum).getYPeak();
203      }
204    }
205
206    if(this->head.isWCS()){
207//       double xval = double(this->objectList->at(objNum).getXcentre());
208//       double yval = double(this->objectList->at(objNum).getYcentre());
209//       for(double zval=0;zval<zdim;zval++)
210//      specx[int(zval)] = this->head.pixToVel(xval,yval,zval);
211      for(double zval=0;zval<zdim;zval++)
212        specx[int(zval)] = this->head.pixToVel(xloc,yloc,zval);
213    }
214    else
215      for(double zval=0;zval<zdim;zval++) specx[int(zval)] = zval;
216       
217    float beamCorrection;
218    if(this->header().needBeamSize())
219      beamCorrection = this->head.beam().area();
220    else beamCorrection = 1.;
221       
222    if(objNum>=0 && this->par.getSpectralMethod()=="sum"){
223      bool *done = new bool[xdim*ydim];
224      for(size_t i=0;i<xdim*ydim;i++) done[i]=false;
225//       std::vector<Voxel> voxlist = this->objectList->at(objNum).getPixelSet();
226      std::vector<Voxel>::iterator vox;
227      for(vox=voxlist.begin();vox<voxlist.end();vox++){
228        spatpos = vox->getX() + xdim * vox->getY();
229        if(!done[spatpos]){
230          done[spatpos] = true;
231          for(size_t z=0;z<zdim;z++){
232            if(!(this->isBlank(spatpos+z*xdim*ydim))){
233              specy[z] += this->array[spatpos + z*xdim*ydim] / beamCorrection;
234              if(this->reconExists)
235                specRecon[z] += this->recon[spatpos + z*xdim*ydim] / beamCorrection;
236              if(this->par.getFlagBaseline())
237                specBase[z] += this->baseline[spatpos + z*xdim*ydim] / beamCorrection;
238            }       
239          }
240        }
241      }
242      delete [] done;
243    }
244    else {// if(par.getSpectralMethod()=="peak"){
245//       size_t spatpos = this->objectList->at(objNum).getXPeak() +
246//      xdim*this->objectList->at(objNum).getYPeak();
247      for(size_t z=0;z<zdim;z++){
248        specy[z] = this->array[spatpos + z*xdim*ydim];
249        if(this->reconExists)
250          specRecon[z] = this->recon[spatpos + z*xdim*ydim];
251        if(this->par.getFlagBaseline())
252          specBase[z] = this->baseline[spatpos + z*xdim*ydim];
253      }
254    }
255
256  }
257  //--------------------------------------------------------------------
258
259  void drawSpectralRange(Plot::SpectralPlot &plot, Detection &obj, FitsHeader &head)
260  {
261    /// @details
262
263    /// A front-end to drawing the lines delimiting the spectral
264    /// extent of the detection. This takes into account the channel
265    /// widths, offsetting outwards by half a channel (for instance, a
266    /// single-channel detection will not have the separation of one
267    /// channel).
268    /// If the world coordinate is being plotted, the correct offset
269    /// is calcuated by transforming from the central spatial
270    /// positions and the offsetted min/max z-pixel extents
271
272    if(head.isWCS()){
273      double x=obj.getXcentre(),y=obj.getYcentre(),z;
274      z=obj.getZmin()-0.5;
275      float vmin=head.pixToVel(x,y,z);
276      z=obj.getZmax()+0.5;
277      float vmax=head.pixToVel(x,y,z);
278      plot.drawVelRange(vmin,vmax);
279    }
280    else{
281      plot.drawVelRange(obj.getZmin()-0.5,obj.getZmax()+0.5);
282    }
283
284
285  }
286
287  void drawSpectralRange(Plot::SimpleSpectralPlot &plot, Detection &obj, FitsHeader &head)
288  {
289    /// @details
290
291    /// A front-end to drawing the lines delimiting the spectral
292    /// extent of the detection. This takes into account the channel
293    /// widths, offsetting outwards by half a channel (for instance, a
294    /// single-channel detection will not have the separation of one
295    /// channel).
296    /// If the world coordinate is being plotted, the correct offset
297    /// is calcuated by transforming from the central spatial
298    /// positions and the offsetted min/max z-pixel extents
299
300    if(head.isWCS()){
301      double x=obj.getXcentre(),y=obj.getYcentre(),z;
302      z=obj.getZmin()-0.5;
303      float vmin=head.pixToVel(x,y,z);
304      z=obj.getZmax()+0.5;
305      float vmax=head.pixToVel(x,y,z);
306      plot.drawVelRange(vmin,vmax);
307    }
308    else{
309      plot.drawVelRange(obj.getZmin()-0.5,obj.getZmax()+0.5);
310    }
311
312
313  }
314
315  void getSmallVelRange(Detection &obj, FitsHeader &head,
316                        double *minvel, double *maxvel)
317  {
318    ///  @details
319    ///  Routine to calculate the velocity range for the zoomed-in region.
320    ///  This range should be the maximum of 20 pixels, or 3x the wdith of
321    ///   the detection.
322    ///  Need to :
323    ///      Calculate pixel width of a 3x-detection-width region.
324    ///      If smaller than 20, calculate velocities of central vel +- 10 pixels
325    ///      If not, use the 3x-detection-width
326    ///  Range returned via "minvel" and "maxvel" parameters.
327    ///  \param obj Detection under examination.
328    ///  \param head FitsHeader, containing the WCS information.
329    ///  \param minvel Returned value of minimum velocity
330    ///  \param maxvel Returned value of maximum velocity
331
332    double *pixcrd = new double[3];
333    double *world  = new double[3];
334    float minpix,maxpix;
335    // define new velocity extrema
336    //    -- make it 3x wider than the width of the detection.
337    *minvel = 0.5*(obj.getVelMin()+obj.getVelMax()) - 1.5*obj.getVelWidth();
338    *maxvel = 0.5*(obj.getVelMin()+obj.getVelMax()) + 1.5*obj.getVelWidth();
339    // Find velocity range in number of pixels:
340    world[0] = obj.getRA();
341    world[1] = obj.getDec();
342    world[2] = head.velToSpec(*minvel);
343    head.wcsToPix(world,pixcrd);
344    minpix = pixcrd[2];
345    world[2] = head.velToSpec(*maxvel);
346    head.wcsToPix(world,pixcrd);
347    maxpix = pixcrd[2];
348    if(maxpix<minpix) std::swap(maxpix,minpix);
349   
350    if((maxpix - minpix + 1) < 20){
351      pixcrd[0] = double(obj.getXcentre());
352      pixcrd[1] = double(obj.getYcentre());
353      pixcrd[2] = obj.getZcentre() - 10.;
354      head.pixToWCS(pixcrd,world);
355      //    *minvel = setVel_kms(wcs,world[2]);
356      *minvel = head.specToVel(world[2]);
357      pixcrd[2] = obj.getZcentre() + 10.;
358      head.pixToWCS(pixcrd,world);
359      //     *maxvel = setVel_kms(wcs,world[2]);
360      *maxvel = head.specToVel(world[2]);
361      if(*maxvel<*minvel) std::swap(*maxvel,*minvel);
362    }
363    delete [] pixcrd;
364    delete [] world;
365
366  }
367  //--------------------------------------------------------------------
368
369  void getSmallZRange(Detection &obj, double *minz, double *maxz)
370  {
371    ///  @details
372    ///  Routine to calculate the pixel range for the zoomed-in spectrum.
373    ///  This range should be the maximum of 20 pixels, or 3x the width
374    ///   of the detection.
375    ///  Need to :
376    ///      Calculate pixel width of a 3x-detection-width region.
377    ///       If smaller than 20, use central pixel +- 10 pixels
378    ///  Range returned via "minz" and "maxz" parameters.
379    ///  \param obj Detection under examination.
380    ///  \param minz Returned value of minimum z-pixel coordinate
381    ///  \param maxz Returned value of maximum z-pixel coordinate
382
383    *minz = 2.*obj.getZmin() - obj.getZmax();
384    *maxz = 2.*obj.getZmax() - obj.getZmin();
385   
386    if((*maxz - *minz + 1) < 20){
387      *minz = obj.getZcentre() - 10.;
388      *maxz = obj.getZcentre() + 10.;
389    }
390
391  }
392  //--------------------------------------------------------------------
393
394}
Note: See TracBrowser for help on using the repository browser.