#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Column; using namespace mycpgplot; using namespace Statistics; /****************************************************************/ /////////////////////////////////////////////////// //// Functions for DataArray class: /////////////////////////////////////////////////// DataArray::DataArray(short int nDim, long size){ if(size<0) duchampError("DataArray(nDim,size)", "Negative size -- could not define DataArray"); else if(nDim<0) duchampError("DataArray(nDim,size)", "Negative number of dimensions: could not define DataArray"); else { if(size>0) this->array = new float[size]; this->numPixels = size; if(nDim>0) this->axisDim = new long[nDim]; this->numDim = nDim; } } //-------------------------------------------------------------------- DataArray::DataArray(short int nDim, long *dimensions){ if(nDim<0) duchampError("DataArray(nDim,dimArray)", "Negative number of dimensions: could not define DataArray"); else { int size = dimensions[0]; for(int i=1;inumPixels = size; if(size>0) this->array = new float[size]; this->numDim=nDim; if(nDim>0) this->axisDim = new long[nDim]; for(int i=0;iaxisDim[i] = dimensions[i]; } } } //-------------------------------------------------------------------- DataArray::~DataArray() { delete [] this->array; delete [] this->axisDim; this->objectList.clear(); } //-------------------------------------------------------------------- void DataArray::getDimArray(long *output){ for(int i=0;inumDim;i++) output[i] = this->axisDim[i]; } //-------------------------------------------------------------------- void DataArray::getArray(float *output){ for(int i=0;inumPixels;i++) output[i] = this->array[i]; } //-------------------------------------------------------------------- void DataArray::saveArray(float *input, long size){ if(size != this->numPixels) duchampError("DataArray::saveArray", "Input array different size to existing array. Cannot save."); else { if(this->numPixels>0) delete [] this->array; this->numPixels = size; this->array = new float[size]; for(int i=0;iarray[i] = input[i]; } } //-------------------------------------------------------------------- void DataArray::getDim(long &x, long &y, long &z){ if(numDim>0) x=axisDim[0]; else x=0; if(numDim>1) y=axisDim[1]; else y=0; if(numDim>2) z=axisDim[2]; else z=0; } //-------------------------------------------------------------------- void DataArray::addObject(Detection object){ // adds a single detection to the object list // objectList is a vector, so just use push_back() this->objectList.push_back(object); } //-------------------------------------------------------------------- void DataArray::addObjectList(vector newlist) { for(int i=0;iobjectList.push_back(newlist[i]); } //-------------------------------------------------------------------- void DataArray::addObjectOffsets(){ for(int i=0;iobjectList.size();i++){ for(int p=0;pobjectList[i].getSize();p++){ this->objectList[i].setX(p,this->objectList[i].getX(p)+ this->par.getXOffset()); this->objectList[i].setY(p,this->objectList[i].getY(p)+ this->par.getYOffset()); this->objectList[i].setZ(p,this->objectList[i].getZ(p)+ this->par.getZOffset()); } } } //-------------------------------------------------------------------- std::ostream& operator<< ( std::ostream& theStream, DataArray &array) { for(int i=0;i0) theStream<<"x"; theStream<getSize();j++){ obj->setX(j,obj->getX(j)+obj->getXOffset()); obj->setY(j,obj->getY(j)+obj->getYOffset()); obj->setZ(j,obj->getZ(j)+obj->getZOffset()); } theStream<<*obj; delete obj; } theStream<<"--------------\n"; } /****************************************************************/ ///////////////////////////////////////////////////////////// //// Functions for Image class ///////////////////////////////////////////////////////////// Image::Image(long size){ // need error handling in case size<0 !!! if(size<0) duchampError("Image(size)","Negative size -- could not define Image"); else{ if(size>0) this->array = new float[size]; this->numPixels = size; this->axisDim = new long[2]; this->numDim = 2; } } //-------------------------------------------------------------------- Image::Image(long *dimensions){ int size = dimensions[0] * dimensions[1]; if(size<0) duchampError("Image(dimArray)","Negative size -- could not define Image"); else{ this->numPixels = size; if(size>0) this->array = new float[size]; this->numDim=2; this->axisDim = new long[2]; for(int i=0;i<2;i++) this->axisDim[i] = dimensions[i]; } } //-------------------------------------------------------------------- //-------------------------------------------------------------------- void Image::saveArray(float *input, long size){ if(size != this->numPixels) duchampError("Image::saveArray", "Input array different size to existing array. Cannot save."); else { if(this->numPixels>0) delete [] array; this->numPixels = size; if(this->numPixels>0) this->array = new float[size]; for(int i=0;iarray[i] = input[i]; } } //-------------------------------------------------------------------- void Image::extractSpectrum(float *Array, long *dim, long pixel) { /** * Image::extractSpectrum(float *, long *, int) * A function to extract a 1-D spectrum from a 3-D array. * The array is assumed to be 3-D with the third dimension the spectral one. * The dimensions of the array are in the dim[] array. * The spectrum extracted is the one lying in the spatial pixel referenced * by the third argument. */ float *spec = new float[dim[2]]; for(int z=0;zsaveArray(spec,dim[2]); delete [] spec; } //-------------------------------------------------------------------- void Image::extractSpectrum(Cube &cube, long pixel) { /** * Image::extractSpectrum(Cube &, int) * A function to extract a 1-D spectrum from a Cube class * The spectrum extracted is the one lying in the spatial pixel referenced * by the second argument. */ long zdim = cube.getDimZ(); long spatSize = cube.getDimX()*cube.getDimY(); float *spec = new float[zdim]; for(int z=0;zsaveArray(spec,zdim); delete [] spec; } //-------------------------------------------------------------------- void Image::extractImage(float *Array, long *dim, long channel) { /** * Image::extractImage(float *, long *, int) * A function to extract a 2-D image from a 3-D array. * The array is assumed to be 3-D with the third dimension the spectral one. * The dimensions of the array are in the dim[] array. * The image extracted is the one lying in the channel referenced * by the third argument. */ float *image = new float[dim[0]*dim[1]]; for(int npix=0; npixsaveArray(image,dim[0]*dim[1]); delete [] image; } //-------------------------------------------------------------------- void Image::extractImage(Cube &cube, long channel) { /** * Image::extractImage(Cube &, int) * A function to extract a 2-D image from Cube class. * The image extracted is the one lying in the channel referenced * by the second argument. */ long spatSize = cube.getDimX()*cube.getDimY(); float *image = new float[spatSize]; for(int npix=0; npixsaveArray(image,spatSize); delete [] image; } //-------------------------------------------------------------------- void Image::removeMW() { /** * Image::removeMW() * A function to remove the Milky Way range of channels from a 1-D spectrum. * The array in this Image is assumed to be 1-D, with only the first axisDim * equal to 1. * The values of the MW channels are set to 0, unless they are BLANK. */ if(this->par.getFlagMW() && (this->axisDim[1]==1) ){ for(int z=0;zaxisDim[0];z++){ if(!this->isBlank(z) && this->par.isInMW(z)) this->array[z]=0.; } } } /****************************************************************/ ///////////////////////////////////////////////////////////// //// Functions for Cube class ///////////////////////////////////////////////////////////// Cube::Cube(long size){ // need error handling in case size<0 !!! this->reconAllocated = false; this->baselineAllocated = false; if(size<0) duchampError("Cube(size)","Negative size -- could not define Cube"); else{ if(size>0){ this->array = new float[size]; this->recon = new float[size]; this->reconAllocated = true; } this->numPixels = size; this->axisDim = new long[2]; this->numDim = 3; this->reconExists = false; } } //-------------------------------------------------------------------- Cube::Cube(long *dimensions){ int size = dimensions[0] * dimensions[1] * dimensions[2]; int imsize = dimensions[0] * dimensions[1]; this->reconAllocated = false; this->baselineAllocated = false; if((size<0) || (imsize<0) ) duchampError("Cube(dimArray)","Negative size -- could not define Cube"); else{ this->numPixels = size; if(size>0){ this->array = new float[size]; this->detectMap = new short[imsize]; if(this->par.getFlagATrous()||this->par.getFlagSmooth()){ this->recon = new float[size]; this->reconAllocated = true; } if(this->par.getFlagBaseline()){ this->baseline = new float[size]; this->baselineAllocated = true; } } this->numDim = 3; this->axisDim = new long[3]; for(int i=0;i<3 ;i++) this->axisDim[i] = dimensions[i]; for(int i=0;idetectMap[i] = 0; this->reconExists = false; } } //-------------------------------------------------------------------- Cube::~Cube() { // delete [] array; // delete [] axisDim; // objectList.clear(); delete [] this->detectMap; if(this->reconAllocated) delete [] this->recon; if(this->baselineAllocated) delete [] this->baseline; } //-------------------------------------------------------------------- void Cube::initialiseCube(long *dimensions) { /** * Cube::initialiseCube(long *dim) * A function that defines the sizes of all the necessary * arrays in the Cube class. * It also defines the values of the axis dimensions. * This is done with the WCS in the FitsHeader class, so the * WCS needs to be good and have three axes. */ int lng,lat,spc,size,imsize; if(this->head.isWCS() && (this->head.getWCS()->naxis>=3)){ // if there is a WCS and there is at least 3 axes lng = this->head.getWCS()->lng; lat = this->head.getWCS()->lat; spc = this->head.getWCS()->spec; } else{ // just take dimensions[] at face value lng = 0; lat = 1; spc = 2; } size = dimensions[lng] * dimensions[lat] * dimensions[spc]; imsize = dimensions[lng] * dimensions[lat]; this->reconAllocated = false; this->baselineAllocated = false; if((size<0) || (imsize<0) ) duchampError("Cube::initialiseCube(dimArray)", "Negative size -- could not define Cube.\n"); else{ this->numPixels = size; if(size>0){ this->array = new float[size]; this->detectMap = new short[imsize]; if(this->par.getFlagATrous() || this->par.getFlagSmooth()){ this->recon = new float[size]; this->reconAllocated = true; } if(this->par.getFlagBaseline()){ this->baseline = new float[size]; this->baselineAllocated = true; } } this->numDim = 3; this->axisDim = new long[3]; this->axisDim[0] = dimensions[lng]; this->axisDim[1] = dimensions[lat]; this->axisDim[2] = dimensions[spc]; for(int i=0;idetectMap[i] = 0; this->reconExists = false; } } //-------------------------------------------------------------------- int Cube::getopts(int argc, char ** argv) { /** * Cube::getopt * A front-end to read in the command-line options, * and then read in the correct parameters to the cube->par */ int returnValue; if(argc==1){ std::cout << ERR_USAGE_MSG; returnValue = FAILURE; } else { string file; Param *par = new Param; char c; while( ( c = getopt(argc,argv,"p:f:hv") )!=-1){ switch(c) { case 'p': file = optarg; if(this->readParam(file)==FAILURE){ stringstream errmsg; errmsg << "Could not open parameter file " << file << ".\n"; duchampError("Duchamp",errmsg.str()); returnValue = FAILURE; } else returnValue = SUCCESS; break; case 'f': file = optarg; par->setImageFile(file); this->saveParam(*par); returnValue = SUCCESS; break; case 'v': std::cout << PROGNAME << " version " << VERSION << std::endl; returnValue = FAILURE; break; case 'h': default : std::cout << ERR_USAGE_MSG; returnValue = FAILURE; break; } } delete par; } return returnValue; } //-------------------------------------------------------------------- void Cube::readSavedArrays() { // If the reconstructed array is to be read in from disk if( this->par.getFlagReconExists() && this->par.getFlagATrous() ){ std::cout << "Reading reconstructed array: "<readReconCube() == FAILURE){ std::stringstream errmsg; errmsg <<"Could not read in existing reconstructed array.\n" <<"Will perform reconstruction using assigned parameters.\n"; duchampWarning("Duchamp", errmsg.str()); this->par.setFlagReconExists(false); } else std::cout << "Reconstructed array available.\n"; } if( this->par.getFlagSmoothExists() && this->par.getFlagSmooth() ){ std::cout << "Reading Hanning-smoothed array: "<readSmoothCube() == FAILURE){ std::stringstream errmsg; errmsg <<"Could not read in existing smoothed array.\n" <<"Will smooth the cube using assigned parameters.\n"; duchampWarning("Duchamp", errmsg.str()); this->par.setFlagSmoothExists(false); } else std::cout << "Smoothed array available.\n"; } } //-------------------------------------------------------------------- void Cube::saveArray(float *input, long size){ if(size != this->numPixels){ stringstream errmsg; errmsg << "Input array different size to existing array (" << size << " cf. " << this->numPixels << "). Cannot save.\n"; duchampError("Cube::saveArray",errmsg.str()); } else { if(this->numPixels>0) delete [] array; this->numPixels = size; this->array = new float[size]; for(int i=0;iarray[i] = input[i]; } } //-------------------------------------------------------------------- void Cube::saveRecon(float *input, long size){ if(size != this->numPixels){ stringstream errmsg; errmsg << "Input array different size to existing array (" << size << " cf. " << this->numPixels << "). Cannot save.\n"; duchampError("Cube::saveRecon",errmsg.str()); } else { if(this->numPixels>0){ if(this->reconAllocated) delete [] this->recon; this->numPixels = size; this->recon = new float[size]; this->reconAllocated = true; for(int i=0;irecon[i] = input[i]; this->reconExists = true; } } } //-------------------------------------------------------------------- void Cube::getRecon(float *output){ // Need check for change in number of pixels! for(int i=0;inumPixels;i++){ if(this->reconExists) output[i] = this->recon[i]; else output[i] = 0.; } } //-------------------------------------------------------------------- void Cube::removeMW() { if(this->par.getFlagMW()){ for(int pix=0;pixaxisDim[0]*this->axisDim[1];pix++){ for(int z=0;zaxisDim[2];z++){ int pos = z*this->axisDim[0]*this->axisDim[1] + pix; if(!this->isBlank(pos) && this->par.isInMW(z)) this->array[pos]=0.; } } } } //-------------------------------------------------------------------- void Cube::calcObjectWCSparams() { /** * Cube::calcObjectWCSparams() * A function that calculates the WCS parameters for each object in the * cube's list of detections. * Each object gets an ID number set (just the order in the list), and if * the WCS is good, the WCS paramters are calculated. */ for(int i=0; iobjectList.size();i++){ this->objectList[i].setID(i+1); this->objectList[i].calcWCSparams(this->head); this->objectList[i].setPeakSNR( (this->objectList[i].getPeakFlux() - this->Stats.getMiddle()) / this->Stats.getSpread() ); } } //-------------------------------------------------------------------- void Cube::sortDetections() { /** * Cube::sortDetections() * A front end to the sort-by functions. * If there is a good WCS, the detection list is sorted by velocity. * Otherwise, it is sorted by increasing z-pixel value. * The ID numbers are then re-calculated. */ if(this->head.isWCS()) SortByVel(this->objectList); else SortByZ(this->objectList); for(int i=0; iobjectList.size();i++) this->objectList[i].setID(i+1); } //-------------------------------------------------------------------- void Cube::updateDetectMap() { /** * Cube::updateDetectMap() * A function that, for each detected object in the cube's list, increments * the cube's detection map by the required amount at each pixel. */ for(int obj=0;objobjectList.size();obj++){ for(int pix=0;pixobjectList[obj].getSize();pix++) { int spatialPos = this->objectList[obj].getX(pix)+ this->objectList[obj].getY(pix)*this->axisDim[0]; this->detectMap[spatialPos]++; } } } //-------------------------------------------------------------------- void Cube::updateDetectMap(Detection obj) { /** * Cube::updateDetectMap(Detection) * A function that, for the given object, increments the cube's * detection map by the required amount at each pixel. */ for(int pix=0;pixaxisDim[0]; this->detectMap[spatialPos]++; } } //-------------------------------------------------------------------- void Cube::setCubeStatsOld() { /** * Cube::setCubeStatsOld() * Calculates the full statistics for the cube: * mean, rms, median, madfm * Only do this if the threshold has not been defined (ie. is still 0., * its default). * Also work out the threshold and store it in the par set. * * For stats calculations, ignore BLANKs and MW channels. */ if(!this->par.getFlagFDR() && this->par.getFlagUserThreshold() ){ // if the user has defined a threshold, set this in the StatsContainer this->Stats.setThreshold( this->par.getThreshold() ); } else{ // only work out the mean etc if we need to. // the only reason we don't is if the user has specified a threshold. std::cout << "Calculating the cube statistics... " << std::flush; // get number of good pixels; int goodSize = 0; for(int p=0;paxisDim[0]*this->axisDim[1];p++){ for(int z=0;zaxisDim[2];z++){ int vox = z * this->axisDim[0] * this->axisDim[1] + p; if(!this->isBlank(vox) && !this->par.isInMW(z)) goodSize++; } } float *tempArray = new float[goodSize]; goodSize=0; for(int p=0;paxisDim[0]*this->axisDim[1];p++){ for(int z=0;zaxisDim[2];z++){ int vox = z * this->axisDim[0] * this->axisDim[1] + p; if(!this->isBlank(vox) && !this->par.isInMW(z)) tempArray[goodSize++] = this->array[vox]; } } if(!this->reconExists){ // if there's no recon array, calculate everything from orig array this->Stats.calculate(tempArray,goodSize); } else{ // just get mean & median from orig array, and rms & madfm from recon StatsContainer origStats,reconStats; origStats.calculate(tempArray,goodSize); goodSize=0; for(int p=0;paxisDim[0]*this->axisDim[1];p++){ for(int z=0;zaxisDim[2];z++){ int vox = z * this->axisDim[0] * this->axisDim[1] + p; if(!this->isBlank(vox) && !this->par.isInMW(z)) tempArray[goodSize++] = this->array[vox] - this->recon[vox]; } } reconStats.calculate(tempArray,goodSize); // Get the "middle" estimators from the original array. // Get the "spread" estimators from the residual (orig-recon) array this->Stats.setMean(origStats.getMean()); this->Stats.setMedian(origStats.getMedian()); this->Stats.setStddev(reconStats.getStddev()); this->Stats.setMadfm(reconStats.getMadfm()); } delete [] tempArray; this->Stats.setUseFDR( this->par.getFlagFDR() ); // If the FDR method has been requested if(this->par.getFlagFDR()) this->setupFDR(); else{ // otherwise, calculate one based on the requested SNR cut level, and // then set the threshold parameter in the Par set. this->Stats.setThresholdSNR( this->par.getCut() ); this->par.setThreshold( this->Stats.getThreshold() ); } } std::cout << "Using "; if(this->par.getFlagFDR()) std::cout << "effective "; std::cout << "flux threshold of: "; float thresh = this->Stats.getThreshold(); if(this->par.getFlagNegative()) thresh *= -1.; std::cout << thresh << std::endl; } //-------------------------------------------------------------------- void Cube::setCubeStats() { /** * Cube::setCubeStats() * Calculates the full statistics for the cube: * mean, rms, median, madfm * Only do this if the threshold has not been defined (ie. is still 0., * its default). * Also work out the threshold and store it in the par set. * * Different from setCubeStatsOld as it doesn't use the getStats functions * but has own versions of them hardcoded to ignore BLANKs and * MW channels. */ if(!this->par.getFlagFDR() && this->par.getFlagUserThreshold() ){ // if the user has defined a threshold, set this in the StatsContainer this->Stats.setThreshold( this->par.getThreshold() ); } else{ // only work out the mean etc if we need to. // the only reason we don't is if the user has specified a threshold. std::cout << "Calculating the cube statistics... " << std::flush; long xysize = this->axisDim[0]*this->axisDim[1]; // get number of good pixels; int vox,goodSize = 0; for(int p=0;paxisDim[2];z++){ vox = z*xysize+p; if(!this->isBlank(vox) && !this->par.isInMW(z)) goodSize++; } } float *tempArray = new float[goodSize]; goodSize=0; for(int p=0;paxisDim[2];z++){ vox = z * xysize + p; if(!this->isBlank(vox) && !this->par.isInMW(z)){ tempArray[goodSize] = this->array[vox]; goodSize++; } } } float mean,median,stddev,madfm; mean = tempArray[0]; for(int i=1;iStats.setMean(mean); std::sort(tempArray,tempArray+goodSize); if((goodSize%2)==0) median = (tempArray[goodSize/2-1] + tempArray[goodSize/2])/2; else median = tempArray[goodSize/2]; this->Stats.setMedian(median); if(!this->reconExists){ // if there's no recon array, calculate everything from orig array stddev = (tempArray[0]-mean) * (tempArray[0]-mean); for(int i=1;iStats.setStddev(stddev); for(int i=0;imedian) tempArray[i] -= median; else tempArray[i] = median - tempArray[i]; } std::sort(tempArray,tempArray+goodSize); if((goodSize%2)==0) madfm = (tempArray[goodSize/2-1]+tempArray[goodSize/2])/2; else madfm = tempArray[goodSize/2]; this->Stats.setMadfm(madfm); } else{ // just get mean & median from orig array, and rms & madfm from residual // recompute array values to be residuals & then find stddev & madfm goodSize = 0; for(int p=0;paxisDim[2];z++){ vox = z * xysize + p; if(!this->isBlank(vox) && !this->par.isInMW(z)){ tempArray[goodSize] = this->array[vox] - this->recon[vox]; goodSize++; } } } mean = tempArray[0]; for(int i=1;iStats.setStddev(stddev); std::sort(tempArray,tempArray+goodSize); if((goodSize%2)==0) median = (tempArray[goodSize/2-1] + tempArray[goodSize/2])/2; else median = tempArray[goodSize/2]; for(int i=0;imedian) tempArray[i] = tempArray[i]-median; else tempArray[i] = median - tempArray[i]; } std::sort(tempArray,tempArray+goodSize); if((goodSize%2)==0) madfm = (tempArray[goodSize/2-1] + tempArray[goodSize/2])/2; else madfm = tempArray[goodSize/2]; this->Stats.setMadfm(madfm); } delete [] tempArray; this->Stats.setUseFDR( this->par.getFlagFDR() ); // If the FDR method has been requested if(this->par.getFlagFDR()) this->setupFDR(); else{ // otherwise, calculate threshold based on the requested SNR cut level, // and then set the threshold parameter in the Par set. this->Stats.setThresholdSNR( this->par.getCut() ); this->par.setThreshold( this->Stats.getThreshold() ); } } std::cout << "Using "; if(this->par.getFlagFDR()) std::cout << "effective "; std::cout << "flux threshold of: "; float thresh = this->Stats.getThreshold(); if(this->par.getFlagNegative()) thresh *= -1.; std::cout << thresh << std::endl; } //-------------------------------------------------------------------- int Cube::setupFDR() { /** * Cube::setupFDR() * Determines the critical Prob value for the False Discovery Rate * detection routine. All pixels with Prob less than this value will * be considered detections. * The Prob here is the probability, assuming a Normal distribution, of * obtaining a value as high or higher than the pixel value (ie. only the * positive tail of the PDF) */ // first calculate p-value for each pixel -- assume Gaussian for now. float *orderedP = new float[this->numPixels]; int count = 0; float zStat; for(int pix=0; pixnumPixels; pix++){ if( !(this->par.isBlank(this->array[pix])) ){ // only look at non-blank pixels zStat = (this->array[pix] - this->Stats.getMiddle()) / this->Stats.getSpread(); orderedP[count++] = 0.5 * erfc(zStat/M_SQRT2); // Need the factor of 0.5 here, as we are only considering the positive // tail of the distribution. Don't care about negative detections. } } // now order them std::sort(orderedP,orderedP+count); // now find the maximum P value. int max = 0; float cN = 0.; int psfCtr; int numVox = int(this->par.getBeamSize()) * 2; // why beamSize*2? we are doing this in 3D, so spectrally assume just the // neighbouring channels are correlated, but spatially all those within // the beam, so total number of voxels is 2*beamSize for(psfCtr=1;psfCtr<=numVox;(psfCtr)++) cN += 1./float(psfCtr); for(int loopCtr=0;loopCtrpar.getAlpha()/(cN * double(count))) ) { max = loopCtr; } } this->Stats.setPThreshold( orderedP[max] ); delete [] orderedP; // Find real value of the P threshold by finding the inverse of the // error function -- root finding with brute force technique // (relatively slow, but we only do it once). zStat = 0; float deltaZ = 0.1; float tolerance = 1.e-6; float zeroP = 0.5 * erfc(zStat/M_SQRT2) - this->Stats.getPThreshold(); do{ zStat+=deltaZ; if((zeroP * (erfc(zStat/M_SQRT2)-this->Stats.getPThreshold()))<0.){ zStat-=deltaZ; deltaZ/=2.; } }while(deltaZ>tolerance); this->Stats.setThreshold( zStat*this->Stats.getSpread() + this->Stats.getMiddle() ); } //-------------------------------------------------------------------- float Cube::enclosedFlux(Detection obj) { /** * float Cube::enclosedFlux(Detection obj) * A function to calculate the flux enclosed by the range * of pixels detected in the object obj (not necessarily all * pixels will have been detected). */ obj.calcParams(); int xsize = obj.getXmax()-obj.getXmin()+1; int ysize = obj.getYmax()-obj.getYmin()+1; int zsize = obj.getZmax()-obj.getZmin()+1; vector fluxArray(xsize*ysize*zsize,0.); for(int x=0;xgetPixValue(x+obj.getXmin(), y+obj.getYmin(), z+obj.getZmin()); if(this->par.getFlagNegative()) fluxArray[x+y*xsize+z*ysize*xsize] *= -1.; } } } float sum = 0.; for(int i=0;ipar.isBlank(fluxArray[i])) sum+=fluxArray[i]; return sum; } //-------------------------------------------------------------------- void Cube::setupColumns() { /** * Cube::setupColumns() * A front-end to the two setup routines in columns.cc. */ this->calcObjectWCSparams(); // need this as the colSet functions use vel, RA, Dec, etc... this->fullCols.clear(); this->fullCols = getFullColSet(this->objectList, this->head); this->logCols.clear(); this->logCols = getLogColSet(this->objectList, this->head); int vel,fpeak,fint,pos,xyz,temp,snr; vel = fullCols[VEL].getPrecision(); fpeak = fullCols[FPEAK].getPrecision(); snr = fullCols[SNRPEAK].getPrecision(); xyz = fullCols[X].getPrecision(); if(temp=fullCols[Y].getPrecision() > xyz) xyz = temp; if(temp=fullCols[Z].getPrecision() > xyz) xyz = temp; if(this->head.isWCS()) fint = fullCols[FINT].getPrecision(); else fint = fullCols[FTOT].getPrecision(); pos = fullCols[WRA].getPrecision(); if(temp=fullCols[WDEC].getPrecision() > pos) pos = temp; for(int obj=0;objobjectList.size();obj++){ this->objectList[obj].setVelPrec(vel); this->objectList[obj].setFpeakPrec(fpeak); this->objectList[obj].setXYZPrec(xyz); this->objectList[obj].setPosPrec(pos); this->objectList[obj].setFintPrec(fint); this->objectList[obj].setSNRPrec(snr); } } //-------------------------------------------------------------------- bool Cube::objAtSpatialEdge(Detection obj) { /** * bool Cube::objAtSpatialEdge() * A function to test whether the object obj * lies at the edge of the cube's spatial field -- * either at the boundary, or next to BLANKs */ bool atEdge = false; int pix = 0; while(!atEdge && pix=this->axisDim[0])) atEdge = true; else if(this->isBlank(vox.getX()+dx,vox.getY(),vox.getZ())) atEdge = true; } for(int dy=-1;dy<=1;dy+=2){ if(((vox.getY()+dy)<0) || ((vox.getY()+dy)>=this->axisDim[1])) atEdge = true; else if(this->isBlank(vox.getX(),vox.getY()+dy,vox.getZ())) atEdge = true; } pix++; } return atEdge; } //-------------------------------------------------------------------- bool Cube::objAtSpectralEdge(Detection obj) { /** * bool Cube::objAtSpectralEdge() * A function to test whether the object obj * lies at the edge of the cube's spectral extent -- * either at the boundary, or next to BLANKs */ bool atEdge = false; int pix = 0; while(!atEdge && pix=this->axisDim[2])) atEdge = true; else if(this->isBlank(vox.getX(),vox.getY(),vox.getZ()+dz)) atEdge = true; } pix++; } return atEdge; } //-------------------------------------------------------------------- void Cube::setObjectFlags() { /** * void Cube::setObjectFlags() * A function to set any warning flags for all the detected objects * associated with the cube. * Flags to be looked for: * * Negative enclosed flux (N) * * Object at edge of field (E) */ for(int i=0;iobjectList.size();i++){ if( this->enclosedFlux(this->objectList[i]) < 0. ) this->objectList[i].addToFlagText("N"); if( this->objAtSpatialEdge(this->objectList[i]) ) this->objectList[i].addToFlagText("E"); if( this->objAtSpectralEdge(this->objectList[i]) ) this->objectList[i].addToFlagText("S"); } } //-------------------------------------------------------------------- void Cube::plotBlankEdges() { if(this->par.drawBlankEdge()){ int colour; cpgqci(&colour); cpgsci(MAGENTA); drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par); cpgsci(colour); } }