// -*- C++ -*- /*************************************************************************** * * The IPPL Framework * * * Visit http://people.web.psi.ch/adelmann/ for more details * ***************************************************************************/ #ifndef SINDEX_H #define SINDEX_H // include files #include "Index/NDIndex.h" #include "Index/SOffset.h" #include "Index/LSIndex.h" #include "FieldLayout/FieldLayoutUser.h" #include "Utility/Inform.h" #include #include #include // forward declarations template class FieldLayout; template class SIndex; template class IndexedSIndex; template std::ostream& operator<<(std::ostream&, const SIndex&); /*********************************************************************** * * SIndex represents a set of single-point indices for a Field, which * are used to implement sparse-index operations. The user creates an * SIndex object through a where statement or by just adding individual * points, and then performs operations using the SIndex object just as * is done with a regular Index object. In that case, operations are * only performed on those elements of the LHS which are in the SIndex * list. Stencil operations are represented by using SOffset objects * to indicate offsets from the SIndex indices. * * Initially, an SIndex object is empty; points must be added to it by * calling addIndex. An SIndex has an offset, set (or changed) by * calling setOffset(const SOffset&). Only indices for local vnodes are * stored in this object; adding other points will return an error flag. * * Constructing an SIndex requires a FieldLayout object, since SIndex * needs to know the range of index values for which is can store points, * and the location of vnodes. * * A note about offsets: the offset factor is used primarily to make * it possible to specify index offsets in expressions for stenciling * purposes. The method for adding an offset to an SIndex is via the * + or - operators, e.g., A[si] = B[si + SOffset(1,-1)], or via * the () operator, e.g., A[si] = B[si(1,-1)] (which means the same as * above). Otherwise, the user should not specify an offset, and the * operations such as union, intersection, etc. implicitly assume that * the offset is zero for the LHS and the RHS. * ***********************************************************************/ template class SIndex : public FieldLayoutUser { public: //# public typedefs typedef std::vector< std::shared_ptr > > container_t; typedef unsigned int size_type; typedef typename container_t::iterator iterator_iv; typedef typename container_t::const_iterator const_iterator_iv; typedef typename container_t::size_type size_type_iv; typedef typename LSIndex::iterator iterator_indx; typedef typename LSIndex::const_iterator const_iterator_indx; // default constructor: this requires the user to call 'initialize' // before any other actions are carried out with this SIndex SIndex(); // constructor: requires a FieldLayout SIndex(FieldLayout&); // copy constructor SIndex(const SIndex&); // destructor: frees memory used to store indices, and check out from Layout virtual ~SIndex(); // initialize the object, if it was constructed with the default // constructor void initialize(FieldLayout&); // report if we need initialization bool needInitialize() const { return (Layout == 0); } // a templated operator= taking a PETE expression template SIndex& operator=(const PETE_Expr& rhs) { assign(*this, rhs); return *this; } // assignment operator, with another SIndex or SOffset object. If an // NDIndex object is given, all the points in the NDIndex are used. SIndex& operator=(const SIndex&); SIndex& operator=(const SOffset&); SIndex& operator=(const NDIndex&); // intersection operator, with another SIndex or SOffset object. // intersected SIndexes must have the same layout; intersection with an // SOffset will leave this object with at most one point SIndex& operator&=(const SIndex&); SIndex& operator&=(const SOffset&); SIndex& operator&=(const NDIndex&); // union operator, with another SIndex or SOffset object. This will // append the point if it is not already present. SIndex& operator|=(const SIndex&); SIndex& operator|=(const SOffset&); SIndex& operator|=(const NDIndex&); // add a new index point, specified as an Offset or as a single-point NDIndex // return success (this can fail if the point is outsize the field's domain) bool addIndex(const SOffset&); bool addIndex(iterator_iv&, const SOffset&); void addIndex(const NDIndex&); // remove an index point, specified as an Offset or as a single-point NDIndex // return success (this can fail if the point is not on this node) bool removeIndex(const SOffset&); bool removeIndex(iterator_iv&, const SOffset&); void removeIndex(const NDIndex&); // reserve storage space equal to the given fraction of the size of // each vnode. if fraction=1.0, reserve storage for the entire vnode. void reserve(double = 1.0); // clear out the existing indices void clear(); // get the offset for this sparse index. You can change the offset by // retrieving it this way and then adding to it. SOffset& getOffset() { return Offset; } const SOffset& getOffset() const { return Offset; } // get the FieldLayout we are using FieldLayout& getFieldLayout() const { return *Layout; }; // change to using a new layout. void setFieldLayout(FieldLayout&); // get or change the 'bounding box' domain of this SIndex const NDIndex &getDomain() const { return BoundingBox; } void setDomain(const NDIndex &ndi) { BoundingBox = ndi; } // // SIndex <--> SOffset operations // // add or subtract a given offset // SIndex& operator+=(const SOffset& so) {Offset+=so;return *this;} // SIndex& operator-=(const SOffset& so) {Offset-=so;return *this;} friend SIndex operator+(const SIndex& si, const SOffset& so) { return SIndex(si, so); } friend SIndex operator+(const SOffset &so, const SIndex& si) { return SIndex(si, so); } friend SIndex operator+(const SIndex& si, const int *so) { return SIndex(si, so); } friend SIndex operator+(const int *so, const SIndex& si) { return SIndex(si, so); } friend SIndex operator-(const SIndex& si, const SOffset& so) { return SIndex(si, -so); } friend SIndex operator-(const SOffset &so, const SIndex& si) { return SIndex(si, -so); } friend SIndex operator-(const SIndex& si, const int *so) { return SIndex(si, -SOffset(so)); } friend SIndex operator-(const int *so, const SIndex& si) { return SIndex(si, -SOffset(so)); } // () operators which make a copy of this SIndex with an extra offset. // These are functionally identical to the operator+, but provide a // nicer syntax. That is, si(1,1) means si + SOffset(1,1) SIndex operator()(int); SIndex operator()(int,int); SIndex operator()(int,int,int); SIndex operator()(int,int,int,int); SIndex operator()(int,int,int,int,int); SIndex operator()(int,int,int,int,int,int); SIndex operator()(const SOffset&); SIndex operator()(const int *); // operator[], which is used with Index or NDIndex objects to further // subset the data. This will only work if the dimension of the Index // arguments + Brackets is <= Dim. Otherwise, too many dimensions worth // of Index objects are being applied IndexedSIndex operator[](const Index &); template IndexedSIndex operator[](const NDIndex &ndi) { CTAssert(Dim >= Dim2); NDIndex dom; for (unsigned int i=0; i < Dim2; ++i) dom[i] = ndi[i]; return IndexedSIndex(*this, dom); } // // SIndex <--> NDIndex operations // // convert from the given SOffset value to an NDIndex, with offset added void toNDIndex(const SOffset&, NDIndex&); // // container methods // // return begin/end iterators for the LSIndex container iterator_iv begin_iv() { return IndexList.begin(); } iterator_iv end_iv() { return IndexList.end(); } const_iterator_iv begin_iv() const { return IndexList.begin(); } const_iterator_iv end_iv() const { return IndexList.end(); } size_type_iv size_iv() const { return IndexList.size(); } // return the total size, which is the sum of the individual sizes size_type_iv size() const; // return whether the given point is contained here bool hasIndex(const SOffset&) const; // // virtual functions for FieldLayoutUser's // // Repartition onto a new layout virtual void Repartition(UserList *); // Tell this object that an object is being deleted virtual void notifyUserOfDelete(UserList *); // // I/O // // print out debugging info void printDebug(Inform&) const; private: // our FieldLayout, indicating the extent and distrib. of index space FieldLayout* Layout; // our current offset; by default, this is zero. We keep a special flag // to indicate whether it is zero or not. SOffset Offset; // our list of indices for each local vnode container_t IndexList; // our 'bounding box', which is the region that is or should be iterated // over to determine what points are in this sparse index list. By default, // this is the domain of the FieldLayout NDIndex BoundingBox; // a special constructor, taking another SIndex and an Offset. This // version is almost like a copy constructor, except that the given Offset // is added in to the offset from the copied SIndex. SIndex(const SIndex&, const SOffset&); SIndex(const SIndex&, const int *); // set up our internal data structures from the constructor. Assumes // the Layout and Offset have been set. void setup(); }; #include "Index/SIndex.hpp" #endif // SINDEX_H /*************************************************************************** * $RCSfile: SIndex.h,v $ $Author: adelmann $ * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $ * IPPL_VERSION_ID: $Id: SIndex.h,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $ ***************************************************************************/