// ----------------------------------------------------------------------- // outputSpectra.cc: Print the spectra of the detected objects. // ----------------------------------------------------------------------- // Copyright (C) 2006, Matthew Whiting, ATNF // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // Duchamp is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with Duchamp; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA // // Correspondence concerning Duchamp may be directed to: // Internet email: Matthew.Whiting [at] atnf.csiro.au // Postal address: Dr. Matthew Whiting // Australia Telescope National Facility, CSIRO // PO Box 76 // Epping NSW 1710 // AUSTRALIA // ----------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mycpgplot; using namespace PixelInfo; namespace duchamp { void getSmallVelRange(Detection &obj, FitsHeader head, float *minvel, float *maxvel); void getSmallZRange(Detection &obj, float *minz, float *maxz); void Cube::outputSpectra() { /** * The way to display individual detected objects. The standard way * is plot the full spectrum, plus a zoomed-in spectrum showing just * the object, plus the 0th-moment map. If there is no spectral * axis, just the 0th moment map is plotted (using * Cube::plotSource() rather than Cube::plotSpectrum()). * * It makes use of the SpectralPlot or CutoutPlot classes from * plots.h, which size everything correctly. * * The main choice for SpectralPlot() is whether to use the peak * pixel, in which case the spectrum is just that of the peak pixel, * or the sum, where the spectrum is summed over all spatial pixels * that are in the object. If a reconstruction has been done, that * spectrum is plotted in red. The limits of the detection are * marked in blue. A 0th moment map of the detection is also * plotted, with a scale bar indicating the spatial scale. */ if(this->fullCols.size()==0) this->setupColumns(); // in case cols haven't been set -- need the precisions for printing values. std::string spectrafile = this->par.getSpectraFile() + "/vcps"; if(this->getDimZ()<=1){ Plot::CutoutPlot newplot; if(newplot.setUpPlot(spectrafile.c_str())>0) { for(int nobj=0;nobjobjectList->size();nobj++){ // for each object in the cube: this->plotSource(this->objectList->at(nobj),newplot); }// end of loop over objects. cpgclos(); } } else{ Plot::SpectralPlot newplot; if(newplot.setUpPlot(spectrafile.c_str())>0) { for(int nobj=0;nobjobjectList->size();nobj++){ // for each object in the cube: this->plotSpectrum(nobj,newplot); }// end of loop over objects. cpgclos(); } if(this->par.getFlagTextSpectra()){ if(this->par.isVerbose()) std::cout << "Saving spectra in text file ... "; this->writeSpectralData(); if(this->par.isVerbose()) std::cout << "Done. "; } } } //-------------------------------------------------------------------- void Cube::writeSpectralData() { /** * A function to write, in ascii form, the spectra of each * detected object to a file. The file consists of a column for * the spectral coordinates, and one column for each object * showing the flux at that spectral position. The units are the * same as those shown in the graphical output. The filename is * given by the Param::spectraTextFile parameter in the Cube::par * parameter set. */ const int zdim = this->axisDim[2]; const int numObj = this->objectList->size(); float *specxOut = new float[zdim]; float *spectra = new float[numObj*zdim]; for(int obj=0; objpar.getSpectraTextFile().c_str()); fspec.setf(std::ios::fixed); for(int z=0;zaxisDim[0]; long ydim = this->axisDim[1]; long zdim = this->axisDim[2]; for(int i=0;ihead.isWCS()){ double xval = double(this->objectList->at(objNum).getXcentre()); double yval = double(this->objectList->at(objNum).getYcentre()); for(double zval=0;zvalhead.pixToVel(xval,yval,zval); } else for(double zval=0;zvalheader().needBeamSize()) beamCorrection = this->par.getBeamSize(); else beamCorrection = 1.; if(this->par.getSpectralMethod()=="sum"){ bool *done = new bool[xdim*ydim]; for(int i=0;i voxlist = this->objectList->at(objNum).pixels().getPixelSet(); for(int pix=0;pixisBlank(pos+z*xdim*ydim))){ specy[z] += this->array[pos + z*xdim*ydim] / beamCorrection; if(this->reconExists) specRecon[z] += this->recon[pos + z*xdim*ydim] / beamCorrection; if(this->par.getFlagBaseline()) specBase[z] += this->baseline[pos + z*xdim*ydim] / beamCorrection; } } } } delete [] done; } else {// if(par.getSpectralMethod()=="peak"){ int pos = this->objectList->at(objNum).getXPeak() + xdim*this->objectList->at(objNum).getYPeak(); for(int z=0;zarray[pos + z*xdim*ydim]; if(this->reconExists) specRecon[z] = this->recon[pos + z*xdim*ydim]; if(this->par.getFlagBaseline()) specBase[z] = this->baseline[pos + z*xdim*ydim]; } } } //-------------------------------------------------------------------- void Cube::plotSpectrum(int objNum, Plot::SpectralPlot &plot) { /** * The way to print out the spectrum of a Detection. * Makes use of the SpectralPlot class in plots.hh, which sizes * everything correctly. * * The main choice for the user is whether to use the peak pixel, in * which case the spectrum is just that of the peak pixel, or the * sum, where the spectrum is summed over all spatial pixels that * are in the object. * * If a reconstruction has been done, that spectrum is plotted in * red, and if a baseline has been calculated that is also shown, in * yellow. The spectral limits of the detection are marked in blue. * A 0th moment map of the detection is also plotted, with a scale * bar indicating the spatial size. * * \param objNum The number of the Detection to be plotted. * \param plot The SpectralPlot object defining the PGPLOT device * to plot the spectrum on. */ long zdim = this->axisDim[2]; this->objectList->at(objNum).calcFluxes(this->array, this->axisDim); double minMWvel,maxMWvel,xval,yval,zval; xval = double(this->objectList->at(objNum).getXcentre()); yval = double(this->objectList->at(objNum).getYcentre()); if(this->par.getFlagMW()){ zval = double(this->par.getMinMW()); minMWvel = this->head.pixToVel(xval,yval,zval); zval = double(this->par.getMaxMW()); maxMWvel = this->head.pixToVel(xval,yval,zval); } float *specx = new float[zdim]; float *specy = new float[zdim]; float *specy2 = new float[zdim]; float *base = new float[zdim]; this->getSpectralArrays(objNum,specx,specy,specy2,base); std::string fluxLabel = "Flux"; if(this->par.getSpectralMethod()=="sum"){ fluxLabel = "Integrated " + fluxLabel; if(this->head.isWCS()) fluxLabel += " ["+this->head.getIntFluxUnits()+"]"; } else {// if(par.getSpectralMethod()=="peak"){ fluxLabel = "Peak " + fluxLabel; if(this->head.isWCS()) fluxLabel += " ["+this->head.getFluxUnits()+"]"; } float vmax,vmin,width; vmax = vmin = specx[0]; for(int i=1;ivmax) vmax=specx[i]; if(specx[i]par.getMinMW()>0) max = min = specy[0]; else max = min = specx[this->par.getMaxMW()+1]; for(int i=0;ipar.isInMW(i)){ if(specy[i]>max) max=specy[i]; if(specy[i]head.isWCS()){ label = this->head.getSpectralDescription() + " [" + this->head.getSpectralUnits() + "]"; plot.gotoHeader(label); } else plot.gotoHeader("Spectral pixel value"); if(this->head.isWCS()){ label = this->objectList->at(objNum).outputLabelWCS(); plot.firstHeaderLine(label); label = this->objectList->at(objNum).outputLabelFluxes(); plot.secondHeaderLine(label); } label = this->objectList->at(objNum).outputLabelWidths(); plot.thirdHeaderLine(label); label = this->objectList->at(objNum).outputLabelPix(); plot.fourthHeaderLine(label); plot.gotoMainSpectrum(vmin,vmax,min,max,fluxLabel); cpgline(zdim,specx,specy); if(this->par.getFlagBaseline()){ cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR); cpgline(zdim,specx,base); cpgsci(FOREGND); } if(this->reconExists){ cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR); cpgline(zdim,specx,specy2); cpgsci(FOREGND); } if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel); if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(),this->objectList->at(objNum).getVelMax()); else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax()); /**************************/ // ZOOM IN SPECTRALLY ON THE DETECTION. float minvel,maxvel; if(this->head.isWCS()) getSmallVelRange(this->objectList->at(objNum),this->head,&minvel,&maxvel); else getSmallZRange(this->objectList->at(objNum),&minvel,&maxvel); // Find new max & min flux values std::swap(max,min); int ct = 0; for(int i=0;ipar.isInMW(i))&&(specx[i]>=minvel)&&(specx[i]<=maxvel)){ ct++; if(specy[i]>max) max=specy[i]; if(specy[i]par.getFlagBaseline()){ cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR); cpgline(zdim,specx,base); cpgsci(FOREGND); } if(this->reconExists){ cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR); cpgline(zdim,specx,specy2); cpgsci(FOREGND); } if(this->par.getFlagMW()) plot.drawMWRange(minMWvel,maxMWvel); if(this->head.isWCS()) plot.drawVelRange(this->objectList->at(objNum).getVelMin(), this->objectList->at(objNum).getVelMax()); else plot.drawVelRange(this->objectList->at(objNum).getZmin(),this->objectList->at(objNum).getZmax()); /**************************/ // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS plot.gotoMap(); this->drawMomentCutout(this->objectList->at(objNum)); delete [] specx; delete [] specy; delete [] specy2; delete [] base; } //-------------------------------------------------------------------- void getSmallVelRange(Detection &obj, FitsHeader head, float *minvel, float *maxvel) { /** * Routine to calculate the velocity range for the zoomed-in region. * This range should be the maximum of 20 pixels, or 3x the wdith of * the detection. * Need to : * Calculate pixel width of a 3x-detection-width region. * If smaller than 20, calculate velocities of central vel +- 10 pixels * If not, use the 3x-detection-width * Range returned via "minvel" and "maxvel" parameters. * \param obj Detection under examination. * \param head FitsHeader, containing the WCS information. * \param minvel Returned value of minimum velocity * \param maxvel Returned value of maximum velocity */ double *pixcrd = new double[3]; double *world = new double[3]; float minpix,maxpix; // define new velocity extrema // -- make it 3x wider than the width of the detection. *minvel = 0.5*(obj.getVelMin()+obj.getVelMax()) - 1.5*obj.getVelWidth(); *maxvel = 0.5*(obj.getVelMin()+obj.getVelMax()) + 1.5*obj.getVelWidth(); // Find velocity range in number of pixels: world[0] = obj.getRA(); world[1] = obj.getDec(); world[2] = head.velToSpec(*minvel); head.wcsToPix(world,pixcrd); minpix = pixcrd[2]; world[2] = head.velToSpec(*maxvel); head.wcsToPix(world,pixcrd); maxpix = pixcrd[2]; if(maxpixarray, this->axisDim); std::string label; plot.gotoHeader(); if(this->head.isWCS()){ label = obj.outputLabelWCS(); plot.firstHeaderLine(label); label = obj.outputLabelFluxes(); plot.secondHeaderLine(label); } label = obj.outputLabelWidths(); plot.thirdHeaderLine(label); label = obj.outputLabelPix(); plot.fourthHeaderLine(label); // DRAW THE MOMENT MAP OF THE DETECTION -- SUMMED OVER ALL CHANNELS plot.gotoMap(); this->drawMomentCutout(obj); } }