casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Convolver.h
Go to the documentation of this file.
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