OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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
100 #include "AppTypes/Vektor.h"
101 #include "DataSource/DataSource.h"
103 #include "Message/Format.h"
104 #include "Message/MsgBuffer.h"
105 #include <vector>
106 #include <utility>
107 #include <iostream>
108 
109 template <class T, unsigned Dim>
111 
112 // forward declarations
113 class Inform;
114 class Message;
115 template <class PLayout> class IpplParticleBase;
116 template <class PLayout>
117 std::ostream& operator<<(std::ostream&, const IpplParticleBase<PLayout>&);
118 template <class T, unsigned D> class ParticleBConds;
119 
120 
121 // IpplParticleBase class definition. Template parameter is the specific
122 // ParticleLayout-derived class which determines how the particles are
123 // distributed among processors.
124 template<class PLayout>
126  public AbstractParticle<typename PLayout::Position_t, PLayout::Dimension> {
127 public:
128  // useful enums
130 
131  // useful typedefs and enums
132  typedef PLayout Layout_t;
133  typedef typename PLayout::Position_t Position_t;
134  typedef typename PLayout::Index_t Index_t;
135 
136  typedef typename PLayout::ParticlePos_t ParticlePos_t;
137  typedef typename PLayout::ParticleIndex_t ParticleIndex_t;
138 
139  typedef typename PLayout::pair_iterator pair_iterator;
140  typedef typename PLayout::pair_t pair_t;
142  typedef std::vector<ParticleAttribBase *> attrib_container_t;
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.
155  Layout(NULL),
156  TotalNum(0),
157  LocalNum(0),
158  DestroyNum(0),
159  GhostNum(0)
160  { }
161 
162  // constructor 2: arguments = layout to use.
164  Layout(layout),
165  TotalNum(0),
166  LocalNum(0),
167  DestroyNum(0),
168  GhostNum(0)
169  {
170  setup();
171  }
172 
173  // destructor - delete the layout if necessary
175  if (Layout != 0)
176  delete Layout;
177  }
178 
179  //
180  // Initialization methods
181  //
182 
183  // For a IpplParticleBase that was created with the default constructor,
184  // initialize performs the same actions as are done in the non-default
185  // constructor. If this object has already been initialized, it is
186  // an error. For initialize, you must supply a layout instance.
187  void initialize(PLayout *);
188 
189 
190  //
191  // Accessor functions for this class
192  //
193 
194  // return/change the total or local number of particles
195  size_t getTotalNum() const { return TotalNum; }
196  size_t getLocalNum() const { return LocalNum; }
197  size_t getDestroyNum() const { return DestroyNum; }
198  size_t getGhostNum() const { return GhostNum; }
199  void setTotalNum(size_t n) { TotalNum = n; }
200  void setLocalNum(size_t n) { LocalNum = n; }
201 
202  // get the layout manager
203  PLayout& getLayout() { return *Layout; }
204  const PLayout& getLayout() const { return *Layout; }
205 
206  // get or set the boundary conditions container
208  return Layout->getBConds();
209  }
211  Layout->setBConds(bc);
212  }
213 
214  // Return a boolean value indicating if we are on a processor which can
215  // be used for single-node particle creation and initialization
216  bool singleInitNode() const;
217 
218  // get or set the flags used to indicate what to do during the update
219  bool getUpdateFlag(UpdateFlags f) const {
220  return getLayout().getUpdateFlag(f);
221  }
222  void setUpdateFlag(UpdateFlags f, bool val) {
223  getLayout().setUpdateFlag(f, val);
224  }
225 
226  //
227  // attribute manipulation methods
228  //
229 
230  // add a new attribute ... called by constructor of this and derived classes
231  void addAttribute(ParticleAttribBase& pa) { AttribList.push_back(&pa); }
232 
233  // get a pointer to the base class for the Nth attribute
235  getAttribute(attrib_container_t::size_type N) { return *(AttribList[N]); }
236 
237  // return the number of attributes in our list
238  attrib_container_t::size_type
239  numAttributes() const { return AttribList.size(); }
240 
241  // obtain the beginning and end iterators for our attribute list
242  attrib_iterator begin() { return AttribList.begin(); }
243  attrib_iterator end() { return AttribList.end(); }
244 
245  // reset the particle ID's to be globally consecutive, 0 thru TotalNum-1.
246  void resetID();
247 
248  //
249  // Global operations on all attributes
250  //
251 
252  // Update the particle object after a timestep. This routine will change
253  // our local, total, create particle counts properly.
254  virtual void update();
255  virtual void update(const ParticleAttrib<char>& canSwap);
256 
257  // create 1 new particle with a given ID
258  void createWithID(unsigned id);
259 
260  // create M new particles on this processor
261  void create(size_t);
262 
263  // create np new particles globally, equally distributed among all processors
264  void globalCreate(size_t np);
265 
266  // delete M particles, starting with the Ith particle. If the last argument
267  // is true, the destroy will be done immediately, otherwise the request
268  // will be cached.
269  void destroy(size_t, size_t, bool = false);
270 
271  // Put the data for M particles starting from local index I in a Message.
272  // Return the number of particles put in the Message.
273  size_t putMessage(Message&, size_t, size_t);
274  // put the data for particles on a list into a Message, given list of indices
275  // Return the number of particles put in the Message.
276  size_t putMessage(Message&, const std::vector<size_t>&);
277 
278  size_t putMessage(Message&, size_t);
279 
280 
281  Format* getFormat();
282 
283  size_t writeMsgBuffer(MsgBuffer*&, const std::vector<size_t>&);
284 
285  template<class O>
286  size_t writeMsgBufferWithOffsets(MsgBuffer*&, const std::vector<size_t>&, const std::vector<O>&);
287 
288  size_t readMsgBuffer(MsgBuffer *);
289  size_t readGhostMsgBuffer(MsgBuffer *, int);
290 
291  // Retrieve particles from the given message and store them.
292  // Return the number of particles retrieved.
293  size_t getMessage(Message&);
294 
295  size_t getSingleMessage(Message&);
296 
297  // retrieve particles from the given message and store them, also
298  // signaling we are creating the given number of particles. Return the
299  // number of particles created.
300  size_t getMessageAndCreate(Message&);
301 
302  // Actually perform the delete atoms action for all the attributes; the
303  // calls to destroy() only stored a list of what to do. This actually
304  // does it. This should in most cases only be called by the layout manager.
305  void performDestroy(bool updateLocalNum = false);
306 
307  // Apply the given sortlist to all the attributes.
308  void sort(SortList_t &);
309 
310  //
311  // Global operations on all ghost attributes ... generally, these should
312  // only be used by the layout object
313  //
314 
315  // Put the data for M particles starting from local index I in a Message.
316  // Return the number of particles put in the Message. This is for building
317  // ghost particle interaction lists.
318  size_t ghostPutMessage(Message&, size_t, size_t);
319 
320  // put the data for particles on a list into a Message, given list of indices
321  // Return the number of particles put in the Message. This is for building
322  // ghost particle interaction lists.
323  size_t ghostPutMessage(Message&, const std::vector<size_t>&);
324 
325  // Retrieve particles from the given message and sending node and store them.
326  // Return the number of particles retrieved.
327  size_t ghostGetMessage(Message&, int);
328 
329  size_t ghostGetSingleMessage(Message&, int);
330 
331  // delete M ghost particles, starting with the Ith particle. This is
332  // always done immediately.
333  void ghostDestroy(size_t, size_t);
334 
335  //
336  // I/O
337  //
338 
339  // print out debugging information
340  void printDebug(Inform&);
341 
342 protected:
343  // a virtual function which is called by this base class to get a
344  // specific instance of DataSourceObject based on the type of data
345  // and the connection method (the argument to the call).
346  virtual DataSourceObject *createDataSourceObject(const char *nm,
347  DataConnect *dc, int tm) {
348  return make_DataSourceObject(nm, dc, tm, *this);
349  }
350 
351  // list of destroy events for the next update. The data
352  // is not actually destroyed until the update phase.
353  // Each destroy is stored as a pair of unsigned ints, the particle
354  // index I to start at and the number of particles M to destroy.
355  std::vector< std::pair<size_t,size_t> > DestroyList;
356 
357 private:
358  // our layout object, which we delete in our destructor
360 
361  // our list of attributes
363 
364  // our current number of total and local atoms, and
365  // the number of particles we've deleted since the last update
366  // also, the number of ghost particles
367  size_t TotalNum;
368  size_t LocalNum;
369  size_t DestroyNum;
370  size_t GhostNum;
371 
372  // unique particle ID number generation value
373  unsigned NextID;
374 
375  //
376  // private methods
377  //
378 
379  // set up this new object: add attributes and check in to the layout
380  void setup();
381 
382  // Return a new unique ID value for use by new particles.
383  // The ID number = (i * numprocs) + myproc, i = 0, 1, 2, ...
384  unsigned getNextID();
385 };
386 
388 
389 #endif // PARTICLE_BASE_H
390 
391 /***************************************************************************
392  * $RCSfile: IpplParticleBase.h,v $ $Author: adelmann $
393  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:28 $
394  * IPPL_VERSION_ID: $Id: IpplParticleBase.h,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $
395  ***************************************************************************/
DataSourceObject * make_DataSourceObject(const char *, DataConnect *, int, Field< T, Dim, M, C > &)
std::ostream & operator<<(std::ostream &, const IpplParticleBase< PLayout > &)
std::string::iterator iterator
Definition: MSLang.h:16
virtual DataSourceObject * createDataSourceObject(const char *nm, DataConnect *dc, int tm)
size_t getMessageAndCreate(Message &)
PLayout::pair_t pair_t
ParticleBConds< Position_t, PLayout::Dimension > & getBConds()
void setTotalNum(size_t n)
size_t getSingleMessage(Message &)
size_t ghostGetMessage(Message &, int)
void performDestroy(bool updateLocalNum=false)
size_t readMsgBuffer(MsgBuffer *)
const PLayout & getLayout() const
size_t ghostPutMessage(Message &, size_t, size_t)
void initialize(PLayout *)
size_t getTotalNum() const
void ghostDestroy(size_t, size_t)
std::vector< ParticleAttribBase * > attrib_container_t
size_t getMessage(Message &)
void addAttribute(ParticleAttribBase &pa)
ParticleAttribBase & getAttribute(attrib_container_t::size_type N)
void sort(SortList_t &)
PLayout::Position_t Position_t
PLayout::ParticlePos_t ParticlePos_t
size_t putMessage(Message &, size_t, size_t)
attrib_container_t::iterator attrib_iterator
virtual void update()
size_t getGhostNum() const
PLayout & getLayout()
PLayout::Index_t Index_t
std::vector< std::pair< size_t, size_t > > DestroyList
size_t getDestroyNum() const
size_t writeMsgBuffer(MsgBuffer *&, const std::vector< size_t > &)
bool singleInitNode() const
ParticleAttribBase::SortList_t SortList_t
void setBConds(const ParticleBConds< Position_t, PLayout::Dimension > &bc)
size_t writeMsgBufferWithOffsets(MsgBuffer *&, const std::vector< size_t > &, const std::vector< O > &)
void setUpdateFlag(UpdateFlags f, bool val)
PLayout::pair_iterator pair_iterator
PLayout::UpdateFlags UpdateFlags
attrib_container_t::size_type numAttributes() const
ParticleIndex_t ID
bool getUpdateFlag(UpdateFlags f) const
void printDebug(Inform &)
size_t getLocalNum() const
PLayout::ParticleIndex_t ParticleIndex_t
attrib_iterator begin()
void globalCreate(size_t np)
size_t readGhostMsgBuffer(MsgBuffer *, int)
attrib_container_t AttribList
IpplParticleBase(PLayout *layout)
size_t ghostGetSingleMessage(Message &, int)
void createWithID(unsigned id)
void destroy(size_t, size_t, bool=false)
void setLocalNum(size_t n)
attrib_iterator end()
Definition: Format.h:27
std::vector< SortListIndex_t > SortList_t
void setUpdateFlag(UpdateFlags f, bool val)
void setBConds(const ParticleBConds< T, Dim > &bc)
ParticleBConds< T, Dim > & getBConds()
bool getUpdateFlag(UpdateFlags f) const
unsigned Index_t
Definition: Inform.h:42