casa
$Rev:20696$
|
00001 //# LatticeStepper.h: provides 'natural' traversal, by cursor shape 00002 //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001 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: LatticeStepper.h 20652 2009-07-06 05:04:32Z Malte.Marquarding $ 00027 00028 #ifndef LATTICES_LATTICESTEPPER_H 00029 #define LATTICES_LATTICESTEPPER_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 // Traverse a Lattice by cursor shape 00042 // </summary> 00043 00044 // <use visibility=export> 00045 00046 // <reviewed reviewer="Peter Barnes" date="1999/10/30" tests="tLatticeStepper.cc"> 00047 // </reviewed> 00048 00049 // <prerequisite> 00050 // <li> <linkto class=LatticeNavigator> LatticeNavigator </linkto> 00051 // </prerequisite> 00052 00053 // <etymology> 00054 // LatticeStepper is so-called because it performs the calculations 00055 // necessary to step through a Lattice. The next position is always one 00056 // simple step forward from the current position. The step-size is 00057 // calculated directly from the size of the LatticeIterator's cursor or 00058 // window. 00059 // </etymology> 00060 00061 // <synopsis> 00062 // When you wish to traverse a Lattice (say, a PagedArray or an Image) you 00063 // will usually create a LatticeIterator. Once created, you must attach a 00064 // LatticeNavigator to the iterator. A LatticeStepper, is a concrete class 00065 // derived from the abstract LatticeNavigator that allows you to move 00066 // sequentially through the Lattice. 00067 // <p> 00068 // In constructing a LatticeStepper, you specify the Lattice shape and the 00069 // shape of the "cursor" used to step through the data. The cursor position 00070 // can be incremented or decremented to retrieve the next portion of the 00071 // Lattice. 00072 // The specified cursor shape can (and often will) have fewer dimensions 00073 // that the Lattice itself. For example if we have a 4-dimensional Lattice 00074 // with <src>latticeShape = IPosition(4,64,64,4,16)</src>, then specifying a 00075 // cursor of <src>cursorShape = IPosition(1,64)</src>, will step through the 00076 // hypercube row by row. When the cursor shape has fewer dimensions than the 00077 // Lattice degenerate dimensions are added to the end of the cursor so that 00078 // in the above example the specified cursor is assumed to mean 00079 // <src>cursorShape = IPosition(4,64,1,1,1)</src>. To access the data 00080 // spectrum by spectrum (assuming the last axis is the spectral axis), you 00081 // must use a 1-dimensional cursor of <src>IPosition(4,1,1,1,16)</src>. The 00082 // <src>cursorShape</src> function always returns a shape with as many 00083 // dimensions as the underlying Lattice. 00084 // <p> 00085 // It is an error (and an exception will be thrown) if the cursor has more 00086 // dimensions than the Lattice or if it is larger on any axis than the 00087 // Lattice shape. 00088 // <br> 00089 // Also the cursor shape on all axes must be less than or equal to the Lattice 00090 // shape on that axis. Otherwise an exception will be thrown. 00091 // <p> 00092 // In principle cursor axes with length 1 are degenerate axes. They 00093 // are removed from the lattice cursor if the 00094 // <linkto class=LatticeIterator>LatticeIterator</linkto> cursor is accessed 00095 // using e.g. the <src>matrixCursor</src> function. 00096 // Using a special LatticeStepper constructor it is, however, possible 00097 // to specify which cursor axes with length 1 have to be treated as 00098 // normal axes. In that way one can be sure that a cursor is, for 00099 // example, always 2D, even if an axis happens to have length 1. 00100 // <srcblock> 00101 // IPosition latticeShape(4,20,16,1,4); 00102 // IPosition cursorAxes(2,1,2); 00103 // IPosition cursorShape(2,16,1); 00104 // IPosition axisPath; 00105 // LatticeStepper stepper(latticeShape, cursorShape, 00106 // cursorAxes, axisPath); 00107 // </srcblock> 00108 // This results in a cursor with shape [1,16,1,1]. The first and last 00109 // axis are degenerate, so the cursor can also be accessed using 00110 // <src>matrixCursor</src> (with shape [16,1]). 00111 // Note that the cursor shape could also be specified as [1,16,1,1]. 00112 // <p> 00113 // The "path" of the cursor through the Lattice can be controlled by 00114 // specifying an axisPath during construction of the class. This is an 00115 // IPosition which has exactly as many elements as the Lattice 00116 // dimension. Each element must contain an integer between 00117 // 0 -- Lattice_Dimension-1, and must be unique. For example, 00118 // <srcblock> 00119 // axisPath = IPosition(4,0,1,2,3) or 00120 // axisPath = IPosition(4,3,1,2,0) 00121 // </srcblock> 00122 // are valid but 00123 // <srcblock> 00124 // axisPath = IPosition(4,1,2,3,4) or 00125 // axisPath = IPosition(4,0,1,1,3) 00126 // </srcblock> 00127 // are not, given the latticeShape specified above. An exception is thrown 00128 // if the AxisPath is bad. 00129 // <br> 00130 // The "axis path" defines which axis will be iterated through fastest as 00131 // the cursor moves through the Lattice. With the above mentioned 00132 // 4-dimensional Lattice and a single element cursor 00133 // (<src>cursorShape=IPosition(4,1,1,1,1)</src>) setting an 00134 // <src>axisPath=IPosition(4,0,1,2,3)</src> will move the cursor through all 00135 // the columns, and then onto the next row, and again through all the 00136 // columns in the second row. Once all the rows in the first plane have 00137 // been exhausted the cursor will then iterate to the next plane, and 00138 // eventually to the next spectral channel. If, however, the axisPath was 00139 // <src>axisPath=IPosition(4,3,0,1,2)</src> then the cursor would iterate 00140 // through each spectral channel first, before moving onto the next column in 00141 // the first row. 00142 // <p> 00143 // The cursor never changes dimensionality as it traverses the Lattice. But it 00144 // may change shape if the cursor shape is not a factor of the Lattice 00145 // shape. A cursor shape is not a factor of the Lattice shape if the Lattice 00146 // shape is not an integer multiple of the cursor shape on all axes. 00147 // The integer multiplier need not to be the same for each axes. 00148 // For example, for a Lattice of shape [10,10,10] a cursor of shape [8,5,2] 00149 // is not a factor but one with a shape of [10,5,1] is. 00150 // <br> 00151 // When the cursor is not congruent with the Lattice moving the cursor through 00152 // the Lattice will sometimes result in part of the cursor hanging over the 00153 // edge of the Lattice. When this occurs the hangOver member function will 00154 // return True. What to do in these situtations is specified by the 00155 // hangOverPolicy enumerator. 00156 // <ol> 00157 // <li> 00158 // If the LatticeStepper::PAD option (the default) is used at construction time 00159 // the cursor shape does not change. The parts of the cursor that hang over the 00160 // edge of the Lattice are filled with a default value, usually zero, that is 00161 // defined by the particular LatticeIterator used. 00162 // <li> 00163 // If the LatticeStepper::RESIZE option is used at construction time the cursor 00164 // shape does change to a smaller value when near the edge of the Lattice so 00165 // that it is just big enough. For example with a Lattice shape of 10x10 and a 00166 // cursor of 8x8 the cursor shape will initally be 8x8, then resize to 2x8 on 00167 // the first step, then resize to 8x2 on the second step and finally resize to 00168 // 2x2. The hangover function will return True for the last three steps, even 00169 // though the cursor has resized. 00170 // </ol> 00171 // The portion of the Lattice that the cursor will traverse can be 00172 // restricted to a region defined by a top right corner, bottom left corner 00173 // and a step size. This is done using the <src>subSection</src> function, 00174 // which also resets the cursor position to the origin of the sub-Lattice. 00175 // The cursor shape will remain unchanged. It is no error when the cursor 00176 // shape exceeds the sub-Lattice shape (instead it is a hangover state). 00177 // <br> 00178 // If a sub-Lattice is defined then cursor positions relative 00179 // to the sub-Lattice origins can be obtained using the 00180 // <src>relativePosition</src> function rather than the 00181 // <src>position</src> function, which always returns positions relative to 00182 // the origin of the main Lattice. 00183 // <br> 00184 // To change the size of the sub-Lattice simply call the 00185 // <src>subSection</src> function again with a different trc, blc & 00186 // inc. This first clears the old sub-Lattice, then imposes the newly 00187 // specified one, and finally moves the cursor to the origin of the 00188 // new sub-Lattice. 00189 // </synopsis> 00190 00191 // <example> 00192 // This example is of a global function that will iterate through a 00193 // 4-dimensional Lattice. It is assumed that the axes are RA, Dec, Stokes & 00194 // Frequency, and it will calculate the average flux in the I polarization 00195 // on each frequency channel. Imagine it is passed a data set (ie. Lattice) 00196 // of size 256 x 256 x 4 x 1024. This corresponds to 1GByte of data. However 00197 // the iterator will page through this data using a cursor of size 256 x 256 00198 // (or 256kByte) and will only read (because of subsectioning) the relevant 00199 // quarter of the data set. It is usually a good idea to set up the axis 00200 // path as this is gives hints to data cache about which data to retrieve in 00201 // advance. 00202 // <srcblock> 00203 // void averageFluxByChannel(const Lattice<Float>& data) 00204 // { 00205 // // for convenience, get the shape into a local variable 00206 // IPosition latticeShape = data.shape(); 00207 // cout << "Data has shape: " << latticeShape << endl; 00208 // 00209 // // check that the data has 4 axes. 00210 // DebugAssert(latticeShape.nelements() == 4, AipsError); 00211 // 00212 // // specify the cursor, or window shape. Here the cursor is a matrix 00213 // // that is the shape of the first plane of our Lattice. 00214 // // For convenience, get the first two axis lengths into local vars 00215 // uInt nCols = latticeShape(0); 00216 // uInt nRows = latticeShape(1); 00217 // IPosition cursorShape(2, nCols, nRows); 00218 // 00219 // // construct a stepper, which needs to know the shape of the lattice 00220 // // and the shape of the iterator's cursor. By using cursorShape, which 00221 // // is directly determined by the lattice's shape, we can be sure 00222 // // that the cursor is a factor of the lattice, and thus that 00223 // // all elements will be picked up efficiently during the traversal. 00224 // // Because we will not be iterating through the stokes axis this axis 00225 // // is made the slowest moving one. 00226 // IPosition axisPath(4, 0, 1, 3, 2) 00227 // LatticeStepper stepper(latticeShape, cursorShape, axisPath); 00228 // 00229 // // Subsection the stepper so that it only iterates through the I 00230 // // Stokes parameter (assumed to be when the third axis is zero) 00231 // uInt nFreqs = latticeShape(3); 00232 // IPosition blc(4, 0, 0, 0, 0), trc(4, nCols-1, nRows-1, 0, nFreqs-1); 00233 // stepper.subSection(blc, trc); 00234 // 00235 // // construct the iterator. Since we only want to read the Data, 00236 // // use the read-only class, which disallows writing back to the cursor 00237 // // (and hence is more efficient). 00238 // RO_LatticeIterator<Float> iterator(data, stepper); 00239 // 00240 // Vector<Float> spectrum(nFreqs); 00241 // spectrum = 0.0; 00242 // uInt channel = 0; 00243 // for (iterator.reset(); !iterator.atEnd(); iterator++) { 00244 // const Matrix<Float>& cursor = iterator.matrixCursor(); 00245 // for (uInt col = 0; col < nCols; col++) { 00246 // for (uInt row = 0; row < nRows; row++) { 00247 // spectrum(channel) += cursor(col, row); 00248 // } 00249 // } 00250 // channel++; 00251 // } // for iterator 00252 // cout << "Average spectrum is: " 00253 // << spectrum / cursorShape.product() << endl; 00254 // } 00255 // </srcblock> 00256 // </example> 00257 00258 // <motivation> 00259 // Moving through a Lattice by equal sized chunks, and without regard 00260 // to the nature of the data, is a basic and common procedure. 00261 // </motivation> 00262 00263 //# <todo asof="1995/08/28"> 00264 //# </todo> 00265 00266 00267 class LatticeStepper: public LatticeNavigator 00268 { 00269 public: 00270 00271 // The hangOverPolicy enumerator is used in the constructors to indicate 00272 // what this class should do when the cursor shape hangs over the edge 00273 // of the Lattice. 00274 enum hangOverPolicy { 00275 // PAD is the default and means that the cursor size supplied by the user is 00276 // kept fixed. But if the cursor overhangs the Lattice the part that 00277 // overhangs is filled with a default value that is specified by the 00278 // Iterator. Currently the default value is zero. 00279 PAD, 00280 // RESIZE means that the cursor shape is adjusted whenever it approaches the 00281 // edges of the Lattice so that it is always the right size to include only 00282 // the parts of the Lattice that are available. The user specified cursor 00283 // shape now becomes the default and largest possible cursor shape. 00284 RESIZE}; 00285 00286 // The first argument is the shape of the Lattice to be iterated and the 00287 // second argument is the shape of the cursor. The cursor will increment 00288 // initially along first axis, then the second and then the third 00289 // (ie. axisPath = IPosition(ndim,0,1,2,...)) 00290 // The dimensionality of the cursorShape can be less than the 00291 // dimensionality of the lattice. It will be padded with 1s. 00292 // <br>The cursorShape axes with length > 1 are seen as the true cursor axes. 00293 // The other axes are degenerated and are removed by the functions 00294 // <src>vectorCursor()</src>, etc., in class 00295 // <linkto class=RO_LatticeIterator>(RO_)LatticeIterator</linkto>. 00296 LatticeStepper (const IPosition& latticeShape, const IPosition& cursorShape, 00297 const uInt hangOverPolicy=PAD); 00298 00299 // Same as the above constructor except that the axis path is explicitly 00300 // specified. The axis path is described in the synopsis above. 00301 LatticeStepper (const IPosition& latticeShape, const IPosition& cursorShape, 00302 const IPosition& axisPath, const uInt hangOverPolicy=PAD); 00303 00304 // Same as the above constructor except that the cursor axes are 00305 // explicitly specified. This can be useful to avoid that cursor axes 00306 // with length=1 are treated as degenerated axes by the Iterator classes. 00307 // The following rules have to be obeyed: 00308 // <br>- <src>cursorAxes.nelements() <= latticeShape.nelements()</src> 00309 // <br>- <src>cursorShape.nelements() == latticeShape.nelements()</src> 00310 // <br>or <src>cursorShape.nelements() == cursorAxes.nelements()</src> 00311 // The latter means that the cursorShape contains the axes mentioned in 00312 // cursorAxes. 00313 // <br>See also the example in the synopsis. 00314 LatticeStepper (const IPosition& latticeShape, const IPosition& cursorShape, 00315 const IPosition& cursorAxes, 00316 const IPosition& axisPath, const uInt hangOverPolicy=PAD); 00317 00318 // The copy constructor uses copy semantics. 00319 LatticeStepper (const LatticeStepper& other); 00320 00321 ~LatticeStepper(); 00322 00323 // The assignment operator uses copy semantics. 00324 LatticeStepper& operator= (const LatticeStepper& other); 00325 00326 // Increment operator (postfix version) - move the cursor 00327 // forward one step. Returns True if the cursor was moved. 00328 virtual Bool operator++(int); 00329 00330 // Decrement operator (postfix version) - move the cursor 00331 // backwards one step. Returns True if the cursor was moved. 00332 virtual Bool operator--(int); 00333 00334 // Function to move the cursor to the beginning of the (sub)-Lattice. Also 00335 // resets the number of steps (<src>nsteps</src> function) to zero. 00336 virtual void reset(); 00337 00338 // Function which returns "True" if the cursor is at the beginning of the 00339 // (sub)-Lattice, otherwise, returns "False" 00340 virtual Bool atStart() const; 00341 00342 // Function which returns "True" if an attempt has been made to increment 00343 // the cursor beyond the end of the (sub)-Lattice. 00344 virtual Bool atEnd() const; 00345 00346 // Function to return the number of steps (increments & decrements) taken 00347 // since construction (or since last reset). This is a running count of 00348 // all cursor movement (operator++ or operator--), even though 00349 // N-increments followed by N-decrements will ALWAYS leave the cursor in 00350 // the original position. 00351 virtual uInt nsteps() const; 00352 00353 // Functions which return the current position of the beginning of the 00354 // cursor. The <src>position</src> function is relative to the origin 00355 // in the main Lattice and the <src>relativePosition</src> function is 00356 // relative to the origin and increment used in the sub-Lattice (defined 00357 // using the <src>subSection</src> function). If no sub-Lattice is defined 00358 // the two functions return identical positions. 00359 // <group> 00360 virtual IPosition position() const; 00361 virtual IPosition relativePosition() const; 00362 // </group> 00363 00364 // Functions which return the current position of the end of the 00365 // cursor. The <src>endPosition</src> function is relative to the origin 00366 // in the main Lattice and the <src>relativeEndPosition</src> function 00367 // is relative to the origin and increment used in the sub-Lattice 00368 // (defined using the <src>subSection</src> function). If no sub-Lattice 00369 // is defined the two functions return identical positions. 00370 // <note role=caution> It returns the end position in the lattice and 00371 // does not take overhang into account. </note> 00372 // <group> 00373 virtual IPosition endPosition() const; 00374 virtual IPosition relativeEndPosition() const; 00375 // </group> 00376 00377 // Functions which return the shape of the Lattice being iterated 00378 // through. <src>latticeShape</src> always returns the shape of the main 00379 // Lattice while <src>subLatticeShape</src> returns the shape of any 00380 // sub-Lattice defined using the <src>subSection</src> function. 00381 // <group> 00382 virtual IPosition latticeShape() const; 00383 virtual IPosition subLatticeShape() const; 00384 // </group> 00385 00386 // Functions to change the cursor shape to a new one. They always reset 00387 // the cursor to the beginning of the Lattice (and reset the number of 00388 // steps to zero). 00389 // <group> 00390 void setCursorShape (const IPosition& cursorShape); 00391 void setCursorShape (const IPosition& cursorShape, 00392 const IPosition& cursorAxes); 00393 // </group> 00394 00395 // Function which returns the shape of the cursor. This always includes 00396 // all axes (ie. it includes degenerates axes) 00397 virtual IPosition cursorShape() const; 00398 00399 // Function which returns the axes of the cursor. 00400 virtual IPosition cursorAxes() const; 00401 00402 // Function which returns "True" if the increment/decrement operators have 00403 // moved the cursor position such that part of the cursor beginning or end 00404 // is hanging over the edge of the (sub)-Lattice. 00405 virtual Bool hangOver() const; 00406 00407 // Functions to specify a "section" of the Lattice to step over. A section 00408 // is defined in terms of the Bottom Left Corner (blc), Top Right Corner 00409 // (trc), and step size (inc), on ALL of its axes, including degenerate 00410 // axes. The step size defaults to one if not specified. 00411 // <group> 00412 virtual void subSection (const IPosition& blc, const IPosition& trc); 00413 virtual void subSection (const IPosition& blc, const IPosition& trc, 00414 const IPosition& inc); 00415 // </group> 00416 00417 // Return the bottom left hand corner (blc), top right corner (trc) or 00418 // step size (increment) used by the current sub-Lattice. If no 00419 // sub-Lattice has been defined (with the <src>subSection</src> function) 00420 // these functions return blc=0, trc=latticeShape-1, increment=1, ie. the 00421 // entire Lattice. 00422 // <group> 00423 virtual IPosition blc() const; 00424 virtual IPosition trc() const; 00425 virtual IPosition increment() const; 00426 // </group> 00427 00428 // Return the axis path. 00429 virtual const IPosition& axisPath() const; 00430 00431 // Function which returns a pointer to dynamic memory of an exact copy 00432 // of this instance. The pointer returned by this function must 00433 // be deleted externally. 00434 virtual LatticeNavigator* clone() const; 00435 00436 // Function which checks the internal data of this class for correct 00437 // dimensionality and consistant values. 00438 // Returns True if everything is fine otherwise returns False 00439 virtual Bool ok() const; 00440 00441 // Calculate the cache size (in tiles) for this type of access to a lattice 00442 // in the given row of the tiled hypercube. 00443 virtual uInt calcCacheSize (const IPosition& cubeShape, 00444 const IPosition& tileShape, 00445 uInt maxCacheSize, uInt bucketSize) const; 00446 00447 private: 00448 // Prevent the default constructor from being used. 00449 LatticeStepper(); 00450 // Pad the cursor to the right number of dimensions. 00451 void padCursor(); 00452 // Check if the cursor shape is a factor of the Lattice shape. 00453 Bool niceFit() const; 00454 00455 00456 LatticeIndexer itsIndexer;//# Knows about the (sub)-Lattice shape and how 00457 //# to traverse it. 00458 IPosition itsCursorAxes; //# the cursor axes 00459 IPosition itsCursorShape; //# The shape of the cursor 00460 IPosition itsCursorPos; //# The current position of the iterator. 00461 IPosition itsAxisPath; //# the heading to follow for the cursor 00462 uInt itsNsteps; //# the number of iterator steps taken thus far; 00463 //# set to 0 on reset () 00464 Bool itsEnd; //# is the cursor beyond the end? 00465 Bool itsStart; //# is the cursor at the beginning? 00466 Bool itsNiceFit; //# if the cursor shape is a sub-multiple of the 00467 //# Lattice shape then set this to True. Used to 00468 //# avoid needing to test for a cursor hanging 00469 //# over the edge of the lattice. 00470 Bool itsHangover; //# this data member is set by the increment and 00471 //# decrement operators if itsNiceFit == False. It 00472 //# is used to tell if the cursor "Hangs over" 00473 //# the edge of the lattice shape. 00474 uInt itsPolicy; //# what to do if the cursor does hang over 00475 }; 00476 00477 00478 00479 } //# NAMESPACE CASA - END 00480 00481 #endif