00001 //# MomentCalcBase.h: 00002 //# Copyright (C) 1997,1999,2000,2001,2002 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: MomentCalculator.h 20299 2008-04-03 05:56:44Z gervandiepen $ 00027 00028 #ifndef IMAGEANALYSIS_MOMENTCALCBASE_H 00029 #define IMAGEANALYSIS_MOMENTCALCBASE_H 00030 00031 namespace casa { 00032 00033 //# Forward Declarations 00034 template <class T> class MomentsBase; 00035 // <summary> 00036 // Abstract base class for moment calculator classes 00037 // </summary> 00038 // <use visibility=export> 00039 // <reviewed reviewer="" date="yyyy/mm/dd" tests="" demos=""> 00040 // </reviewed> 00041 // 00042 // <prerequisite> 00043 // <li> <linkto class="MomentsBase">MomentsBase</linkto> 00044 // <li> <linkto class="ImageMoments">ImageMoments</linkto> 00045 // <li> <linkto class="LatticeApply">LatticeApply</linkto> 00046 // <li> <linkto class="LineCollapser">LineCollapser</linkto> 00047 // </prerequisite> 00048 // 00049 // <synopsis> 00050 // This class, its concrete derived classes, and the classes LineCollapser, 00051 // ImageMoments, MSMoments, and LatticeApply are connected as follows. LatticeApply offers 00052 // functions so that the application programmer does not need to worry about how 00053 // to optimally iterate through a Lattice; it deals with tiling and to a 00054 // lesser extent memory. LatticeApply functions are used by offering a class 00055 // object to them that has a member function with a name and signature 00056 // specified by an abstract base class that LatticeApply uses and the 00057 // offered class inherits from. Specifically, in this case, MomentCalcBase 00058 // inherits from LineCollapser and LatticeApply uses objects and methods of this 00059 // class (but does not inherit from it). This defines the functions 00060 // <src>collapse</src> and <src>multiProcess</src> which operate on a vector 00061 // extracted from a Lattice. The former returns one number, the latter a vector 00062 // of numbers from that profile. MomentCalcBase is a base class for 00063 // for moment calculation and the <src>multiProcess</src> 00064 // functions are used to compute moments (e.g., mean, sum, sum squared, 00065 // intensity weighted velocity etc). 00066 // 00067 // It is actually the concrete classes derived from MomentCalcBase (call them, 00068 // as a group, the MomentCalculator classes) that implement the <src>multiProcess</src> 00069 // functions. These derived classes allow different 00070 // algorithms to be written with which moments of the vector can be computed. 00071 // 00072 // Now, so far, we have a LatticeApply function which iterates through Lattices, 00073 // extracts vectors, and offers them up to functions implemented in the derived 00074 // MomentCalculator classes to compute the moments. As well as that, we need some 00075 // class to actually construct the MomentCalculator classes and to feed them to 00076 // LatticeApply. This is the role of the ImageMoments or MSMoments classes. 00077 // They are a high level 00078 // class which takes control information from users specifying which moments they 00079 // would like to calculate and how. They also provide the ancilliary masking lattice to 00080 // the MomentCalculator constructors. The actual computational work is done by the 00081 // MomentCalculator classes. So MomentsBase, MomentCalcBase and their derived 00082 // MomentCalculator classes are really one unit; none of them are useful without 00083 // the others. The separation of functionality is caused by having the 00084 // LatticeApply class that knows all about optimally iterating through Lattices. 00085 // 00086 // The coupling between these classes is done partly by the "friendship". MomentsBase and 00087 // its inheritances 00088 // grant friendship to MomentCalcBase so that the latter has access to the private data and 00089 // private functions of the formers. MomentCalcBase then operates as an interface between 00090 // its derived MomentCalculator classes and ImageMoments or MSMoments. It retrieves private data 00091 // from these classes, and also activates private functions in these classes, on behalf 00092 // of the MomentCalculator classes. The rest of the coupling is done via the constructors 00093 // of the derived MomentCalculator classes. 00094 // 00095 // Finally, MomentCalcBase also has a number of protected functions that are common to its 00096 // derived classes (e.g. fitting, accumulating sums etc). It also has protected 00097 // data that is common to all the MomentCalculator classes. This protected data is accessed 00098 // directly by name rather than with interface functions as there is too much of it. Of 00099 // course, since MomentCalcBase is an abstract base class, it is up to the MomentCalculator 00100 // classes to give the MomentCalcBase protected data objects values. 00101 // 00102 // For discussion about different moments and algorithms to compute them see the 00103 // discussion in <linkto class="MomentsBase">MomentsBase</linkto>, 00104 // <linkto class="ImageMoments">ImageMoments</linkto>, 00105 // <linkto class="MSMoments">MSMoments</linkto> and also in 00106 // the derived classes documentation. 00107 // </synopsis> 00108 // 00109 // <example> 00110 // Since MomentCalcBase is an abstract class, we defer code examples to 00111 // the derived classes. 00112 // </example> 00113 // 00114 // <motivation> 00115 // We were desirous of writing functions to optimally iterate through Lattices 00116 // so that the application programmer did not have to know anything about tiling 00117 // or memory if possible. These are the LatticeApply functions. To incorporate 00118 // MomentsBase and its inheritances into this scheme required some of it to be shifted into 00119 // MomentCalcBase and its derived classes. 00120 // </motivation> 00121 // 00122 // <note role=tip> 00123 // Note that there are is assignment operator or copy constructor. 00124 // Do not use the ones the system would generate either. 00125 // </note> 00126 // 00127 // <todo asof="yyyy/mm/dd"> 00128 // <li> Derive more classes ! 00129 // </todo> 00130 00131 00132 template <class T> class MomentCalcBase : public LineCollapser<T,T> { 00133 public: 00134 00135 using AccumType = typename NumericTraits<T>::PrecisionType; 00136 using DataIterator = typename Vector<T>::const_iterator; 00137 using MaskIterator = Vector<Bool>::const_iterator; 00138 00139 virtual ~MomentCalcBase(); 00140 00141 // Returns the number of failed fits if doing fitting 00142 virtual inline uInt nFailedFits() const { return nFailed_p; } 00143 00144 protected: 00145 00146 // A number of private data members are kept here in the base class 00147 // as they are common to the derived classes. Since this class 00148 // is abstract, they have to be filled by the derived classes. 00149 00150 // CoordinateSystem 00151 CoordinateSystem cSys_p; 00152 00153 // This vector is a container for all the possible moments that 00154 // can be calculated. They are in the order given by the MomentsBase 00155 // enum MomentTypes 00156 Vector<T> calcMoments_p; 00157 Vector<Bool> calcMomentsMask_p; 00158 00159 // This vector tells us which elements of the calcMoments_p vector 00160 // we wish to select 00161 Vector<Int> selectMoments_p; 00162 00163 // Although the general philosophy of these classes is to compute 00164 // all the posisble moments and then select the ones we want, 00165 // some of them are too expensive to calculate unless they are 00166 // really wanted. These are the median moments and those that 00167 // require a second pass. These control Bools tell us whether 00168 // we really want to compute the expensive ones. 00169 Bool doMedianI_p, doMedianV_p, doAbsDev_p; 00170 00171 // These vectors are used to transform coordinates between pixel and world 00172 Vector<Double> pixelIn_p, worldOut_p; 00173 00174 // All computations involving Coordinate conversions are relatively expensive 00175 // These Bools signifies whether we need coordinate calculations or not for 00176 // the full profile, and for some occaisional calculations 00177 Bool doCoordProfile_p, doCoordRandom_p; 00178 00179 // This vector houses the world coordinate values for the profile if it 00180 // was from a separable axis. This means this vector can be pre computed 00181 // just once, instead of working out the coordinates for each profile 00182 // (expensive). It should only be filled if doCoordCalc_p is True 00183 Vector<Double> sepWorldCoord_p; 00184 00185 // This vector is used to hold the abscissa values 00186 Vector<T> abcissa_p; 00187 00188 // This string tells us the name of the moment axis (VELO or FREQ etc) 00189 String momAxisType_p; 00190 00191 // This is the number of Gaussian fits that failed. 00192 uInt nFailed_p; 00193 00194 // This scale factor is the increment along the moment axis 00195 // applied so that units for the Integrated moment are like 00196 // Jy/beam.km/s (or whatever is needed for the moment axis units) 00197 // For non-linear velocities (e.g. optical) this is approximate 00198 // only and is computed at the reference pixel 00199 Double integratedScaleFactor_p; 00200 00201 // Accumulate statistical sums from a vector 00202 inline void accumSums( 00203 typename NumericTraits<T>::PrecisionType& s0, 00204 typename NumericTraits<T>::PrecisionType& s0Sq, 00205 typename NumericTraits<T>::PrecisionType& s1, 00206 typename NumericTraits<T>::PrecisionType& s2, 00207 Int& iMin, Int& iMax, T& dMin, T& dMax, 00208 Int i, T datum, Double coord 00209 ) const { 00210 // Accumulate statistical sums from this datum 00211 // 00212 // Input: 00213 // i Index 00214 // datum Pixel value 00215 // coord Coordinate value on moment axis 00216 // Input/output: 00217 // iMin,max index of dMin and dMax 00218 // dMin,dMax minimum and maximum value 00219 // Output: 00220 // s0 sum (I) 00221 // s0Sq sum (I*I) 00222 // s1 sum (I*v) 00223 // s2 sum (I*v*v) 00224 typename NumericTraits<T>::PrecisionType dDatum = datum; 00225 s0 += dDatum; 00226 s0Sq += dDatum*dDatum; 00227 s1 += dDatum*coord; 00228 s2 += dDatum*coord*coord; 00229 if (datum < dMin) { 00230 iMin = i; 00231 dMin = datum; 00232 } 00233 if (datum > dMax) { 00234 iMax = i; 00235 dMax = datum; 00236 } 00237 } 00238 00239 // Determine if the spectrum is pure noise 00240 uInt allNoise(T& dMean, 00241 const Vector<T>& data, 00242 const Vector<Bool>& mask, 00243 T peakSNR, 00244 T stdDeviation 00245 ) const; 00246 00247 // Check validity of constructor inputs 00248 void constructorCheck( 00249 Vector<T>& calcMoments, 00250 Vector<Bool>& calcMomentsMask, 00251 const Vector<Int>& selectMoments, 00252 uInt nLatticeOut 00253 ) const; 00254 00255 // Find out from the selectMoments array whether we want 00256 // to compute the more expensive moments 00257 void costlyMoments( 00258 MomentsBase<T>& iMom, Bool& doMedianI, 00259 Bool& doMedianV, Bool& doAbsDev 00260 ) const; 00261 00262 // Return the Bool saying whether we need to compute coordinates 00263 // or not for the requested moments 00264 void doCoordCalc( 00265 Bool& doCoordProfile, 00266 Bool& doCoordRandom, 00267 const MomentsBase<T>& iMom 00268 ) const; 00269 00270 // Return the Bool from the ImageMoments or MSMoments object saying whether we 00271 // are going to fit Gaussians to the profiles or not. 00272 Bool doFit(const MomentsBase<T>& iMom) const; 00273 00274 // Find the next masked or unmasked point in a vector 00275 Bool findNextDatum( 00276 uInt& iFound, const uInt& n, 00277 const Vector<Bool>& mask, const uInt& iStart, 00278 const Bool& findGood 00279 ) const; 00280 00281 // Fit a Gaussian to x and y arrays given guesses for the gaussian parameters 00282 Bool fitGaussian( 00283 uInt& nFailed, T& peak, T& pos, 00284 T& width, T& level, const Vector<T>& x, 00285 const Vector<T>& y, const Vector<Bool>& mask, 00286 T peakGuess, T posGuess, T widthGuess, 00287 T levelGuess 00288 ) const; 00289 00290 // Automatically fit a Gaussian to a spectrum, including finding the 00291 // starting guesses. 00292 Bool getAutoGaussianFit( 00293 uInt& nFailed, Vector<T>& gaussPars, 00294 const Vector<T>& x, const Vector<T>& y, 00295 const Vector<Bool>& mask, T peakSNR, 00296 T stdDeviation 00297 ) const; 00298 00299 // Automatically work out a guess for the Gaussian parameters 00300 // Returns False if all pixels masked. 00301 Bool getAutoGaussianGuess( 00302 T& peakGuess, T& posGuess, 00303 T& widthGuess, T& levelGuess, 00304 const Vector<T>& x, const Vector<T>& y, 00305 const Vector<Bool>& mask 00306 ) const; 00307 00308 // Compute the world coordinate for the given moment axis pixel 00309 inline Double getMomentCoord( 00310 const MomentsBase<T>& iMom, Vector<Double>& pixelIn, 00311 Vector<Double>& worldOut, Double momentPixel, 00312 Bool asVelocity=False 00313 ) const { 00314 // Find the value of the world coordinate on the moment axis 00315 // for the given moment axis pixel value. 00316 // 00317 // Input 00318 // momentPixel is the index in the profile extracted from the data 00319 // Input/output 00320 // pixelIn Pixels to convert. Must all be filled in except for 00321 // pixelIn(momentPixel). 00322 // worldOut Vector to hold result 00323 // 00324 // Should really return a Fallible as I don't check and see 00325 // if the coordinate transformation fails or not 00326 // 00327 // Should really check the result is True, but for speed ... 00328 pixelIn[iMom.momentAxis_p] = momentPixel; 00329 cSys_p.toWorld(worldOut, pixelIn); 00330 if (asVelocity) { 00331 Double velocity; 00332 cSys_p.spectralCoordinate().frequencyToVelocity( 00333 velocity, worldOut(iMom.worldMomentAxis_p) 00334 ); 00335 return velocity; 00336 } 00337 return worldOut(iMom.worldMomentAxis_p); 00338 } 00339 00340 // Examine a mask and determine how many segments of unmasked points 00341 // it consists of. 00342 void lineSegments ( 00343 uInt& nSeg, Vector<uInt>& start, 00344 Vector<uInt>& nPts, const Vector<Bool>& mask 00345 ) const; 00346 00347 // Return the moment axis from the ImageMoments object 00348 Int& momentAxis(MomentsBase<T>& iMom) const; 00349 00350 // Return the name of the moment/profile axis 00351 String momentAxisName( 00352 const CoordinateSystem&, 00353 const MomentsBase<T>& iMom 00354 ) const; 00355 00356 // Return the peak SNR for determination of all noise spectra from 00357 // the ImageMoments or MSMoments object 00358 T& peakSNR(MomentsBase<T>& iMom) const; 00359 00360 // Return the selected pixel intensity range from the ImageMoments or MSMoments 00361 // object and the Bools describing whether it is inclusion or exclusion 00362 void selectRange( 00363 Vector<T>& pixelRange, 00364 Bool& doInclude, 00365 Bool& doExlude, 00366 MomentsBase<T>& iMom 00367 ) const; 00368 00369 // The MomentCalculators compute a vector of all possible moments. 00370 // This function returns a vector which selects the desired moments from that 00371 // "all moment" vector. 00372 Vector<Int> selectMoments(MomentsBase<T>& iMom) const; 00373 00374 // Fill the ouput moments array 00375 void setCalcMoments( 00376 const MomentsBase<T>& iMom, Vector<T>& calcMoments, 00377 Vector<Bool>& calcMomentsMask, Vector<Double>& pixelIn, 00378 Vector<Double>& worldOut, Bool doCoord, 00379 Double integratedScaleFactor, T dMedian, 00380 T vMedian, Int nPts, 00381 typename NumericTraits<T>::PrecisionType s0, 00382 typename NumericTraits<T>::PrecisionType s1, 00383 typename NumericTraits<T>::PrecisionType s2, 00384 typename NumericTraits<T>::PrecisionType s0Sq, 00385 typename NumericTraits<T>::PrecisionType sumAbsDev, 00386 T dMin, T dMax, Int iMin, Int iMax 00387 ) const; 00388 00389 // Fill a string with the position of the cursor 00390 void setPosLabel(String& title, const IPosition& pos) const; 00391 00392 // Install CoordinateSystem and SpectralCoordinate 00393 // in protected data members 00394 void setCoordinateSystem( 00395 CoordinateSystem& cSys, MomentsBase<T>& iMom 00396 ); 00397 00398 // Set up separable moment axis coordinate vector and 00399 // conversion vectors if not separable 00400 void setUpCoords( 00401 const MomentsBase<T>& iMom, Vector<Double>& pixelIn, 00402 Vector<Double>& worldOut, Vector<Double>& sepWorldCoord, 00403 LogIO& os, Double& integratedScaleFactor, 00404 const CoordinateSystem& cSys, Bool doCoordProfile, 00405 Bool doCoordRandom 00406 ) const; 00407 00408 // Return standard deviation of image from ImageMoments or MSMoments object 00409 T& stdDeviation(MomentsBase<T>& iMom) const; 00410 00411 protected: 00412 // Check if #pixels is indeed 1. 00413 virtual void init (uInt nOutPixelsPerCollapse); 00414 }; 00415 00416 } 00417 00418 #ifndef CASACORE_NO_AUTO_TEMPLATES 00419 #include <imageanalysis/ImageAnalysis/MomentCalcBase.tcc> 00420 #endif 00421 #endif