00001 //# Lattice.h: Lattice is an abstract base class for array-like classes 00002 //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,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 //# $Id$ 00027 00028 #ifndef LATTICES_LATTICE_H 00029 #define LATTICES_LATTICE_H 00030 00031 00032 //# Includes 00033 #include <casacore/casa/aips.h> 00034 #include <casacore/lattices/Lattices/LatticeBase.h> 00035 #include <casacore/casa/Arrays/Slicer.h> 00036 00037 namespace casacore { //# NAMESPACE CASACORE - BEGIN 00038 00039 //# Forward Declarations 00040 class IPosition; 00041 class LatticeNavigator; 00042 template <class T> class Array; 00043 template <class T> class COWPtr; 00044 template <class Domain, class Range> class Functional; 00045 template <class T> class LatticeIterInterface; 00046 00047 00048 // <summary> 00049 // A templated, abstract base class for array-like objects. 00050 // </summary> 00051 00052 // <use visibility=export> 00053 00054 // <reviewed reviewer="Peter Barnes" date="1999/10/30" tests="tArrayLattice.cc" demos="dLattice.cc"> 00055 // </reviewed> 00056 00057 // <prerequisite> 00058 // <li> <linkto class="IPosition"> IPosition </linkto> 00059 // <li> <linkto class="Array"> Array </linkto> 00060 // <li> <linkto class="LatticeBase"> LatticeBase </linkto> 00061 // <li> Abstract Base class Inheritance - try "Advanced C++" by James 00062 // O. Coplien, Ch. 5. 00063 // </prerequisite> 00064 00065 // <etymology> 00066 // Lattice: "A regular, periodic configuration of points, particles, 00067 // or objects, throughout an area of a space..." (American Heritage Directory) 00068 // This definition matches our own: an n-dimensional arrangement of items, 00069 // on regular orthogonal axes. 00070 // </etymology> 00071 00072 // <synopsis> 00073 // This pure abstract base class defines the operations which may be performed 00074 // on any concrete class derived from it. It has only a few non-pure virtual 00075 // member functions. 00076 // The fundamental contribution of this class, therefore, is that it 00077 // defines the operations derived classes must provide: 00078 // <ul> 00079 // <li> how to extract a "slice" (or sub-array, or subsection) from 00080 // a Lattice. 00081 // <li> how to copy a slice in. 00082 // <li> how to get and put a single element 00083 // <li> how to apply a function to all elements 00084 // <li> various shape related functions. 00085 // </ul> 00086 // The base class <linkto class=LatticeBase>LatticeBase</linkto> contains 00087 // several functions not dependent on the template parameter. 00088 // <note role=tip> Lattices always have a zero origin. </note> 00089 // </synopsis> 00090 00091 // <example> 00092 // Because Lattice is an abstract base class, an actual instance of this 00093 // class cannot be constructed. However the interface it defines can be used 00094 // inside a function. This is always recommended as it allows functions 00095 // which have Lattices as arguments to work for any derived class. 00096 // <p> 00097 // I will give a few examples here and then refer the reader to the 00098 // <linkto class="ArrayLattice">ArrayLattice</linkto> class (a memory resident 00099 // Lattice) and the <linkto class="PagedArray">PagedArray</linkto> class (a 00100 // disk based Lattice) which contain further examples with concrete 00101 // classes (rather than an abstract one). All the examples shown below are used 00102 // in the <src>dLattice.cc</src> demo program. 00103 // 00104 // <h4>Example 1:</h4> 00105 // This example calculates the mean of the Lattice. Because Lattices can be too 00106 // large to fit into physical memory it is not good enough to simply use 00107 // <src>getSlice</src> to read all the elements into an Array. Instead the 00108 // Lattice is accessed in chunks which can fit into memory (the size is 00109 // determined by the <src>advisedMaxPixels</src> and <src>niceCursorShape</src> 00110 // functions). The <src>LatticeIterator::cursor()</src> function then returns 00111 // each of these chunks as an Array and the standard Array based functions are 00112 // used to calculate the mean on each of these chunks. Functions like this one 00113 // are the recommended way to access Lattices as the 00114 // <linkto class="LatticeIterator">LatticeIterator</linkto> will correctly 00115 // setup any required caches. 00116 // 00117 // <srcblock> 00118 // Complex latMean(const Lattice<Complex>& lat) { 00119 // const uInt cursorSize = lat.advisedMaxPixels(); 00120 // const IPosition cursorShape = lat.niceCursorShape(cursorSize); 00121 // const IPosition latticeShape = lat.shape(); 00122 // Complex currentSum = 0.0f; 00123 // size_t nPixels = 0u; 00124 // RO_LatticeIterator<Complex> iter(lat, 00125 // LatticeStepper(latticeShape, cursorShape)); 00126 // for (iter.reset(); !iter.atEnd(); iter++){ 00127 // currentSum += sum(iter.cursor()); 00128 // nPixels += iter.cursor().nelements(); 00129 // } 00130 // return currentSum/nPixels; 00131 // } 00132 // </srcblock> 00133 // 00134 // <h4>Example 2:</h4> 00135 // Sometimes it will be neccesary to access slices of a Lattice in a nearly 00136 // random way. Often this can be done using the subSection commands in the 00137 // <linkto class="LatticeStepper">LatticeStepper</linkto> class. But it is also 00138 // possible to use the getSlice and putSlice functions. The following example 00139 // does a two-dimensional Real to Complex Fourier transform. This example is 00140 // restricted to four-dimensional Arrays (unlike the previous example) and does 00141 // not set up any caches (caching is currently only used with PagedArrays). So 00142 // only use getSlice and putSlice when things cannot be done using 00143 // LatticeIterators. 00144 // 00145 // <srcblock> 00146 // void FFT2DReal2Complex(Lattice<Complex>& result, 00147 // const Lattice<Float>& input){ 00148 // AlwaysAssert(input.ndim() == 4, AipsError); 00149 // const IPosition shape = input.shape(); 00150 // const uInt nx = shape(0); 00151 // AlwaysAssert (nx > 1, AipsError); 00152 // const uInt ny = shape(1); 00153 // AlwaysAssert (ny > 1, AipsError); 00154 // const uInt npol = shape(2); 00155 // const uInt nchan = shape(3); 00156 // const IPosition resultShape = result.shape(); 00157 // AlwaysAssert(resultShape.nelements() == 4, AipsError); 00158 // AlwaysAssert(resultShape(3) == nchan, AipsError); 00159 // AlwaysAssert(resultShape(2) == npol, AipsError); 00160 // AlwaysAssert(resultShape(1) == ny, AipsError); 00161 // AlwaysAssert(resultShape(0) == nx/2 + 1, AipsError); 00162 // 00163 // const IPosition inputSliceShape(4,nx,ny,1,1); 00164 // const IPosition resultSliceShape(4,nx/2+1,ny,1,1); 00165 // COWPtr<Array<Float> > 00166 // inputArrPtr(new Array<Float>(inputSliceShape.nonDegenerate())); 00167 // Array<Complex> resultArray(resultSliceShape.nonDegenerate()); 00168 // FFTServer<Float, Complex> FFT2D(inputSliceShape.nonDegenerate()); 00169 // 00170 // IPosition start(4,0); 00171 // Bool isARef; 00172 // for (uInt c = 0; c < nchan; c++){ 00173 // for (uInt p = 0; p < npol; p++){ 00174 // isARef = input.getSlice(inputArrPtr, 00175 // Slicer(start,inputSliceShape), True); 00176 // FFT2D.fft(resultArray, *inputArrPtr); 00177 // result.putSlice(resultArray, start); 00178 // start(2) += 1; 00179 // } 00180 // start(2) = 0; 00181 // start(3) += 1; 00182 // } 00183 // } 00184 // </srcblock> 00185 // Note that the <linkto class=LatticeFFT>LatticeFFT</linkto> class 00186 // offers a nice way to do lattice based FFTs. 00187 // 00188 // <h4>Example 3:</h4> 00189 // Occasionally you may want to access a few elements of a Lattice without 00190 // all the difficulty involved in setting up Iterators or calling getSlice 00191 // and putSlice. This is demonstrated in the example below. 00192 // Setting a single element can be done with the <src>putAt</src> function, 00193 // while getting a single element can be done with the parenthesis operator. 00194 // Using these functions to access many elements of a Lattice is not 00195 // recommended as this is the slowest access method. 00196 // 00197 // In this example an ideal point spread function will be inserted into an 00198 // empty Lattice. As with the previous examples all the action occurs 00199 // inside a function because Lattice is an interface (abstract) class. 00200 // 00201 // <srcblock> 00202 // void makePsf(Lattice<Float>& psf) { 00203 // const IPosition centrePos = psf.shape()/2; 00204 // psf.set(0.0f); // this sets all the elements to zero 00205 // // As it uses a LatticeIterator it is efficient 00206 // psf.putAt (1, centrePos); // This sets just the centre element to one 00207 // AlwaysAssert(near(psf(centrePos), 1.0f, 1E-6), AipsError); 00208 // AlwaysAssert(near(psf(centrePos*0), 0.0f, 1E-6), AipsError); 00209 // } 00210 // </srcblock> 00211 // </example> 00212 00213 // <motivation> 00214 // Creating an abstract base class which provides a common interface between 00215 // memory and disk based arrays has a number of advantages. 00216 // <ul> 00217 // <li> It allows functions common to all arrays to be written independent 00218 // of the way the data is stored. This is illustrated in the three examples 00219 // above. 00220 // <li> It reduces the learning curve for new users who only have to become 00221 // familiar with one interface (ie. Lattice) rather than distinct interfaces 00222 // for different array types. 00223 // </ul> 00224 // </motivation> 00225 00226 // <todo asof="1996/07/01"> 00227 // <li> Make PagedArray cache functions virtual in this base class. 00228 // </todo> 00229 00230 00231 template <class T> class Lattice : public LatticeBase 00232 { 00233 public: 00234 // a virtual destructor is needed so that it will use the actual destructor 00235 // in the derived class 00236 virtual ~Lattice(); 00237 00238 // Make a copy of the derived object (reference semantics). 00239 virtual Lattice<T>* clone() const = 0; 00240 00241 // Get the data type of the lattice. 00242 virtual DataType dataType() const; 00243 00244 // Return the value of the single element located at the argument 00245 // IPosition. 00246 // <br> The default implementation uses getSlice. 00247 // <group> 00248 T operator() (const IPosition& where) const; 00249 virtual T getAt (const IPosition& where) const; 00250 // </group> 00251 00252 // Put the value of a single element. 00253 // <br> The default implementation uses putSlice. 00254 virtual void putAt (const T& value, const IPosition& where); 00255 00256 // Functions which extract an Array of values from a Lattice. All the 00257 // IPosition arguments must have the same number of axes as the underlying 00258 // Lattice, otherwise, an exception is thrown. <br> 00259 // The parameters are: 00260 // <ul> 00261 // <li> buffer: a <src>COWPtr<Array<T>></src> or an 00262 // <src>Array<T></src>. See example 2 above for an example. 00263 // <li> start: The starting position (or Bottom Left Corner), within 00264 // the Lattice, of the data to be extracted. 00265 // <li> shape: The shape of the data to be extracted. This is not a 00266 // position within the Lattice but the actual shape the buffer will 00267 // have after this function is called. This argument added 00268 // to the "start" argument should be the "Top Right Corner". 00269 // <li> stride: The increment for each axis. A stride of 00270 // one will return every data element, a stride of two will return 00271 // every other element. The IPosition elements may be different for 00272 // each respective axis. Thus, a stride of IPosition(3,1,2,3) says: 00273 // fill the buffer with every element whose position has a first 00274 // index between start(0) and start(0)+shape(0), a second index 00275 // which is every other element between start(1) and 00276 // (start(1)+shape(1))*2, and a third index of every third element 00277 // between start(2) and (start(2)+shape(2))*3. 00278 // <li> section: Another way of specifying the start, shape and stride 00279 // <li> removeDegenerateAxes: a Bool which dictates whether to remove 00280 // "empty" axis created in buffer. (e.g. extracting an n-dimensional 00281 // from an (n+1)-dimensional will fill 'buffer' with an array that 00282 // has a degenerate axis (i.e. one axis will have a length = 1.) 00283 // Setting removeDegenerateAxes = True will return a buffer with 00284 // a shape that doesn't reflect these superfluous axes.) 00285 // </ul> 00286 // 00287 // The derived implementations of these functions return 00288 // 'True' if "buffer" is a reference to Lattice data and 'False' if it 00289 // is a copy. 00290 // <group> 00291 Bool get (COWPtr<Array<T> >& buffer, 00292 Bool removeDegenerateAxes=False) const; 00293 Bool getSlice (COWPtr<Array<T> >& buffer, const Slicer& section, 00294 Bool removeDegenerateAxes=False) const; 00295 Bool getSlice (COWPtr<Array<T> >& buffer, const IPosition& start, 00296 const IPosition& shape, 00297 Bool removeDegenerateAxes=False) const; 00298 Bool getSlice (COWPtr<Array<T> >& buffer, const IPosition& start, 00299 const IPosition& shape, const IPosition& stride, 00300 Bool removeDegenerateAxes=False) const; 00301 Bool get (Array<T>& buffer, 00302 Bool removeDegenerateAxes=False); 00303 Bool getSlice (Array<T>& buffer, const Slicer& section, 00304 Bool removeDegenerateAxes=False); 00305 Bool getSlice (Array<T>& buffer, const IPosition& start, 00306 const IPosition& shape, 00307 Bool removeDegenerateAxes=False); 00308 Bool getSlice (Array<T>& buffer, const IPosition& start, 00309 const IPosition& shape, const IPosition& stride, 00310 Bool removeDegenerateAxes=False); 00311 Array<T> get (Bool removeDegenerateAxes=False) const; 00312 Array<T> getSlice (const Slicer& section, 00313 Bool removeDegenerateAxes=False) const; 00314 Array<T> getSlice (const IPosition& start, 00315 const IPosition& shape, 00316 Bool removeDegenerateAxes=False) const; 00317 Array<T> getSlice (const IPosition& start, 00318 const IPosition& shape, const IPosition& stride, 00319 Bool removeDegenerateAxes=False) const; 00320 // </group> 00321 00322 // A function which places an Array of values within this instance of the 00323 // Lattice at the location specified by the IPosition "where", incrementing 00324 // by "stride". All of the IPosition arguments must be of the same 00325 // dimensionality as the Lattice. The sourceBuffer array may (and probably 00326 // will) have less axes than the Lattice. The stride defaults to one if 00327 // not specified. 00328 // <group> 00329 void putSlice (const Array<T>& sourceBuffer, const IPosition& where, 00330 const IPosition& stride) 00331 { doPutSlice (sourceBuffer, where, stride); } 00332 void putSlice (const Array<T>& sourceBuffer, const IPosition& where); 00333 void put (const Array<T>& sourceBuffer); 00334 00335 // </group> 00336 00337 // Set all elements in the Lattice to the given value. 00338 virtual void set (const T& value); 00339 00340 // Replace every element, x, of the Lattice with the result of f(x). You 00341 // must pass in the address of the function -- so the function must be 00342 // declared and defined in the scope of your program. All versions of 00343 // apply require a function that accepts a single argument of type T (the 00344 // Lattice template type) and return a result of the same type. The first 00345 // apply expects a function with an argument passed by value; the second 00346 // expects the argument to be passed by const reference; the third 00347 // requires an instance of the class <src>Functional<T,T></src>. The 00348 // first form ought to run faster for the built-in types, which may be an 00349 // issue for large Lattices stored in memory, where disk access is not an 00350 // issue. 00351 // <group> 00352 virtual void apply (T (*function)(T)); 00353 virtual void apply (T (*function)(const T&)); 00354 virtual void apply (const Functional<T,T>& function); 00355 // </group> 00356 00357 // Add, subtract, multiple, or divide by another Lattice. 00358 // The other Lattice can be a scalar (e.g. the result of LatticeExpr). 00359 // Possible masks are not taken into account. 00360 // <group> 00361 void operator+= (const Lattice<T>& other) 00362 { handleMath (other, 0); } 00363 void operator-= (const Lattice<T>& other) 00364 { handleMath (other, 1); } 00365 void operator*= (const Lattice<T>& other) 00366 { handleMath (other, 2); } 00367 void operator/= (const Lattice<T>& other) 00368 { handleMath (other, 3); } 00369 // </group> 00370 00371 // Copy the data from the given lattice to this one. 00372 // The default implementation uses function <src>copyDataTo</src>. 00373 virtual void copyData (const Lattice<T>& from); 00374 00375 // Copy the data from this lattice to the given lattice. 00376 // The default implementation only copies data (thus no mask, etc.). 00377 virtual void copyDataTo (Lattice<T>& to) const; 00378 00379 // This function returns the advised maximum number of pixels to 00380 // include in the cursor of an iterator. The default implementation 00381 // returns a number that is a power of two and includes enough pixels to 00382 // consume between 4 and 8 MBytes of memory. 00383 virtual uInt advisedMaxPixels() const; 00384 00385 // These functions are used by the LatticeIterator class to generate an 00386 // iterator of the correct type for a specified Lattice. Not recommended 00387 // for general use. 00388 // <br>The default implementation creates a LatticeIterInterface object. 00389 virtual LatticeIterInterface<T>* makeIter (const LatticeNavigator& navigator, 00390 Bool useRef) const; 00391 00392 // The functions (in the derived classes) doing the actual work. 00393 // These functions are public, so they can be used internally in the 00394 // various Lattice classes, which is especially useful for doGetSlice. 00395 // <br>However, doGetSlice does not call Slicer::inferShapeFromSource 00396 // to fill in possible unspecified section values. Therefore one 00397 // should normally use one of the get(Slice) functions. doGetSlice 00398 // should be used with care and only when performance is an issue. 00399 // <group> 00400 virtual Bool doGetSlice (Array<T>& buffer, const Slicer& section) = 0; 00401 virtual void doPutSlice (const Array<T>& buffer, const IPosition& where, 00402 const IPosition& stride) = 0; 00403 // </group> 00404 00405 protected: 00406 // Define default constructor to satisfy compiler. 00407 Lattice() {}; 00408 00409 // Handle the Math operators (+=, -=, *=, /=). 00410 // They work similarly to copyData(To). 00411 // However, they are not defined for Bool types, thus specialized below. 00412 // <group> 00413 virtual void handleMath (const Lattice<T>& from, int oper); 00414 virtual void handleMathTo (Lattice<T>& to, int oper) const; 00415 // </group> 00416 00417 // Copy constructor and assignment can only be used by derived classes. 00418 // <group> 00419 Lattice (const Lattice<T>&) 00420 : LatticeBase() {} 00421 Lattice<T>& operator= (const Lattice<T>&) 00422 { return *this; } 00423 // </group> 00424 }; 00425 00426 00427 template<> inline 00428 void Lattice<Bool>::handleMathTo (Lattice<Bool>&, int) const 00429 { throwBoolMath(); } 00430 00431 //# Declare extern templates for often used types. 00432 #ifdef AIPS_CXX11 00433 extern template class Lattice<Float>; 00434 extern template class Lattice<Complex>; 00435 #endif 00436 00437 00438 } //# NAMESPACE CASACORE - END 00439 00440 //# There is a problem in including Lattice.tcc, because it needs 00441 //# LatticeIterator.h which in its turn includes Lattice.h again. 00442 //# So in a source file including LatticeIterator.h, Lattice::set fails 00443 //# to compile, because the LatticeIterator declarations are not seen yet. 00444 //# Therefore LatticeIterator.h is included here, while LatticeIterator.h 00445 //# includes Lattice.tcc. 00446 #ifndef CASACORE_NO_AUTO_TEMPLATES 00447 #include <casacore/lattices/Lattices/LatticeIterator.h> 00448 #endif //# CASACORE_NO_AUTO_TEMPLATES 00449 #endif