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