src/Particle/ParticleBase.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef PARTICLE_BASE_H
00012 #define PARTICLE_BASE_H
00013 
00014 /*
00015  * ParticleBase - Base class for all user-defined particle classes.
00016  *
00017  * ParticleBase is a container and manager for a set of particles.
00018  * The user must define a class derived from ParticleBase which describes
00019  * what specific data attributes the particle has (e.g., mass or charge).
00020  * Each attribute is an instance of a ParticleAttribute<T> class; ParticleBase
00021  * keeps a list of pointers to these attributes, and performs global
00022  * operations on them such as update, particle creation and destruction,
00023  * and inter-processor particle migration.
00024  *
00025  * ParticleBase is templated on the ParticleLayout mechanism for the particles.
00026  * This template parameter should be a class derived from ParticleLayout.
00027  * ParticleLayout-derived classes maintain the info on which particles are
00028  * located on which processor, and performs the specific communication
00029  * required between processors for the particles.  The ParticleLayout is
00030  * templated on the type and dimension of the atom position attribute, and
00031  * ParticleBase uses the same types for these items as the given
00032  * ParticleLayout.
00033  *
00034  * ParticleBase and all derived classes have the following common
00035  * characteristics:
00036  *     - The spatial positions of the N particles are stored in the
00037  *       ParticlePos_t variable R
00038  *     - The global index of the N particles are stored in the
00039  *       ParticleIndex_t variable ID
00040  *     - A pointer to an allocated layout class.  When you construct a
00041  *       ParticleBase, you must provide a layout instance, and ParticleBase
00042  *       will delete this instance when it (the ParticleBase) is deleted.
00043  *
00044  * To use this class, the user defines a derived class with the same
00045  * structure as in this example:
00046  *
00047  *   class UserParticles :
00048  *            public ParticleBase< ParticleSpatialLayout<double,2> > {
00049  *   public:
00050  *     // attributes for this class
00051  *     ParticleAttribute<double> rad;  // radius
00052  *     ParticlePos_t             vel;  // velocity, same storage type as R
00053  *
00054  *     // constructor: add attributes to base class
00055  *     UserParticles(ParticleSpatialLayout<double,2>* L) : ParticleBase(L) {
00056  *       addAttribute(rad);
00057  *       addAttribute(vel);
00058  *     }
00059  *   };
00060  *
00061  * This example defines a user class with 2D position and two extra
00062  * attributes: a radius rad (double), and a velocity vel (a 2D Vektor).
00063  *
00064  * After each 'time step' in a calculation, which is defined as a period
00065  * in which the particle positions may change enough to affect the global
00066  * layout, the user must call the 'update' routine, which will move
00067  * particles between processors, etc.  After the Nth call to update, a
00068  * load balancing routine will be called instead.  The user may set the
00069  * frequency of load balancing (N), or may supply a function to
00070  * determine if load balancing should be done or not.
00071  *
00072  * Each ParticleBase can contain zero or more 'ghost' particles, which are
00073  * copies of particle data collected from other nodes.  These ghost particles
00074  * have many of the same function calls as for the 'regular' particles, with
00075  * the word 'ghost' prepended.  They are not necessary; but may be used to
00076  * improve performance of some parallel algorithms (such as calculating
00077  * neighbor lists).  The actual determination of what ghost particles should
00078  * be stored in this object (if any) is done by the specific layout object.
00079  *
00080  * ParticleBase also contains information on the types of boundary conditions
00081  * to use.  ParticleBase contains a ParticleBConds object, which is an array
00082  * of particle boundary condition functions.  By default, these BC's are null,
00083  * so that nothing special happens at the boundary, but the user may set these
00084  * BC's by using the 'getBConds' method to access the BC container.  The BC's
00085  * will then be used at the next update.  In fact, the BC container is stored
00086  * within the ParticleLayout object, but the interface the user uses to access
00087  * it is via ParticleBase.
00088  *
00089  * You can create an uninitialized ParticleBase, by using the default
00090  * constructor.  In this case, it will not do any initialization of data
00091  * structures, etc., and will not contain a layout instance.  In order to use
00092  * the ParticleBase in any useful way in this case, use the 'initialize()'
00093  * method which takes as an argument the layout instance to use.
00094  */
00095 
00096 // include files
00097 #include "Particle/ParticleAttrib.h"
00098 #include "AppTypes/Vektor.h"
00099 #include "DataSource/DataSource.h"
00100 #include "DataSource/MakeDataSource.h"
00101 
00102 #ifdef IPPL_STDSTL
00103 #include <vector>
00104 #include <algorithm>  // Include algorithms
00105 #include <utility>
00106 using std::vector;
00107 using std::sort;
00108 using std::pair;
00109 #else
00110 #include <vector.h>
00111 #include <pair.h>
00112 #endif // IPPL_STDSTL
00113 
00114 #ifdef IPPL_USE_STANDARD_HEADERS
00115 #include <iostream>
00116 using namespace std;
00117 #else
00118 #include <iostream.h>
00119 #endif
00120 
00121 
00122 // forward declarations
00123 class Inform;
00124 class Message;
00125 template <class PLayout> class ParticleBase;
00126 template <class PLayout>
00127 ostream& operator<<(ostream&, const ParticleBase<PLayout>&);
00128 template <class T, unsigned D> class ParticleBConds;
00129 
00130 
00131 // ParticleBase class definition.  Template parameter is the specific
00132 // ParticleLayout-derived class which determines how the particles are
00133 // distributed among processors.
00134 template<class PLayout>
00135 class ParticleBase : public DataSource {
00136 
00137 public:
00138   // useful enums
00139   enum { Dim = PLayout::Dimension };
00140 
00141   // useful typedefs and enums
00142   typedef PLayout                           Layout_t;
00143   typedef typename PLayout::Position_t      Position_t;
00144   typedef typename PLayout::Index_t         Index_t;
00145   
00146   typedef typename PLayout::ParticlePos_t   ParticlePos_t;
00147   typedef typename PLayout::ParticleIndex_t ParticleIndex_t;
00148  
00149   typedef typename PLayout::pair_iterator   pair_iterator;
00150   typedef typename PLayout::pair_t          pair_t;
00151   typedef typename PLayout::UpdateFlags     UpdateFlags;
00152   typedef vector<ParticleAttribBase *>      attrib_container_t;
00153   typedef attrib_container_t::iterator      attrib_iterator;
00154   typedef ParticleAttribBase::SortList_t    SortList_t;
00155 
00156   // our position, and our global ID's
00157   ParticlePos_t   R;
00158   ParticleIndex_t ID;
00159 
00160 public:
00161   // constructor 1: no arguments, so create an uninitialized ParticleBase.
00162   // If this constructor is used, the user must call 'initialize' with
00163   // a layout object in order to use this.
00164   ParticleBase() : Layout(0) { }
00165 
00166   // constructor 2: arguments = layout to use.
00167   ParticleBase(PLayout *layout) : Layout(layout) { setup(); }
00168 
00169   // destructor - delete the layout if necessary
00170   ~ParticleBase() {
00171     if (Layout != 0)
00172       delete Layout;
00173   }
00174 
00175   //
00176   // Initialization methods
00177   //
00178 
00179   // For a ParticleBase that was created with the default constructor,
00180   // initialize performs the same actions as are done in the non-default
00181   // constructor.  If this object has already been initialized, it is
00182   // an error.  For initialize, you must supply a layout instance.
00183   void initialize(PLayout *);
00184 
00185 
00186   //
00187   // Accessor functions for this class
00188   //
00189 
00190   // return/change the total or local number of particles
00191   size_t getTotalNum() const { return TotalNum; }
00192   size_t getLocalNum() const { return LocalNum; }
00193   size_t getDestroyNum() const { return DestroyNum; }
00194   size_t getGhostNum() const { return GhostNum; }
00195   void setTotalNum(size_t n) { TotalNum = n; }
00196   void setLocalNum(size_t n) { LocalNum = n; }
00197 
00198   // get the layout manager
00199   PLayout& getLayout() { return *Layout; }
00200   const PLayout& getLayout() const { return *Layout; }
00201 
00202   // get or set the boundary conditions container
00203   ParticleBConds<Position_t,PLayout::Dimension>& getBConds() {
00204     return Layout->getBConds();
00205   }
00206   void setBConds(const ParticleBConds<Position_t,PLayout::Dimension>& bc) {
00207     Layout->setBConds(bc);
00208   }
00209 
00210   // Return a boolean value indicating if we are on a processor which can
00211   // be used for single-node particle creation and initialization
00212   bool singleInitNode() const;
00213 
00214   // get or set the flags used to indicate what to do during the update
00215   bool getUpdateFlag(UpdateFlags f) const {
00216     return getLayout().getUpdateFlag(f);
00217   }
00218   void setUpdateFlag(UpdateFlags f, bool val) {
00219     getLayout().setUpdateFlag(f, val);
00220   }
00221 
00222   //
00223   // attribute manipulation methods
00224   //
00225 
00226   // add a new attribute ... called by constructor of this and derived classes
00227   void addAttribute(ParticleAttribBase& pa) { AttribList.push_back(&pa); }
00228 
00229   // get a pointer to the base class for the Nth attribute
00230   ParticleAttribBase&
00231   getAttribute(attrib_container_t::size_type N) { return *(AttribList[N]); }
00232 
00233   // return the number of attributes in our list
00234   attrib_container_t::size_type
00235   numAttributes() const { return AttribList.size(); }
00236 
00237   // obtain the beginning and end iterators for our attribute list
00238   attrib_iterator begin() { return AttribList.begin(); }
00239   attrib_iterator end()   { return AttribList.end(); }
00240 
00241   // reset the particle ID's to be globally consecutive, 0 thru TotalNum-1.
00242   void resetID();
00243 
00244   //
00245   // Global operations on all attributes
00246   //
00247 
00248   // Update the particle object after a timestep.  This routine will change
00249   // our local, total, create particle counts properly.
00250   void update();
00251   void update(const ParticleAttrib<char>& canSwap);
00252 
00253   // create M new particles on this processor
00254   void create(size_t);
00255 
00256   // create np new particles globally, equally distributed among all processors
00257   void globalCreate(size_t np);
00258 
00259   // delete M particles, starting with the Ith particle.  If the last argument
00260   // is true, the destroy will be done immediately, otherwise the request
00261   // will be cached.
00262   void destroy(size_t, size_t, bool = false);
00263 
00264   // Put the data for M particles starting from local index I in a Message.
00265   // Return the number of particles put in the Message.
00266   size_t putMessage(Message&, size_t, size_t);
00267   // put the data for particles on a list into a Message, given list of indices
00268   // Return the number of particles put in the Message.
00269   size_t putMessage(Message&, const vector<size_t>&);
00270 
00271   // Retrieve particles from the given message and store them.
00272   // Return the number of particles retrieved.
00273   size_t getMessage(Message&);
00274 
00275   // retrieve particles from the given message and store them, also 
00276   // signaling we are creating the given number of particles.  Return the
00277   // number of particles created.
00278   size_t getMessageAndCreate(Message&);
00279 
00280   // Actually perform the delete atoms action for all the attributes; the
00281   // calls to destroy() only stored a list of what to do.  This actually
00282   // does it.  This should in most cases only be called by the layout manager.
00283   void performDestroy();
00284 
00285   // Apply the given sortlist to all the attributes.
00286   void sort(SortList_t &);
00287 
00288   //
00289   // Global operations on all ghost attributes ... generally, these should
00290   // only be used by the layout object
00291   //
00292 
00293   // Put the data for M particles starting from local index I in a Message.
00294   // Return the number of particles put in the Message.  This is for building
00295   // ghost particle interaction lists.
00296   size_t ghostPutMessage(Message&, size_t, size_t);
00297 
00298   // put the data for particles on a list into a Message, given list of indices
00299   // Return the number of particles put in the Message.  This is for building
00300   // ghost particle interaction lists.
00301   size_t ghostPutMessage(Message&, const vector<size_t>&);
00302 
00303   // Retrieve particles from the given message and sending node and store them.
00304   // Return the number of particles retrieved.
00305   size_t ghostGetMessage(Message&, int);
00306 
00307   // delete M ghost particles, starting with the Ith particle.  This is
00308   // always done immediately.
00309   void ghostDestroy(size_t, size_t);
00310 
00311   //
00312   // I/O
00313   //
00314 
00315   // print out debugging information
00316   void printDebug(Inform&);
00317 
00318 protected:
00319   // a virtual function which is called by this base class to get a
00320   // specific instance of DataSourceObject based on the type of data
00321   // and the connection method (the argument to the call).
00322   virtual DataSourceObject *createDataSourceObject(const char *nm,
00323                                                    DataConnect *dc, int tm) {
00324     return make_DataSourceObject(nm, dc, tm, *this);
00325   }
00326 
00327 private:
00328   // our layout object, which we delete in our destructor
00329   PLayout *Layout;
00330 
00331   // our list of attributes
00332   attrib_container_t AttribList;
00333 
00334   // our current number of total and local atoms, and
00335   // the number of particles we've deleted since the last update
00336   // also, the number of ghost particles
00337   size_t TotalNum;
00338   size_t LocalNum;
00339   size_t DestroyNum;
00340   size_t GhostNum;
00341 
00342   // unique particle ID number generation value
00343   unsigned NextID;
00344 
00345   // list of destroy events for the next update.  The data
00346   // is not actually destroyed until the update phase.
00347   // Each destroy is stored as a pair of unsigned ints, the particle
00348   // index I to start at and the number of particles M to destroy.
00349   vector< pair<size_t,size_t> > DestroyList;
00350 
00351   //
00352   // private methods
00353   //
00354 
00355   // set up this new object:  add attributes and check in to the layout
00356   void setup();
00357 
00358   // Return a new unique ID value for use by new particles.
00359   // The ID number = (i * numprocs) + myproc, i = 0, 1, 2, ...
00360   unsigned getNextID();
00361 };
00362 
00363 #include "Particle/ParticleBase.cpp"
00364 
00365 #endif // PARTICLE_BASE_H
00366 
00367 /***************************************************************************
00368  * $RCSfile: ParticleBase.h,v $   $Author: adelmann $
00369  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:28 $
00370  * IPPL_VERSION_ID: $Id: ParticleBase.h,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $ 
00371  ***************************************************************************/

Generated on Mon Jan 16 13:23:53 2006 for IPPL by  doxygen 1.4.6