OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
IpplParticleBase.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  *
7  * Visit http://people.web.psi.ch/adelmann/ for more details
8  *
9  ***************************************************************************/
10 
11 #ifndef PARTICLE_BASE_H
12 #define PARTICLE_BASE_H
13 
14 /*
15  * IpplParticleBase - Base class for all user-defined particle classes.
16  *
17  * IpplParticleBase is a container and manager for a set of particles.
18  * The user must define a class derived from IpplParticleBase which describes
19  * what specific data attributes the particle has (e.g., mass or charge).
20  * Each attribute is an instance of a ParticleAttribute<T> class; IpplParticleBase
21  * keeps a list of pointers to these attributes, and performs global
22  * operations on them such as update, particle creation and destruction,
23  * and inter-processor particle migration.
24  *
25  * IpplParticleBase is templated on the ParticleLayout mechanism for the particles.
26  * This template parameter should be a class derived from ParticleLayout.
27  * ParticleLayout-derived classes maintain the info on which particles are
28  * located on which processor, and performs the specific communication
29  * required between processors for the particles. The ParticleLayout is
30  * templated on the type and dimension of the atom position attribute, and
31  * IpplParticleBase uses the same types for these items as the given
32  * ParticleLayout.
33  *
34  * IpplParticleBase and all derived classes have the following common
35  * characteristics:
36  * - The spatial positions of the N particles are stored in the
37  * ParticlePos_t variable R
38  * - The global index of the N particles are stored in the
39  * ParticleIndex_t variable ID
40  * - A pointer to an allocated layout class. When you construct a
41  * IpplParticleBase, you must provide a layout instance, and IpplParticleBase
42  * will delete this instance when it (the IpplParticleBase) is deleted.
43  *
44  * To use this class, the user defines a derived class with the same
45  * structure as in this example:
46  *
47  * class UserParticles :
48  * public IpplParticleBase< ParticleSpatialLayout<double,2> > {
49  * public:
50  * // attributes for this class
51  * ParticleAttribute<double> rad; // radius
52  * ParticlePos_t vel; // velocity, same storage type as R
53  *
54  * // constructor: add attributes to base class
55  * UserParticles(ParticleSpatialLayout<double,2>* L) : IpplParticleBase(L) {
56  * addAttribute(rad);
57  * addAttribute(vel);
58  * }
59  * };
60  *
61  * This example defines a user class with 2D position and two extra
62  * attributes: a radius rad (double), and a velocity vel (a 2D Vektor).
63  *
64  * After each 'time step' in a calculation, which is defined as a period
65  * in which the particle positions may change enough to affect the global
66  * layout, the user must call the 'update' routine, which will move
67  * particles between processors, etc. After the Nth call to update, a
68  * load balancing routine will be called instead. The user may set the
69  * frequency of load balancing (N), or may supply a function to
70  * determine if load balancing should be done or not.
71  *
72  * Each IpplParticleBase can contain zero or more 'ghost' particles, which are
73  * copies of particle data collected from other nodes. These ghost particles
74  * have many of the same function calls as for the 'regular' particles, with
75  * the word 'ghost' prepended. They are not necessary; but may be used to
76  * improve performance of some parallel algorithms (such as calculating
77  * neighbor lists). The actual determination of what ghost particles should
78  * be stored in this object (if any) is done by the specific layout object.
79  *
80  * IpplParticleBase also contains information on the types of boundary conditions
81  * to use. IpplParticleBase contains a ParticleBConds object, which is an array
82  * of particle boundary condition functions. By default, these BC's are null,
83  * so that nothing special happens at the boundary, but the user may set these
84  * BC's by using the 'getBConds' method to access the BC container. The BC's
85  * will then be used at the next update. In fact, the BC container is stored
86  * within the ParticleLayout object, but the interface the user uses to access
87  * it is via IpplParticleBase.
88  *
89  * You can create an uninitialized IpplParticleBase, by using the default
90  * constructor. In this case, it will not do any initialization of data
91  * structures, etc., and will not contain a layout instance. In order to use
92  * the IpplParticleBase in any useful way in this case, use the 'initialize()'
93  * method which takes as an argument the layout instance to use.
94  */
95 
96 // include files
98 #include "AppTypes/Vektor.h"
99 #include "DataSource/DataSource.h"
101 #include "Message/Formatter.h"
102 #include <vector>
103 #include <algorithm> // Include algorithms
104 #include <utility>
105 #include <iostream>
106 
107 
108 // forward declarations
109 class Inform;
110 class Message;
111 template <class PLayout> class IpplParticleBase;
112 template <class PLayout>
113 std::ostream& operator<<(std::ostream&, const IpplParticleBase<PLayout>&);
114 template <class T, unsigned D> class ParticleBConds;
115 
116 
117 // IpplParticleBase class definition. Template parameter is the specific
118 // ParticleLayout-derived class which determines how the particles are
119 // distributed among processors.
120 template<class PLayout>
121 class IpplParticleBase : public DataSource,
122  public AbstractParticle<typename PLayout::Position_t, PLayout::Dimension> {
123 
124 public:
125  // useful enums
126  enum { Dim = PLayout::Dimension };
127 
128  // useful typedefs and enums
129  typedef PLayout Layout_t;
130  typedef typename PLayout::Position_t Position_t;
131  typedef typename PLayout::Index_t Index_t;
132 
133  typedef typename PLayout::ParticlePos_t ParticlePos_t;
134  typedef typename PLayout::ParticleIndex_t ParticleIndex_t;
135 
136  typedef typename PLayout::pair_iterator pair_iterator;
137  typedef typename PLayout::pair_t pair_t;
138  typedef typename PLayout::UpdateFlags UpdateFlags;
139  typedef std::vector<ParticleAttribBase *> attrib_container_t;
142 
143  // useful constants
144  unsigned int MIN_NUM_PART_PER_CORE;
145 
146  // our position, and our global ID's
149 
150 public:
151  // constructor 1: no arguments, so create an uninitialized IpplParticleBase.
152  // If this constructor is used, the user must call 'initialize' with
153  // a layout object in order to use this.
156  Layout(NULL),
157  TotalNum(0),
158  LocalNum(0),
159  DestroyNum(0),
160  GhostNum(0)
161  { }
162 
163  // constructor 2: arguments = layout to use.
164  IpplParticleBase(PLayout *layout) :
166  Layout(layout),
167  TotalNum(0),
168  LocalNum(0),
169  DestroyNum(0),
170  GhostNum(0)
171  {
172  setup();
173  }
174 
175  // destructor - delete the layout if necessary
177  if (Layout != 0)
178  delete Layout;
179  }
180 
181  //
182  // Initialization methods
183  //
184 
185  // For a IpplParticleBase that was created with the default constructor,
186  // initialize performs the same actions as are done in the non-default
187  // constructor. If this object has already been initialized, it is
188  // an error. For initialize, you must supply a layout instance.
189  void initialize(PLayout *);
190 
191 
192  //
193  // Accessor functions for this class
194  //
195 
196  // return/change the total or local number of particles
197  size_t getTotalNum() const { return TotalNum; }
198  size_t getLocalNum() const { return LocalNum; }
199  size_t getDestroyNum() const { return DestroyNum; }
200  size_t getGhostNum() const { return GhostNum; }
201  void setTotalNum(size_t n) { TotalNum = n; }
202  void setLocalNum(size_t n) { LocalNum = n; }
203 
206 
207 
208  // get the layout manager
209  PLayout& getLayout() { return *Layout; }
210  const PLayout& getLayout() const { return *Layout; }
211 
212  // get or set the boundary conditions container
214  return Layout->getBConds();
215  }
217  Layout->setBConds(bc);
218  }
219 
220  // Return a boolean value indicating if we are on a processor which can
221  // be used for single-node particle creation and initialization
222  bool singleInitNode() const;
223 
224  // get or set the flags used to indicate what to do during the update
225  bool getUpdateFlag(UpdateFlags f) const {
226  return getLayout().getUpdateFlag(f);
227  }
228  void setUpdateFlag(UpdateFlags f, bool val) {
229  getLayout().setUpdateFlag(f, val);
230  }
231 
232  //
233  // attribute manipulation methods
234  //
235 
236  // add a new attribute ... called by constructor of this and derived classes
237  void addAttribute(ParticleAttribBase& pa) { AttribList.push_back(&pa); }
238 
239  // get a pointer to the base class for the Nth attribute
241  getAttribute(attrib_container_t::size_type N) { return *(AttribList[N]); }
242 
243  // return the number of attributes in our list
244  attrib_container_t::size_type
245  numAttributes() const { return AttribList.size(); }
246 
247  // obtain the beginning and end iterators for our attribute list
248  attrib_iterator begin() { return AttribList.begin(); }
249  attrib_iterator end() { return AttribList.end(); }
250 
251  // reset the particle ID's to be globally consecutive, 0 thru TotalNum-1.
252  void resetID();
253 
254  //
255  // Global operations on all attributes
256  //
257 
258  // Update the particle object after a timestep. This routine will change
259  // our local, total, create particle counts properly.
260  virtual void update();
261  virtual void update(const ParticleAttrib<char>& canSwap);
262 
263  // create 1 new particle with a given ID
264  void createWithID(unsigned id);
265 
266  // create M new particles on this processor
267  void create(size_t);
268 
269  // create np new particles globally, equally distributed among all processors
270  void globalCreate(size_t np);
271 
272  // delete M particles, starting with the Ith particle. If the last argument
273  // is true, the destroy will be done immediately, otherwise the request
274  // will be cached.
275  void destroy(size_t, size_t, bool = false);
276 
277  // Put the data for M particles starting from local index I in a Message.
278  // Return the number of particles put in the Message.
279  size_t putMessage(Message&, size_t, size_t);
280  // put the data for particles on a list into a Message, given list of indices
281  // Return the number of particles put in the Message.
282  size_t putMessage(Message&, const std::vector<size_t>&);
283 
284  size_t putMessage(Message&, size_t);
285 
286 
287  Format* getFormat();
288 
289  size_t writeMsgBuffer(MsgBuffer*&, const std::vector<size_t>&);
290 
291  template<class O>
292  size_t writeMsgBufferWithOffsets(MsgBuffer*&, const std::vector<size_t>&, const std::vector<O>&);
293 
294  size_t readMsgBuffer(MsgBuffer *);
295  size_t readGhostMsgBuffer(MsgBuffer *, int);
296 
297  // Retrieve particles from the given message and store them.
298  // Return the number of particles retrieved.
299  size_t getMessage(Message&);
300 
301  size_t getSingleMessage(Message&);
302 
303  // retrieve particles from the given message and store them, also
304  // signaling we are creating the given number of particles. Return the
305  // number of particles created.
306  size_t getMessageAndCreate(Message&);
307 
308  // Actually perform the delete atoms action for all the attributes; the
309  // calls to destroy() only stored a list of what to do. This actually
310  // does it. This should in most cases only be called by the layout manager.
311  void performDestroy(bool updateLocalNum = false);
312 
313  // Apply the given sortlist to all the attributes.
314  void sort(SortList_t &);
315 
316  //
317  // Global operations on all ghost attributes ... generally, these should
318  // only be used by the layout object
319  //
320 
321  // Put the data for M particles starting from local index I in a Message.
322  // Return the number of particles put in the Message. This is for building
323  // ghost particle interaction lists.
324  size_t ghostPutMessage(Message&, size_t, size_t);
325 
326  // put the data for particles on a list into a Message, given list of indices
327  // Return the number of particles put in the Message. This is for building
328  // ghost particle interaction lists.
329  size_t ghostPutMessage(Message&, const std::vector<size_t>&);
330 
331  // Retrieve particles from the given message and sending node and store them.
332  // Return the number of particles retrieved.
333  size_t ghostGetMessage(Message&, int);
334 
335  size_t ghostGetSingleMessage(Message&, int);
336 
337  // delete M ghost particles, starting with the Ith particle. This is
338  // always done immediately.
339  void ghostDestroy(size_t, size_t);
340 
341  //
342  // I/O
343  //
344 
345  // print out debugging information
346  void printDebug(Inform&);
347 
348 protected:
349  // a virtual function which is called by this base class to get a
350  // specific instance of DataSourceObject based on the type of data
351  // and the connection method (the argument to the call).
352  virtual DataSourceObject *createDataSourceObject(const char *nm,
353  DataConnect *dc, int tm) {
354  return make_DataSourceObject(nm, dc, tm, *this);
355  }
356 
357  // list of destroy events for the next update. The data
358  // is not actually destroyed until the update phase.
359  // Each destroy is stored as a pair of unsigned ints, the particle
360  // index I to start at and the number of particles M to destroy.
361  std::vector< std::pair<size_t,size_t> > DestroyList;
362 
363 private:
364  // our layout object, which we delete in our destructor
365  PLayout *Layout;
366 
367  // our list of attributes
369 
370  // our current number of total and local atoms, and
371  // the number of particles we've deleted since the last update
372  // also, the number of ghost particles
373  size_t TotalNum;
374  size_t LocalNum;
375  size_t DestroyNum;
376  size_t GhostNum;
377 
378  // unique particle ID number generation value
379  unsigned NextID;
380 
381  //
382  // private methods
383  //
384 
385  // set up this new object: add attributes and check in to the layout
386  void setup();
387 
388  // Return a new unique ID value for use by new particles.
389  // The ID number = (i * numprocs) + myproc, i = 0, 1, 2, ...
390  unsigned getNextID();
391 };
392 
394 
395 #endif // PARTICLE_BASE_H
396 
397 /***************************************************************************
398  * $RCSfile: IpplParticleBase.h,v $ $Author: adelmann $
399  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:28 $
400  * IPPL_VERSION_ID: $Id: IpplParticleBase.h,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $
401  ***************************************************************************/
size_t ghostGetSingleMessage(Message &, int)
void initialize(PLayout *)
void ghostDestroy(size_t, size_t)
DataSourceObject * make_DataSourceObject(const char *, DataConnect *, int, Field< T, Dim, M, C > &)
attrib_iterator end()
attrib_container_t AttribList
PLayout::ParticlePos_t ParticlePos_t
PLayout::ParticleIndex_t ParticleIndex_t
attrib_container_t::size_type numAttributes() const
PLayout::Index_t Index_t
IpplParticleBase(PLayout *layout)
void destroy(size_t, size_t, bool=false)
void globalCreate(size_t np)
void performDestroy(bool updateLocalNum=false)
void setMinimumNumberOfParticlesPerCore(unsigned int n)
void printDebug(Inform &)
size_t readGhostMsgBuffer(MsgBuffer *, int)
unsigned int getMinimumNumberOfParticlesPerCore() const
PLayout::pair_t pair_t
ParticleBConds< Position_t, PLayout::Dimension > & getBConds()
void setUpdateFlag(UpdateFlags f, bool val)
size_t getDestroyNum() const
Position_t
Definition: Types.h:28
PLayout::UpdateFlags UpdateFlags
unsigned int MIN_NUM_PART_PER_CORE
std::vector< SortListIndex_t > SortList_t
size_t getTotalNum() const
size_t getGhostNum() const
size_t getMessage(Message &)
attrib_iterator begin()
void setLocalNum(size_t n)
size_t ghostGetMessage(Message &, int)
size_t writeMsgBufferWithOffsets(MsgBuffer *&, const std::vector< size_t > &, const std::vector< O > &)
size_t readMsgBuffer(MsgBuffer *)
PLayout::Position_t Position_t
attrib_container_t::iterator attrib_iterator
void setBConds(const ParticleBConds< Position_t, PLayout::Dimension > &bc)
void createWithID(unsigned id)
size_t getLocalNum() const
bool singleInitNode() const
std::vector< ParticleAttribBase * > attrib_container_t
virtual void update()
size_t putMessage(Message &, size_t, size_t)
void sort(SortList_t &)
size_t ghostPutMessage(Message &, size_t, size_t)
void addAttribute(ParticleAttribBase &pa)
PLayout::pair_iterator pair_iterator
ParticleAttribBase & getAttribute(attrib_container_t::size_type N)
ParticleAttribBase::SortList_t SortList_t
const PLayout & getLayout() const
std::string::iterator iterator
Definition: MSLang.h:16
size_t getMessageAndCreate(Message &)
std::vector< std::pair< size_t, size_t > > DestroyList
ParticleIndex_t ID
Definition: Inform.h:41
PLayout & getLayout()
bool getUpdateFlag(UpdateFlags f) const
size_t writeMsgBuffer(MsgBuffer *&, const std::vector< size_t > &)
virtual DataSourceObject * createDataSourceObject(const char *nm, DataConnect *dc, int tm)
size_t getSingleMessage(Message &)
void setTotalNum(size_t n)