casa
$Rev:20696$
|
00001 //# Convolver.h: this defines Convolver a class for doing convolution 00002 //# Copyright (C) 1996,1999,2001,2002,2003 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 //# 00027 //# $Id: Convolver.h 21024 2011-03-01 11:46:18Z gervandiepen $ 00028 00029 #ifndef SCIMATH_CONVOLVER_H 00030 #define SCIMATH_CONVOLVER_H 00031 00032 #include <casa/aips.h> 00033 #include <casa/Arrays/Array.h> 00034 #include <casa/BasicSL/Complex.h> 00035 #include <scimath/Mathematics/FFTServer.h> 00036 #include <casa/Arrays/IPosition.h> 00037 #include <scimath/Mathematics/NumericTraits.h> 00038 00039 namespace casa { //# NAMESPACE CASA - BEGIN 00040 00041 // Forward Declarations 00042 template <class FType> class Convolver; 00043 00044 // Typedefs 00045 typedef Convolver<Float> FloatConvolver; 00046 typedef Convolver<Double> DoubleConvolver; 00047 00048 // <summary> 00049 // A class for doing multi-dimensional convolution 00050 // </summary> 00051 00052 // <use visibility=export> 00053 00054 // <reviewed reviewer="Brian Glendenning " date="1996/05/27" 00055 // tests="tConvolution"> 00056 // </reviewed> 00057 00058 // <prerequisite> 00059 // <li> The mathematical concept of convolution 00060 // </prerequisite> 00061 // 00062 // <etymology> 00063 // The convolver class performs convolution! 00064 // </etymology> 00065 // 00066 // <synopsis> 00067 // This class will perform linear or circular convolution on arrays. 00068 // 00069 // The dimension of the convolution done is determined by the dimension of 00070 // the point spread function (psf), so for example, if the psf is a Vector, 00071 // one dimensional convolution will be done. The dimension of the model 00072 // that is to be convolved must be at least the same as the point 00073 // spread function, but it can be larger. If it is then the convolution will 00074 // be repeated for each row or plane of the model. 00075 // <note role=tip> 00076 // This class strips all degenerate axes when determining the dimensionality 00077 // of the psf or model. So a psf with shapes of [1,1,16] or [16,1,1] is 00078 // treated the same as a Vector of length 16, and will result in one 00079 // dimensional convolutions along the first non-degenerate axis of the 00080 // supplied model. 00081 // </note> 00082 00083 // Repeated convolution can only be done along the fastest moving axes of 00084 // the supplied image. For example, if a one dimensional psf is used (so 00085 // that one dimensional convolution is being done), and a cube of data is 00086 // supplied then the convolution will be repeated for each row in the 00087 // cube. It is not currently possible to have this class do repeated one 00088 // dimensional convolution along all the columns or along the z 00089 // axis. To do this you need to use an iterator external to the class to 00090 // successively feed in the appropriate slices of your Array. 00091 00092 // The difference between linear and circular convolution can best be 00093 // explained with a one dimensional example. 00094 // Suppose the psf and data to be convolved are: 00095 // <srcblock> 00096 // psf = [0 .5 1 .1]; data = [1 0 0 0 0 0] 00097 // </srcblock> 00098 // then their linear and circular convolutions are: 00099 // <srcblock> 00100 // circular convolution = [1 .1 0 0 0 .5] 00101 // linear convolution = [1 .1 0 0 0 0] (fullSize == False) 00102 // linear convolution = [0 .5 1 .1 0 0 0 0 0] (fullSize == True) 00103 // </srcblock> 00104 // The circular convolution "wraps around" whereas the linear one does not. 00105 // Usage of the fullSize option is explained below. As can be seen from the 00106 // above example this class does not normalise the convolved result by any 00107 // factor that depends on the psf, so if the "beam area" is not unity the 00108 // flux scales will vary. 00109 00110 // The "centre" of the convolution is at the point (NX/2, NY/2) (assuming a 00111 // 2 dimensional psf) where the first point in the psf is at (0,0) and the 00112 // last is at (NX-1, NY-1). This means that a psf that is all zero except 00113 // for 1 at the "centre" pixel will when convolved with any model leave the 00114 // model unchanged. 00115 00116 // The convolution is done in the Fourier domain and the transform of the 00117 // psf (the transfer function) is cached by this class. If the cached 00118 // transfer function is the wrong size for a given model it will be 00119 // automatically be recomputed to the right size (this will involve two 00120 // FFT's) 00121 00122 // Each convolution requires two Fourier transforms which dominate the 00123 // computational load. Hence the computational expense is 00124 // <em> n Log(n) </em> for 1 dimensional and 00125 // <em> n^2 Log(n) </em> for 2 dimensional convolutions. 00126 00127 // The size of the convolved result is always the same as the input model 00128 // unless linear convolution is done with the fullSize option set to True. 00129 // In this case the result will be larger than the model and include the 00130 // full linear convolution (resultSize = psfSize+modelSize-1), rather than 00131 // the central portion. 00132 00133 // If the convolver is constructed with an expected model size (as in the 00134 // example below) then the cached transfer function will be computed to a 00135 // size appropriate for linear convolution of models of that size. If no 00136 // model size is given then the cached transfer function will be computed 00137 // with a size appropriate for circular convolution. These guidelines also 00138 // apply when using the setPsf functions. 00139 00140 // <note role=tip> 00141 // If you are intending to do 'fullsize' linear convolutions 00142 // you should also set the fullsize option to True as the cached transfer 00143 // function is a different size for fullsize linear convolutions. 00144 // </note> 00145 00146 // For linear convolution the psf can be larger, the same size or smaller 00147 // than the model but for circular convolution the psf must be smaller or the 00148 // same size. 00149 00150 // The size of the cached transfer function (and also the length of the 00151 // FFT's calculated) depends on the sizes of the psf and the model, as well 00152 // as whether you are doing linear or circular convolution and the fullSize 00153 // option. It is always advantageous to use the smallest possible psf 00154 // (ie. do not pad the psf prior to supplying it to this class). Be aware 00155 // that using odd length images will lead to this class doing odd length 00156 // FFT's, which are less computationally effecient (particularly is the 00157 // length of the transform is a prime number) in general than even length 00158 // transforms. 00159 00160 // There are only two valid template types namely, 00161 // <ol> 00162 // <li>FType=Float or 00163 // <li>FType=Double 00164 // </ol> 00165 // and the user may prefer to use the following typedef's: 00166 // <srcblock> 00167 // FloatConvolver (= Convolver<Float>) or 00168 // DoubleConvolver (= Convolver<Double>) 00169 // </srcblock> 00170 // rather than explicitly specifying the template arguements. 00171 // <note role=tip> 00172 // The typedefs need to be redeclared when using the gnu compiler making 00173 // them essentially useless. 00174 // </note> 00175 00176 // When this class is constructed you may choose to have the psf 00177 // explicitly stored by the class (by setting cachePsf=True). This will 00178 // allow speedy access to the psf when using the getPsf function. However 00179 // the getPsf function can still be called even if the psf has not been 00180 // cached. Then the psf will be computed by FFT'ing the transfer 00181 // function, and the psf will also then be cached (unless 00182 // cachePsf=Flase). Cacheing the psf is also a good idea if you will be 00183 // switching between different sized transfer functions (eg. mixing 00184 // linear and circular convolution) as it will save one of the two 00185 // FFT's. Note that even though the psf is returned as a const Array, it 00186 // is possible to inadvertently modify it using the array copy constructor 00187 // as this uses reference symantics. Modifying the psf is NOT 00188 // recommended. eg. 00189 // <srcblock> 00190 // DoubleConvolver conv(); 00191 // { 00192 // Matrix<Double> psf(20,20); 00193 // conv.setPsf(psf); 00194 // } 00195 // Matrix<Double> convPsf = conv.getPsf(); // Get the psf used by the convolver 00196 // convPsf(0,0) = -100; // And modify it. This modifies 00197 // // This internal psf used by the 00198 // // convolver also! (unless it is 00199 // // not caching the psf) 00200 // </srcblock> 00201 // 00202 // </synopsis> 00203 // 00204 // <example> 00205 // Calculate the convolution of two Matrices (psf and model); 00206 // <srcblock> 00207 // Matrix<Float> psf(4,4), model(12,12); 00208 // ...put meaningful values into the above two matrices... 00209 // FloatConvolver conv(psf, model.shape()); 00210 // conv.linearConv(result, model); // result = Convolution(psf, model) 00211 // </srcblock> 00212 // </example> 00213 // 00214 // <motivation> 00215 // I needed to do linear convolution to write a clean algorithm. It 00216 // blossomed into this class. 00217 // </motivation> 00218 // 00219 // <thrown> 00220 // <li> AipsError: if psf has more dimensions than the model. 00221 // </thrown> 00222 // 00223 // <todo asof="yyyy/mm/dd"> 00224 // <li> the class should detect if the psf or image is small and do the 00225 // convolution directly rather than use the Fourier domain 00226 // <li> Add a lattice interface, and more flexible iteration scheme 00227 // <li> Allow the psf to be specified with a 00228 // <linkto class=Function>Function</linkto>. 00229 // </todo> 00230 00231 template<class FType> class Convolver 00232 { 00233 public: 00234 // When using the default constructor the psf MUST be specified using the 00235 // setPsf function prior to doing any convolution. 00236 // <group> 00237 Convolver(){} 00238 // </group> 00239 // Create the cached Transfer function assuming that circular convolution 00240 // will be done 00241 // <group> 00242 Convolver(const Array<FType>& psf, Bool cachePsf=False); 00243 // </group> 00244 // Create the cached Transfer function assuming that linear convolution 00245 // with an array of size imageSize will be done. 00246 // <group> 00247 Convolver(const Array<FType>& psf, const IPosition& imageSize, 00248 Bool fullSize=False, Bool cachePsf=False); 00249 // </group> 00250 00251 // The copy constructor and the assignment operator make copies (and not 00252 // references) of all the internal data arrays, as this object could get 00253 // really screwed up if the private data was silently messed with. 00254 // <group> 00255 Convolver(const Convolver<FType>& other); 00256 Convolver<FType> & operator=(const Convolver<FType> & other); 00257 // </group> 00258 00259 // The destructor does nothing! 00260 // <group> 00261 ~Convolver(); 00262 // </group> 00263 00264 // Perform linear convolution of the model with the previously 00265 // specified psf. Return the answer in result. Set fullSize to True if you 00266 // want the full convolution, rather than the central portion (the same 00267 // size as the model) returned. 00268 // <group> 00269 void linearConv(Array<FType>& result, 00270 const Array<FType>& model, 00271 Bool fullSize=False); 00272 // </group> 00273 00274 // Perform circular convolution of the model with the previously 00275 // specified psf. Return the answer in result. 00276 // <group> 00277 void circularConv(Array<FType>& result, 00278 const Array<FType>& model); 00279 // </group> 00280 00281 // Set the transfer function for future convolutions to psf. 00282 // Assume circular convolution will be done 00283 // <group> 00284 void setPsf(const Array<FType>& psf, Bool cachePsf=False); 00285 // </group> 00286 // Set the transfer function for future convolutions to psf. 00287 // Assume linear convolution with a model of size imageSize 00288 // <group> 00289 void setPsf(const Array<FType>& psf, 00290 IPosition imageShape, Bool fullSize=False, 00291 Bool cachePsf=False); 00292 // </group> 00293 // Get the psf currently used by this convolver 00294 // <group> 00295 const Array<FType> getPsf(Bool cachePsf=True); 00296 // </group> 00297 00298 // Set to use convolution with lesser flips 00299 // <group> 00300 void setFastConvolve(); 00301 // </group> 00302 00303 private: 00304 IPosition thePsfSize; 00305 IPosition theFFTSize; 00306 Array<typename NumericTraits<FType>::ConjugateType> theXfr; 00307 Array<FType> thePsf; 00308 FFTServer<FType, typename NumericTraits<FType>::ConjugateType> theFFT; 00309 FFTServer<FType, typename NumericTraits<FType>::ConjugateType> theIFFT; 00310 00311 void makeXfr(const Array<FType>& psf, const IPosition& imageSize, 00312 Bool linear, Bool fullSize); 00313 void makePsf(Array<FType>& psf); 00314 IPosition defaultShape(const Array<FType>& psf); 00315 IPosition extractShape(IPosition& psfSize, const IPosition& imageSize); 00316 void doConvolution(Array<FType>& result, 00317 const Array<FType>& model, 00318 Bool fullSize); 00319 void resizeXfr(const IPosition& imageShape, Bool linear, Bool fullSize); 00320 //# void padArray(Array<FType>& paddedArr, const Array<FType>& origArr, 00321 //# const IPosition & blc); 00322 Bool valid; 00323 Bool doFast_p; 00324 void validate(); 00325 }; 00326 00327 } //# NAMESPACE CASA - END 00328 00329 #ifndef CASACORE_NO_AUTO_TEMPLATES 00330 #include <scimath/Mathematics/Convolver.tcc> 00331 #endif //# CASACORE_NO_AUTO_TEMPLATES 00332 #endif