casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
TiledLineStepper.h
Go to the documentation of this file.
00001 //# TiledLineStepper.h: Step a Vector cursor optimally through a tiled Lattice
00002 //# Copyright (C) 1997,1998,1999,2000
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: TiledLineStepper.h 20652 2009-07-06 05:04:32Z Malte.Marquarding $
00027 
00028 #ifndef LATTICES_TILEDLINESTEPPER_H
00029 #define LATTICES_TILEDLINESTEPPER_H
00030 
00031 //# Includes
00032 #include <casa/aips.h>
00033 #include <lattices/Lattices/LatticeNavigator.h>
00034 #include <lattices/Lattices/LatticeIndexer.h>
00035 #include <casa/Arrays/IPosition.h>
00036 
00037 
00038 namespace casa { //# NAMESPACE CASA - BEGIN
00039 
00040 // <summary>
00041 // Step a Vector cursor optimally through a tiled Lattice.
00042 // </summary>
00043 // <use visibility=export>
00044 
00045 // <reviewed reviewer="Peter Barnes" date="1999/10/30" tests="tTiledLineStepper.cc">
00046 // </reviewed>
00047 
00048 // <prerequisite>
00049 //   <li> <linkto class=LatticeNavigator> LatticeNavigator </linkto>
00050 // </prerequisite>
00051 
00052 // <etymology>
00053 // TiledLineStepper is used to step a Vector cursor optimally through
00054 // a Lattice that is tiled.
00055 // </etymology>
00056 
00057 // <synopsis> 
00058 // When you wish to traverse a Lattice (say, a PagedArray or an Image) you
00059 // will usually create a LatticeIterator.  Once created, you may attach a
00060 // LatticeNavigator to the iterator. A TiledLineStepper, is a concrete class
00061 // derived from the abstract LatticeNavigator that allows you to move
00062 // a Vector cursor through the Lattice in a way that will minimize the
00063 // amount of cache memory consumed.
00064 // <p>
00065 // Some Lattices (in particular PagedArrays) are stored (on disk) in
00066 // tiles. For an N-dimensional Lattice a tile is an N-dimensional
00067 // subsection with fewer elements along each axis. For example a Lattice of
00068 // shape [512,512,4,32] may have a tile shape of [32,16,4,16], and there
00069 // will be 16*32*1*2 (=1024) tiles in the entire Lattice. To allow efficient
00070 // access of the data in a Lattice some tiles are cached in memory. As each
00071 // tile may consume a fair bit of memory (in this example 128kBytes,
00072 // assuming each element consumes 4 bytes), it is desirable to minimise the
00073 // number of tiles held in the cache. But it is also desirable to minimise
00074 // the number of times a tiles must be read into or written from the
00075 // cache as this may require a time consuming operation like disk I/O.
00076 // <p>
00077 // Now suppose you wanted to traverse a Lattice with a Vector cursor of
00078 // length 512 pixel aligned along the x-axis. Using a
00079 // <linkto class=LatticeStepper>LatticeStepper</linkto>, each Vector is
00080 // retrieved from the Lattice sequentially and without any consideration of
00081 // the underlying tile shape. What is the optimal cache size for the above
00082 // example?
00083 // <p>
00084 // Suppose we have a cache size of 16 ie., the number of tiles along the
00085 // x-axis. Then Vectors beginning at positions [0,0,0,0] to [0,15,0,0] will
00086 // be stored in the cache. But the next Vector beginning at position
00087 // [0,16,0,0] will flush the cache and read in another 16 tiles. This I/O
00088 // takes time and will occur 16 times for each plane in the four dimensional
00089 // Lattice. Further when the cursor moves to position [0,0,1,0] the 16 tiles
00090 // that where initially in the cache will need to be read again. To avoid
00091 // all this cache I/O it is better to have a bigger cache.
00092 // <p>
00093 // Suppose the cache size is 16*32 (=512) ie., enough tiles to contain an
00094 // (x,y)-plane. Then the cache size will not be flushed until the cursor is
00095 // moved to position [0,0,0,16]. Further the cache will never need to read
00096 // back into memory tiles that had previously been stored in there. The
00097 // cache is big enough to store tiles until they have been completely
00098 // used. But this cache is 64MBytes in size, and consumes too much memory
00099 // for many computers.
00100 // <p>
00101 // This where a TiledLineStepper is useful. Because it knows the shape of the
00102 // tiles in the underlying Lattice it moves the cursor to return all the
00103 // Vectors in the smallest possible cache of tiles before moving on to the
00104 // next set of tiles. Using the above example again, the TiledLineStepper will
00105 // move the beginning of the Vector cursor in the following pattern.
00106 // <srcblock>
00107 // [0,0,0,0], [0,1,0,0], [0,2,0,0], ... [0,15,0,0]
00108 // [0,0,1,0], [0,1,1,0],            ... [0,15,1,0], 
00109 //                                  ... [0,15,3,0],
00110 // [0,0,0,1], ...                       [0,15,3,15]
00111 // </srcblock>
00112 // Moving the Vector cursor through all 16*4*16 (=1024 positions) can be
00113 // done by caching only 16 tiles in memory (those along the x-axis). Hence
00114 // the cache size need only be 2MBytes in size. Further once all 1024
00115 // vectors have been returned it is not necessary to read these 16 tiles
00116 // back into memory. All the data in those tiles has already been
00117 // accessed. Using a TiledLineStepper rather than a LatticeStepper has,
00118 // in this example, resulted in a drop in the required cache size from
00119 // 64MBytes down to 2MBytes. 
00120 // <p>
00121 // In constructing a TiledLineStepper, you specify the Lattice shape, the
00122 // tile shape and the axis the Vector cursor will be aligned with. Specifying
00123 // an axis=0 will align the cursor with the x-axis and axis=2 will produce a
00124 // cursor that is along the z-axis. The length of the cursor is always the
00125 // same as the number of elements in the Lattice along the axis the cursor
00126 // is aligned with.
00127 // <br>It is possible to use the function <src>subSection</src> to
00128 // traverse only a subsection of the lattice.
00129 // <p>
00130 // The cursor position can be incremented or decremented to retrieve the next
00131 // or previous Vector in the Lattice. The position of the next Vector in the
00132 // Lattice will depend on the tile shape, and is described above. Within a tile
00133 // the Vector cursor will move first through the x-axis and then the y-axis
00134 // (assuming we have a cursor oriented along the z-axis). In general the lower
00135 // dimensions will be exhausted (within a tile) before moving the cursor
00136 // through higher dimensions. This intra-tile behaviour for cursor movement
00137 // extends to the inter-tile movement of the cursor between tiles. 
00138 // </synopsis> 
00139 
00140 // <example>
00141 // This example is of a global function that will do a 2-D inplace
00142 // complex Fourier transform of an arbitrary large Lattice (which
00143 // must have at least two dimensions).
00144 //
00145 // A two dimensional transform is done by successive one dimensional
00146 // transforms along all the rows and then all the columns in the
00147 // lattice. Scoping is used to destroy iterators once they have been
00148 // used. This frees up the cache memory associated with the cursor in each
00149 // iterator.
00150 //
00151 // <srcblock>
00152 // void FFT2DComplex (Lattice<Complex>& cArray,
00153 //                    const Bool direction)
00154 // {
00155 //   const uInt ndim = cArray.ndim();
00156 //   AlwaysAssert(ndim > 1, AipsError);
00157 //   const IPosition latticeShape = cArray.shape();
00158 //   const uInt nx=latticeShape(0);
00159 //   const uInt ny=latticeShape(1);
00160 //   const IPosition tileShape = cArray.niceCursorShape();
00161 //
00162 //   {
00163 //     TiledLineStepper tsx(latticeShape, tileShape, 0);
00164 //     LatticeIterator<Complex> lix(cArray, tsx);
00165 //     FFTServer<Float,Complex> fftx(IPosition(1, nx));
00166 //     for (lix.reset();!lix.atEnd();lix++) {
00167 //       fftx.fft(lix.rwVectorCursor(), direction);
00168 //     }
00169 //   }
00170 //   {
00171 //     TiledLineStepper tsy(latticeShape, tileShape, 1);
00172 //     LatticeIterator<Complex> liy(cArray, tsy);
00173 //     FFTServer<Float,Complex> ffty(IPosition(1, ny));
00174 //     for (liy.reset();!liy.atEnd();liy++) {
00175 //       ffty.fft(liy.rwVectorCursor(), direction);
00176 //     }
00177 //   }
00178 // }
00179 // </srcblock>
00180 // </example>
00181 
00182 // <motivation>
00183 // Moving through a Lattice by equal sized chunks, and without regard
00184 // to the nature of the data, is a basic and common procedure.  
00185 // </motivation>
00186 
00187 // <todo asof="1997/03/28">
00188 //  <li> Support for Matrix and higher dimensional cursors can be used.
00189 // </todo>
00190 
00191 
00192 class TiledLineStepper : public LatticeNavigator
00193 {
00194 public:
00195 
00196   // Construct a TiledLineStepper by specifying the Lattice shape,
00197   // a tile shape and the axis along which the Vector cursor will lie
00198   // (0 means the x-axis). Is is nearly always advisable to make the
00199   // tileShape identical to the Lattice tileShape. This can be obtained by
00200   // <src>lat.niceCursorShape(lat.advisedMaxPixels())</src>
00201   // where <src>lat</src> is a Lattice object.
00202   TiledLineStepper (const IPosition& latticeShape, 
00203                     const IPosition& tileShape, 
00204                     const uInt axis);
00205 
00206   // The copy constructor uses copy semantics.
00207   TiledLineStepper (const TiledLineStepper& other);
00208     
00209   ~TiledLineStepper();
00210 
00211   // The assignment operator uses copy semantics.
00212   TiledLineStepper& operator= (const TiledLineStepper& other);
00213 
00214   // Increment operator (postfix or prefix version) - move the cursor
00215   // forward one step. Returns True if the cursor was moved.
00216   virtual Bool operator++(int);
00217 
00218   // Decrement operator (postfix or prefix version) - move the cursor
00219   // backwards one step. Returns True if the cursor was moved.
00220   virtual Bool operator--(int);
00221 
00222   // Function to move the cursor to the beginning of the Lattice. Also
00223   // resets the number of steps (<src>nsteps</src> function) to zero. 
00224   virtual void reset();
00225 
00226   // Function which returns "True" if the cursor is at the beginning of the
00227   // Lattice, otherwise, returns "False"
00228   virtual Bool atStart() const;
00229 
00230   // Function which returns "True" if an attempt has been made to increment
00231   // the cursor beyond the end of the Lattice.
00232   virtual Bool atEnd() const;
00233 
00234   // Function to return the number of steps (increments & decrements) taken
00235   // since construction (or since last reset).  This is a running count of
00236   // all cursor movement (operator++ or operator--), even though
00237   // N-increments followed by N-decrements will always leave the cursor in
00238   // the original position.
00239   virtual uInt nsteps() const;
00240 
00241   // Function which returns the current position of the beginning of the
00242   // cursor. The <src>position</src> function is relative to the origin
00243   // in the main Lattice.
00244   // <group>
00245   virtual IPosition position() const;
00246   // </group>
00247 
00248   // Function which returns the current position of the end of the
00249   // cursor. The <src>endPosition</src> function is relative to the origin
00250   // in the main Lattice.
00251   // <group>
00252   virtual IPosition endPosition() const;
00253   // </group>
00254 
00255   // Functions which returns the shape of the Lattice being iterated
00256   // through. <src>latticeShape</src> always returns the shape of the main
00257   // Lattice while <src>subLatticeShape</src> returns the shape of any
00258   // sub-Lattice defined using the <src>subSection</src> function. 
00259   // <group>
00260   virtual IPosition latticeShape() const;
00261   virtual IPosition subLatticeShape() const;
00262   // </group>
00263 
00264   // Function which returns the shape of the cursor. This always includes
00265   // all axes (ie. it includes degenerates axes)
00266   virtual IPosition cursorShape() const;
00267 
00268   // Function which returns the axes of the cursor.
00269   virtual IPosition cursorAxes() const;
00270 
00271   // Function which returns the shape of the "tile" the cursor will iterate
00272   // through before moving onto the next tile. THIS IS NOT THE SAME AS THE
00273   // TILE SHAPE USED BY THE LATTICE. It is nearly the same except that the
00274   // axis the cursor is aligned with is replaced by the shape of the Lattice
00275   // on that axis. eg., If a Lattice has a shape of [512,512,4,32] and a
00276   // tile shape of [32,16,4,16] then <src>tileShape()</src> will return
00277   // [512,16,4,16] if the cursor is along the x-axis and [32,512,4,16] if the
00278   // cursor is along the y-axis.
00279   IPosition tileShape() const;
00280 
00281   // Function which returns "True" if the increment/decrement operators have
00282   // moved the cursor position such that part of the cursor beginning or end
00283   // is hanging over the edge of the Lattice. This always returns False.
00284   virtual Bool hangOver() const;
00285 
00286   // Functions to specify a "section" of the Lattice to step over. A section
00287   // is defined in terms of the Bottom Left Corner (blc), Top Right Corner
00288   // (trc), and step size (inc), on ALL of its axes, including degenerate
00289   // axes. The step size defaults to one if not specified.
00290   // <group>
00291   virtual void subSection (const IPosition& blc, const IPosition& trc);
00292   virtual void subSection (const IPosition& blc, const IPosition& trc, 
00293                            const IPosition& inc);
00294   // </group>
00295 
00296   // Return the bottom left hand corner (blc), top right corner (trc) or
00297   // step size (increment) used by the current sub-Lattice. If no
00298   // sub-Lattice has been defined (with the <src>subSection</src> function)
00299   // these functions return blc=0, trc=latticeShape-1, increment=1, ie. the
00300   // entire Lattice.
00301   // <group>
00302   virtual IPosition blc() const;
00303   virtual IPosition trc() const;
00304   virtual IPosition increment() const;
00305   // </group>
00306 
00307   // Return the axis path.
00308   // See <linkto class=LatticeStepper>LatticeStepper</linkto> for a
00309   // description and examples.
00310   virtual const IPosition& axisPath() const;
00311 
00312   // Function which returns a pointer to dynamic memory of an exact copy 
00313   // of this instance.  The pointer returned by this function must
00314   // be deleted externally.
00315   virtual LatticeNavigator* clone() const;
00316 
00317   // Function which checks the internal data of this class for correct
00318   // dimensionality and consistant values. 
00319   // Returns True if everything is fine otherwise returns False
00320   virtual Bool ok() const;
00321 
00322   // Calculate the cache size (in tiles) for this type of access to a lattice
00323   // in the given row of the tiled hypercube.
00324   virtual uInt calcCacheSize (const IPosition& cubeShape,
00325                               const IPosition& tileShape,
00326                               uInt maxCacheSize, uInt bucketSize) const;
00327 
00328 private:
00329   // Prevent the default constructor from being used.
00330   TiledLineStepper();
00331 
00332 
00333   IPosition itsBlc;              //# Bottom Left Corner
00334   IPosition itsTrc;              //# Top Right Corner
00335   IPosition itsInc;              //# Increment
00336   LatticeIndexer itsSubSection;  //# The current subsection
00337   LatticeIndexer itsIndexer;     //# For moving within a tile
00338   LatticeIndexer itsTiler;       //# For moving between tiles
00339   IPosition itsIndexerCursorPos; //# The current position of the iterator.
00340   IPosition itsTilerCursorPos;   //# The current position of the iterator.
00341   IPosition itsCursorShape;      //# The shape of the cursor for itsIndexer
00342   IPosition itsTileShape;        //# The tile shape (= itsTiler cursor shape)
00343   IPosition itsAxisPath;         //# Path for traversing
00344   uInt itsNsteps;                //# The number of iterator steps taken so far; 
00345   uInt itsAxis;                  //# The axis containing the data vector
00346   Bool itsEnd;                   //# Is the cursor beyond the end?
00347   Bool itsStart;                 //# Is the cursor at the beginning?
00348 };
00349 
00350 
00351 
00352 } //# NAMESPACE CASA - END
00353 
00354 #endif