casacore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Lattice.h
Go to the documentation of this file.
1 //# Lattice.h: Lattice is an abstract base class for array-like classes
2 //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2003
3 //# Associated Universities, Inc. Washington DC, USA.
4 //#
5 //# This library is free software; you can redistribute it and/or modify it
6 //# under the terms of the GNU Library General Public License as published by
7 //# the Free Software Foundation; either version 2 of the License, or (at your
8 //# option) any later version.
9 //#
10 //# This library is distributed in the hope that it will be useful, but WITHOUT
11 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 //# License for more details.
14 //#
15 //# You should have received a copy of the GNU Library General Public License
16 //# along with this library; if not, write to the Free Software Foundation,
17 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 //#
19 //# Correspondence concerning AIPS++ should be addressed as follows:
20 //# Internet email: aips2-request@nrao.edu.
21 //# Postal address: AIPS++ Project Office
22 //# National Radio Astronomy Observatory
23 //# 520 Edgemont Road
24 //# Charlottesville, VA 22903-2475 USA
25 //#
26 //# $Id$
27 
28 #ifndef LATTICES_LATTICE_H
29 #define LATTICES_LATTICE_H
30 
31 
32 //# Includes
33 #include <casacore/casa/aips.h>
37 
38 namespace casacore { //# NAMESPACE CASACORE - BEGIN
39 
40 //# Forward Declarations
41 class IPosition;
42 class LatticeNavigator;
43 template <class T> class COWPtr;
44 template <class Domain, class Range> class Functional;
45 template <class T> class LatticeIterInterface;
46 
47 
48 // <summary>
49 // A templated, abstract base class for array-like objects.
50 // </summary>
51 
52 // <use visibility=export>
53 
54 // <reviewed reviewer="Peter Barnes" date="1999/10/30" tests="tArrayLattice.cc" demos="dLattice.cc">
55 // </reviewed>
56 
57 // <prerequisite>
58 // <li> <linkto class="IPosition"> IPosition </linkto>
59 // <li> <linkto class="Array"> Array </linkto>
60 // <li> <linkto class="LatticeBase"> LatticeBase </linkto>
61 // <li> Abstract Base class Inheritance - try "Advanced C++" by James
62 // O. Coplien, Ch. 5.
63 // </prerequisite>
64 
65 // <etymology>
66 // Lattice: "A regular, periodic configuration of points, particles,
67 // or objects, throughout an area of a space..." (American Heritage Directory)
68 // This definition matches our own: an n-dimensional arrangement of items,
69 // on regular orthogonal axes.
70 // </etymology>
71 
72 // <synopsis>
73 // This pure abstract base class defines the operations which may be performed
74 // on any concrete class derived from it. It has only a few non-pure virtual
75 // member functions.
76 // The fundamental contribution of this class, therefore, is that it
77 // defines the operations derived classes must provide:
78 // <ul>
79 // <li> how to extract a "slice" (or sub-array, or subsection) from
80 // a Lattice.
81 // <li> how to copy a slice in.
82 // <li> how to get and put a single element
83 // <li> how to apply a function to all elements
84 // <li> various shape related functions.
85 // </ul>
86 // The base class <linkto class=LatticeBase>LatticeBase</linkto> contains
87 // several functions not dependent on the template parameter.
88 // <note role=tip> Lattices always have a zero origin. </note>
89 // </synopsis>
90 
91 // <example>
92 // Because Lattice is an abstract base class, an actual instance of this
93 // class cannot be constructed. However the interface it defines can be used
94 // inside a function. This is always recommended as it allows functions
95 // which have Lattices as arguments to work for any derived class.
96 // <p>
97 // I will give a few examples here and then refer the reader to the
98 // <linkto class="ArrayLattice">ArrayLattice</linkto> class (a memory resident
99 // Lattice) and the <linkto class="PagedArray">PagedArray</linkto> class (a
100 // disk based Lattice) which contain further examples with concrete
101 // classes (rather than an abstract one). All the examples shown below are used
102 // in the <src>dLattice.cc</src> demo program.
103 //
104 // <h4>Example 1:</h4>
105 // This example calculates the mean of the Lattice. Because Lattices can be too
106 // large to fit into physical memory it is not good enough to simply use
107 // <src>getSlice</src> to read all the elements into an Array. Instead the
108 // Lattice is accessed in chunks which can fit into memory (the size is
109 // determined by the <src>advisedMaxPixels</src> and <src>niceCursorShape</src>
110 // functions). The <src>LatticeIterator::cursor()</src> function then returns
111 // each of these chunks as an Array and the standard Array based functions are
112 // used to calculate the mean on each of these chunks. Functions like this one
113 // are the recommended way to access Lattices as the
114 // <linkto class="LatticeIterator">LatticeIterator</linkto> will correctly
115 // setup any required caches.
116 //
117 // <srcblock>
118 // Complex latMean(const Lattice<Complex>& lat) {
119 // const uInt cursorSize = lat.advisedMaxPixels();
120 // const IPosition cursorShape = lat.niceCursorShape(cursorSize);
121 // const IPosition latticeShape = lat.shape();
122 // Complex currentSum = 0.0f;
123 // size_t nPixels = 0u;
124 // RO_LatticeIterator<Complex> iter(lat,
125 // LatticeStepper(latticeShape, cursorShape));
126 // for (iter.reset(); !iter.atEnd(); iter++){
127 // currentSum += sum(iter.cursor());
128 // nPixels += iter.cursor().nelements();
129 // }
130 // return currentSum/nPixels;
131 // }
132 // </srcblock>
133 //
134 // <h4>Example 2:</h4>
135 // Sometimes it will be neccesary to access slices of a Lattice in a nearly
136 // random way. Often this can be done using the subSection commands in the
137 // <linkto class="LatticeStepper">LatticeStepper</linkto> class. But it is also
138 // possible to use the getSlice and putSlice functions. The following example
139 // does a two-dimensional Real to Complex Fourier transform. This example is
140 // restricted to four-dimensional Arrays (unlike the previous example) and does
141 // not set up any caches (caching is currently only used with PagedArrays). So
142 // only use getSlice and putSlice when things cannot be done using
143 // LatticeIterators.
144 //
145 // <srcblock>
146 // void FFT2DReal2Complex(Lattice<Complex>& result,
147 // const Lattice<Float>& input){
148 // AlwaysAssert(input.ndim() == 4, AipsError);
149 // const IPosition shape = input.shape();
150 // const uInt nx = shape(0);
151 // AlwaysAssert (nx > 1, AipsError);
152 // const uInt ny = shape(1);
153 // AlwaysAssert (ny > 1, AipsError);
154 // const uInt npol = shape(2);
155 // const uInt nchan = shape(3);
156 // const IPosition resultShape = result.shape();
157 // AlwaysAssert(resultShape.nelements() == 4, AipsError);
158 // AlwaysAssert(resultShape(3) == nchan, AipsError);
159 // AlwaysAssert(resultShape(2) == npol, AipsError);
160 // AlwaysAssert(resultShape(1) == ny, AipsError);
161 // AlwaysAssert(resultShape(0) == nx/2 + 1, AipsError);
162 //
163 // const IPosition inputSliceShape(4,nx,ny,1,1);
164 // const IPosition resultSliceShape(4,nx/2+1,ny,1,1);
165 // COWPtr<Array<Float> >
166 // inputArrPtr(new Array<Float>(inputSliceShape.nonDegenerate()));
167 // Array<Complex> resultArray(resultSliceShape.nonDegenerate());
168 // FFTServer<Float, Complex> FFT2D(inputSliceShape.nonDegenerate());
169 //
170 // IPosition start(4,0);
171 // Bool isARef;
172 // for (uInt c = 0; c < nchan; c++){
173 // for (uInt p = 0; p < npol; p++){
174 // isARef = input.getSlice(inputArrPtr,
175 // Slicer(start,inputSliceShape), True);
176 // FFT2D.fft(resultArray, *inputArrPtr);
177 // result.putSlice(resultArray, start);
178 // start(2) += 1;
179 // }
180 // start(2) = 0;
181 // start(3) += 1;
182 // }
183 // }
184 // </srcblock>
185 // Note that the <linkto class=LatticeFFT>LatticeFFT</linkto> class
186 // offers a nice way to do lattice based FFTs.
187 //
188 // <h4>Example 3:</h4>
189 // Occasionally you may want to access a few elements of a Lattice without
190 // all the difficulty involved in setting up Iterators or calling getSlice
191 // and putSlice. This is demonstrated in the example below.
192 // Setting a single element can be done with the <src>putAt</src> function,
193 // while getting a single element can be done with the parenthesis operator.
194 // Using these functions to access many elements of a Lattice is not
195 // recommended as this is the slowest access method.
196 //
197 // In this example an ideal point spread function will be inserted into an
198 // empty Lattice. As with the previous examples all the action occurs
199 // inside a function because Lattice is an interface (abstract) class.
200 //
201 // <srcblock>
202 // void makePsf(Lattice<Float>& psf) {
203 // const IPosition centrePos = psf.shape()/2;
204 // psf.set(0.0f); // this sets all the elements to zero
205 // // As it uses a LatticeIterator it is efficient
206 // psf.putAt (1, centrePos); // This sets just the centre element to one
207 // AlwaysAssert(near(psf(centrePos), 1.0f, 1E-6), AipsError);
208 // AlwaysAssert(near(psf(centrePos*0), 0.0f, 1E-6), AipsError);
209 // }
210 // </srcblock>
211 // </example>
212 
213 // <motivation>
214 // Creating an abstract base class which provides a common interface between
215 // memory and disk based arrays has a number of advantages.
216 // <ul>
217 // <li> It allows functions common to all arrays to be written independent
218 // of the way the data is stored. This is illustrated in the three examples
219 // above.
220 // <li> It reduces the learning curve for new users who only have to become
221 // familiar with one interface (ie. Lattice) rather than distinct interfaces
222 // for different array types.
223 // </ul>
224 // </motivation>
225 
226 // <todo asof="1996/07/01">
227 // <li> Make PagedArray cache functions virtual in this base class.
228 // </todo>
229 
230 
231 template <class T> class Lattice : public LatticeBase
232 {
233 public:
234  // a virtual destructor is needed so that it will use the actual destructor
235  // in the derived class
236  virtual ~Lattice();
237 
238  // Make a copy of the derived object (reference semantics).
239  virtual Lattice<T>* clone() const = 0;
240 
241  // Get the data type of the lattice.
242  virtual DataType dataType() const;
243 
244  // Return the value of the single element located at the argument
245  // IPosition.
246  // <br> The default implementation uses getSlice.
247  // <group>
248  T operator() (const IPosition& where) const;
249  virtual T getAt (const IPosition& where) const;
250  // </group>
251 
252  // Put the value of a single element.
253  // <br> The default implementation uses putSlice.
254  virtual void putAt (const T& value, const IPosition& where);
255 
256  // Functions which extract an Array of values from a Lattice. All the
257  // IPosition arguments must have the same number of axes as the underlying
258  // Lattice, otherwise, an exception is thrown. <br>
259  // The parameters are:
260  // <ul>
261  // <li> buffer: a <src>COWPtr<Array<T>></src> or an
262  // <src>Array<T></src>. See example 2 above for an example.
263  // <li> start: The starting position (or Bottom Left Corner), within
264  // the Lattice, of the data to be extracted.
265  // <li> shape: The shape of the data to be extracted. This is not a
266  // position within the Lattice but the actual shape the buffer will
267  // have after this function is called. This argument added
268  // to the "start" argument should be the "Top Right Corner".
269  // <li> stride: The increment for each axis. A stride of
270  // one will return every data element, a stride of two will return
271  // every other element. The IPosition elements may be different for
272  // each respective axis. Thus, a stride of IPosition(3,1,2,3) says:
273  // fill the buffer with every element whose position has a first
274  // index between start(0) and start(0)+shape(0), a second index
275  // which is every other element between start(1) and
276  // (start(1)+shape(1))*2, and a third index of every third element
277  // between start(2) and (start(2)+shape(2))*3.
278  // <li> section: Another way of specifying the start, shape and stride
279  // <li> removeDegenerateAxes: a Bool which dictates whether to remove
280  // "empty" axis created in buffer. (e.g. extracting an n-dimensional
281  // from an (n+1)-dimensional will fill 'buffer' with an array that
282  // has a degenerate axis (i.e. one axis will have a length = 1.)
283  // Setting removeDegenerateAxes = True will return a buffer with
284  // a shape that doesn't reflect these superfluous axes.)
285  // </ul>
286  //
287  // The derived implementations of these functions return
288  // 'True' if "buffer" is a reference to Lattice data and 'False' if it
289  // is a copy.
290  // <group>
291  Bool get (COWPtr<Array<T> >& buffer,
292  Bool removeDegenerateAxes=False) const;
293  Bool getSlice (COWPtr<Array<T> >& buffer, const Slicer& section,
294  Bool removeDegenerateAxes=False) const;
295  Bool getSlice (COWPtr<Array<T> >& buffer, const IPosition& start,
296  const IPosition& shape,
297  Bool removeDegenerateAxes=False) const;
298  Bool getSlice (COWPtr<Array<T> >& buffer, const IPosition& start,
299  const IPosition& shape, const IPosition& stride,
300  Bool removeDegenerateAxes=False) const;
301  Bool get (Array<T>& buffer,
302  Bool removeDegenerateAxes=False);
303  Bool getSlice (Array<T>& buffer, const Slicer& section,
304  Bool removeDegenerateAxes=False);
305  Bool getSlice (Array<T>& buffer, const IPosition& start,
306  const IPosition& shape,
307  Bool removeDegenerateAxes=False);
308  Bool getSlice (Array<T>& buffer, const IPosition& start,
309  const IPosition& shape, const IPosition& stride,
310  Bool removeDegenerateAxes=False);
311  Array<T> get (Bool removeDegenerateAxes=False) const;
312  Array<T> getSlice (const Slicer& section,
313  Bool removeDegenerateAxes=False) const;
314  Array<T> getSlice (const IPosition& start,
315  const IPosition& shape,
316  Bool removeDegenerateAxes=False) const;
317  Array<T> getSlice (const IPosition& start,
318  const IPosition& shape, const IPosition& stride,
319  Bool removeDegenerateAxes=False) const;
320  // </group>
321 
322  // A function which places an Array of values within this instance of the
323  // Lattice at the location specified by the IPosition "where", incrementing
324  // by "stride". All of the IPosition arguments must be of the same
325  // dimensionality as the Lattice. The sourceBuffer array may (and probably
326  // will) have less axes than the Lattice. The stride defaults to one if
327  // not specified.
328  // <group>
329  void putSlice (const Array<T>& sourceBuffer, const IPosition& where,
330  const IPosition& stride)
331  { doPutSlice (sourceBuffer, where, stride); }
332  void putSlice (const Array<T>& sourceBuffer, const IPosition& where);
333  void put (const Array<T>& sourceBuffer);
334 
335  // </group>
336 
337  // Set all elements in the Lattice to the given value.
338  virtual void set (const T& value);
339 
340  // Replace every element, x, of the Lattice with the result of f(x). You
341  // must pass in the address of the function -- so the function must be
342  // declared and defined in the scope of your program. All versions of
343  // apply require a function that accepts a single argument of type T (the
344  // Lattice template type) and return a result of the same type. The first
345  // apply expects a function with an argument passed by value; the second
346  // expects the argument to be passed by const reference; the third
347  // requires an instance of the class <src>Functional<T,T></src>. The
348  // first form ought to run faster for the built-in types, which may be an
349  // issue for large Lattices stored in memory, where disk access is not an
350  // issue.
351  // <group>
352  virtual void apply (T (*function)(T));
353  virtual void apply (T (*function)(const T&));
354  virtual void apply (const Functional<T,T>& function);
355  // </group>
356 
357  // Add, subtract, multiple, or divide by another Lattice.
358  // The other Lattice can be a scalar (e.g. the result of LatticeExpr).
359  // Possible masks are not taken into account.
360  // <group>
361  void operator+= (const Lattice<T>& other)
362  { handleMath (other, 0); }
363  void operator-= (const Lattice<T>& other)
364  { handleMath (other, 1); }
365  void operator*= (const Lattice<T>& other)
366  { handleMath (other, 2); }
367  void operator/= (const Lattice<T>& other)
368  { handleMath (other, 3); }
369  // </group>
370 
371  // Copy the data from the given lattice to this one.
372  // The default implementation uses function <src>copyDataTo</src>.
373  virtual void copyData (const Lattice<T>& from);
374 
375  // Copy the data from this lattice to the given lattice.
376  // The default implementation only copies data (thus no mask, etc.).
377  virtual void copyDataTo (Lattice<T>& to) const;
378 
379  // This function returns the advised maximum number of pixels to
380  // include in the cursor of an iterator. The default implementation
381  // returns a number that is a power of two and includes enough pixels to
382  // consume between 4 and 8 MBytes of memory.
383  virtual uInt advisedMaxPixels() const;
384 
385  // These functions are used by the LatticeIterator class to generate an
386  // iterator of the correct type for a specified Lattice. Not recommended
387  // for general use.
388  // <br>The default implementation creates a LatticeIterInterface object.
389  virtual LatticeIterInterface<T>* makeIter (const LatticeNavigator& navigator,
390  Bool useRef) const;
391 
392  // The functions (in the derived classes) doing the actual work.
393  // These functions are public, so they can be used internally in the
394  // various Lattice classes, which is especially useful for doGetSlice.
395  // <br>However, doGetSlice does not call Slicer::inferShapeFromSource
396  // to fill in possible unspecified section values. Therefore one
397  // should normally use one of the get(Slice) functions. doGetSlice
398  // should be used with care and only when performance is an issue.
399  // <group>
400  virtual Bool doGetSlice (Array<T>& buffer, const Slicer& section) = 0;
401  virtual void doPutSlice (const Array<T>& buffer, const IPosition& where,
402  const IPosition& stride) = 0;
403  // </group>
404 
405 protected:
406  // Define default constructor to satisfy compiler.
407  Lattice() {};
408 
409  // Handle the Math operators (+=, -=, *=, /=).
410  // They work similarly to copyData(To).
411  // However, they are not defined for Bool types, thus specialized below.
412  // <group>
413  virtual void handleMath (const Lattice<T>& from, int oper);
414  virtual void handleMathTo (Lattice<T>& to, int oper) const;
415  // </group>
416 
417  // Copy constructor and assignment can only be used by derived classes.
418  // <group>
420  : LatticeBase() {}
422  { return *this; }
423  // </group>
424 };
425 
426 
427 template<> inline
429  { throwBoolMath(); }
430 
431 //# Declare extern templates for often used types.
432  extern template class Lattice<Float>;
433  extern template class Lattice<Complex>;
434 
435 
436 } //# NAMESPACE CASACORE - END
437 
438 //# There is a problem in including Lattice.tcc, because it needs
439 //# LatticeIterator.h which in its turn includes Lattice.h again.
440 //# So in a source file including LatticeIterator.h, Lattice::set fails
441 //# to compile, because the LatticeIterator declarations are not seen yet.
442 //# Therefore LatticeIterator.h is included here, while LatticeIterator.h
443 //# includes Lattice.tcc.
444 #ifndef CASACORE_NO_AUTO_TEMPLATES
446 #endif //# CASACORE_NO_AUTO_TEMPLATES
447 #endif
A Vector of integers, for indexing into Array&lt;T&gt; objects.
Definition: IPosition.h:118
void operator+=(const Lattice< T > &other)
Add, subtract, multiple, or divide by another Lattice.
Definition: Lattice.h:361
void operator*=(const Lattice< T > &other)
Definition: Lattice.h:365
Map a domain object into a range object via operator().
Definition: Functional.h:122
virtual void set(const T &value)
Set all elements in the Lattice to the given value.
void operator/=(const Lattice< T > &other)
Definition: Lattice.h:367
virtual void copyData(const Lattice< T > &from)
Copy the data from the given lattice to this one.
virtual ~Lattice()
a virtual destructor is needed so that it will use the actual destructor in the derived class ...
A non-templated, abstract base class for array-like objects.
Definition: LatticeBase.h:80
T operator()(const IPosition &where) const
Return the value of the single element located at the argument IPosition.
void putSlice(const Array< T > &sourceBuffer, const IPosition &where, const IPosition &stride)
A function which places an Array of values within this instance of the Lattice at the location specif...
Definition: Lattice.h:329
virtual LatticeIterInterface< T > * makeIter(const LatticeNavigator &navigator, Bool useRef) const
These functions are used by the LatticeIterator class to generate an iterator of the correct type for...
virtual void putAt(const T &value, const IPosition &where)
Put the value of a single element.
A base class for Lattice iterators.
Definition: ImageExpr.h:47
A templated, abstract base class for array-like objects.
Definition: Functional.h:37
virtual IPosition shape() const =0
Return the shape of the Lattice including all degenerate axes (ie.
virtual Lattice< T > * clone() const =0
Make a copy of the derived object (reference semantics).
void put(const Array< T > &sourceBuffer)
Lattice< T > & operator=(const Lattice< T > &)
Definition: Lattice.h:421
virtual void handleMath(const Lattice< T > &from, int oper)
Handle the Math operators (+=, -=, *=, /=).
virtual void copyDataTo(Lattice< T > &to) const
Copy the data from this lattice to the given lattice.
void operator-=(const Lattice< T > &other)
Definition: Lattice.h:363
virtual void handleMathTo(Lattice< T > &to, int oper) const
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
virtual Bool doGetSlice(Array< T > &buffer, const Slicer &section)=0
The functions (in the derived classes) doing the actual work.
const Bool False
Definition: aipstype.h:44
Bool getSlice(COWPtr< Array< T > > &buffer, const Slicer &section, Bool removeDegenerateAxes=False) const
virtual DataType dataType() const
Get the data type of the lattice.
Specify which elements to extract from an n-dimensional array.
Definition: Slicer.h:288
virtual T getAt(const IPosition &where) const
virtual uInt advisedMaxPixels() const
This function returns the advised maximum number of pixels to include in the cursor of an iterator...
virtual void apply(T(*function)(T))
Replace every element, x, of the Lattice with the result of f(x).
Lattice()
Define default constructor to satisfy compiler.
Definition: Lattice.h:407
virtual void doPutSlice(const Array< T > &buffer, const IPosition &where, const IPosition &stride)=0
Lattice(const Lattice< T > &)
Copy constructor and assignment can only be used by derived classes.
Definition: Lattice.h:419
LatticeExprNode value(const LatticeExprNode &expr)
This function returns the value of the expression without a mask.
unsigned int uInt
Definition: aipstype.h:51
Abstract base class to steer lattice iterators.