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$
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 //   uInt 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     // Return the value of the single element located at the argument
00241   // IPosition.  
00242   // <br> The default implementation uses getSlice.
00243   // <group>
00244   T operator() (const IPosition& where) const;
00245   virtual T getAt (const IPosition& where) const;
00246   // </group>
00247   
00248   // Put the value of a single element.
00249   // <br> The default implementation uses putSlice.
00250   virtual void putAt (const T& value, const IPosition& where);
00251 
00252   // Functions which extract an Array of values from a Lattice. All the
00253   // IPosition arguments must have the same number of axes as the underlying
00254   // Lattice, otherwise, an exception is thrown. <br>
00255   // The parameters are:
00256   // <ul>
00257   // <li> buffer: a <src>COWPtr<Array<T>></src> or an
00258   //      <src>Array<T></src>. See example 2 above for an example.
00259   // <li> start: The starting position (or Bottom Left Corner), within 
00260   //      the Lattice, of the data to be extracted.
00261   // <li> shape: The shape of the data to be extracted.  This is not a
00262   //      position within the Lattice but the actual shape the buffer will 
00263   //      have after this function is called.  This argument added
00264   //      to the "start" argument should be the "Top Right Corner".
00265   // <li> stride: The increment for each axis.  A stride of
00266   //      one will return every data element, a stride of two will return
00267   //      every other element.  The IPosition elements may be different for
00268   //      each respective axis.  Thus, a stride of IPosition(3,1,2,3) says:
00269   //      fill the buffer with every element whose position has a first 
00270   //      index between start(0) and start(0)+shape(0), a second index
00271   //      which is every other element between start(1) and 
00272   //      (start(1)+shape(1))*2, and a third index of every third element 
00273   //      between start(2) and (start(2)+shape(2))*3.
00274   // <li> section: Another way of specifying the start, shape and stride
00275   // <li> removeDegenerateAxes: a Bool which dictates whether to remove 
00276   //      "empty" axis created in buffer. (e.g. extracting an n-dimensional 
00277   //      from an (n+1)-dimensional will fill 'buffer' with an array that 
00278   //      has a degenerate axis (i.e. one axis will have a length = 1.) 
00279   //      Setting removeDegenerateAxes = True will return a buffer with 
00280   //      a shape that doesn't reflect these superfluous axes.)
00281   // </ul>
00282   // 
00283   // The derived implementations of these functions return
00284   // 'True' if "buffer" is a reference to Lattice data and 'False' if it  
00285   // is a copy. 
00286   // <group>   
00287   Bool get (COWPtr<Array<T> >& buffer,
00288             Bool removeDegenerateAxes=False) const;
00289   Bool getSlice (COWPtr<Array<T> >& buffer, const Slicer& section,
00290                  Bool removeDegenerateAxes=False) const;
00291   Bool getSlice (COWPtr<Array<T> >& buffer, const IPosition& start, 
00292                  const IPosition& shape,
00293                  Bool removeDegenerateAxes=False) const;
00294   Bool getSlice (COWPtr<Array<T> >& buffer, const IPosition& start, 
00295                  const IPosition& shape, const IPosition& stride,
00296                  Bool removeDegenerateAxes=False) const;
00297   Bool get (Array<T>& buffer,
00298             Bool removeDegenerateAxes=False);
00299   Bool getSlice (Array<T>& buffer, const Slicer& section,
00300                  Bool removeDegenerateAxes=False);
00301   Bool getSlice (Array<T>& buffer, const IPosition& start,
00302                  const IPosition& shape,
00303                  Bool removeDegenerateAxes=False);
00304   Bool getSlice (Array<T>& buffer, const IPosition& start,
00305                  const IPosition& shape, const IPosition& stride,
00306                  Bool removeDegenerateAxes=False);
00307   Array<T> get (Bool removeDegenerateAxes=False) const;
00308   Array<T> getSlice (const Slicer& section,
00309                      Bool removeDegenerateAxes=False) const;
00310   Array<T> getSlice (const IPosition& start,
00311                      const IPosition& shape,
00312                      Bool removeDegenerateAxes=False) const;
00313   Array<T> getSlice (const IPosition& start,
00314                      const IPosition& shape, const IPosition& stride,
00315                      Bool removeDegenerateAxes=False) const;
00316   // </group>
00317   
00318   // A function which places an Array of values within this instance of the
00319   // Lattice at the location specified by the IPosition "where", incrementing 
00320   // by "stride".  All of the IPosition arguments must be of the same
00321   // dimensionality as the Lattice.  The sourceBuffer array may (and probably
00322   // will) have less axes than the Lattice. The stride defaults to one if
00323   // not specified. 
00324   // <group>   
00325   void putSlice (const Array<T>& sourceBuffer, const IPosition& where,
00326                  const IPosition& stride)
00327     { doPutSlice (sourceBuffer, where, stride); }
00328   void putSlice (const Array<T>& sourceBuffer, const IPosition& where);
00329   void put (const Array<T>& sourceBuffer);
00330   
00331   // </group>   
00332 
00333   // Set all elements in the Lattice to the given value.
00334   virtual void set (const T& value);
00335   
00336   // Replace every element, x, of the Lattice with the result of f(x).  You
00337   // must pass in the address of the function -- so the function must be
00338   // declared and defined in the scope of your program.  All versions of
00339   // apply require a function that accepts a single argument of type T (the
00340   // Lattice template type) and return a result of the same type.  The first
00341   // apply expects a function with an argument passed by value; the second
00342   // expects the argument to be passed by const reference; the third
00343   // requires an instance of the class <src>Functional<T,T></src>.  The
00344   // first form ought to run faster for the built-in types, which may be an
00345   // issue for large Lattices stored in memory, where disk access is not an
00346   // issue.
00347   // <group>
00348   virtual void apply (T (*function)(T));
00349   virtual void apply (T (*function)(const T&));
00350   virtual void apply (const Functional<T,T>& function);
00351   // </group>
00352 
00353   // Add, subtract, multiple, or divide by another Lattice.
00354   // The other Lattice can be a scalar (e.g. the result of LatticeExpr).
00355   // Possible masks are not taken into account.
00356   // <group>
00357   void operator+= (const Lattice<T>& other)
00358   { handleMath (other, 0); }
00359   void operator-= (const Lattice<T>& other)
00360     { handleMath (other, 1); }
00361   void operator*= (const Lattice<T>& other)
00362     { handleMath (other, 2); }
00363   void operator/= (const Lattice<T>& other)
00364     { handleMath (other, 3); }
00365   // </group>
00366 
00367   // Copy the data from the given lattice to this one.
00368   // The default implementation uses function <src>copyDataTo</src>.
00369   virtual void copyData (const Lattice<T>& from);
00370 
00371   // Copy the data from this lattice to the given lattice.
00372   // The default implementation only copies data (thus no mask, etc.).
00373   virtual void copyDataTo (Lattice<T>& to) const;
00374 
00375   // This function returns the advised maximum number of pixels to
00376   // include in the cursor of an iterator. The default implementation
00377   // returns a number that is a power of two and includes enough pixels to
00378   // consume between 4 and 8 MBytes of memory.
00379   virtual uInt advisedMaxPixels() const;
00380 
00381   // These functions are used by the LatticeIterator class to generate an
00382   // iterator of the correct type for a specified Lattice. Not recommended
00383   // for general use.
00384   // <br>The default implementation creates a LatticeIterInterface object.
00385   virtual LatticeIterInterface<T>* makeIter (const LatticeNavigator& navigator,
00386                                              Bool useRef) const;
00387 
00388   // The functions (in the derived classes) doing the actual work.
00389   // These functions are public, so they can be used internally in the
00390   // various Lattice classes, which is especially useful for doGetSlice.
00391   // <br>However, doGetSlice does not call Slicer::inferShapeFromSource
00392   // to fill in possible unspecified section values. Therefore one
00393   // should normally use one of the get(Slice) functions. doGetSlice
00394   // should be used with care and only when performance is an issue.
00395   // <group>
00396   virtual Bool doGetSlice (Array<T>& buffer, const Slicer& section) = 0;
00397   virtual void doPutSlice (const Array<T>& buffer, const IPosition& where,
00398                            const IPosition& stride) = 0;
00399   // </group>
00400 
00401 protected:
00402   // Define default constructor to satisfy compiler.
00403   Lattice() {};
00404 
00405   // Handle the Math operators (+=, -=, *=, /=).
00406   // They work similarly to copyData(To).
00407   // However, they are not defined for Bool types, thus specialized below.
00408   // <group>
00409   virtual void handleMath (const Lattice<T>& from, int oper);
00410   virtual void handleMathTo (Lattice<T>& to, int oper) const;
00411   // </group>
00412 
00413   // Copy constructor and assignment can only be used by derived classes.
00414   // <group>
00415   Lattice (const Lattice<T>&) {};
00416   Lattice<T>& operator= (const Lattice<T>&)
00417     { return *this; }
00418   // </group>
00419 };
00420 
00421 
00422 template<> inline
00423 void Lattice<Bool>::handleMathTo (Lattice<Bool>& to, int oper) const
00424   { throwBoolMath(); }
00425 
00426 
00427 
00428 } //# NAMESPACE CASA - END
00429 
00430 #ifndef AIPS_NO_TEMPLATE_SRC
00431 #include <lattices/Lattices/Lattice.cc>
00432 #endif //# AIPS_NO_TEMPLATE_SRC
00433 #endif

Generated on Mon Sep 1 22:34:49 2008 for NRAOCASA by  doxygen 1.5.1