OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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"
103#include "Message/Format.h"
104#include "Message/MsgBuffer.h"
105#include <vector>
106#include <utility>
107#include <iostream>
108
109template <class T, unsigned Dim>
111
112// forward declarations
113class Inform;
114class Message;
115template <class PLayout> class IpplParticleBase;
116template <class PLayout>
117std::ostream& operator<<(std::ostream&, const IpplParticleBase<PLayout>&);
118template <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.
124template<class PLayout>
126 public AbstractParticle<typename PLayout::Position_t, PLayout::Dimension> {
127public:
128 // useful enums
130
131 // useful typedefs and enums
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
150public:
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
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.
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
342protected:
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).
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
357private:
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;
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
size_t getMessageAndCreate(Message &)
PLayout & getLayout()
PLayout::pair_t pair_t
void setTotalNum(size_t n)
const PLayout & getLayout() const
size_t getSingleMessage(Message &)
size_t ghostGetMessage(Message &, int)
void performDestroy(bool updateLocalNum=false)
size_t readMsgBuffer(MsgBuffer *)
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)
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::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 > &)
ParticleBConds< Position_t, PLayout::Dimension > & getBConds()
ParticleAttribBase & getAttribute(attrib_container_t::size_type N)
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 &)
virtual DataSourceObject * createDataSourceObject(const char *nm, DataConnect *dc, int tm)
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)
ParticleBConds< T, Dim > & getBConds()
void setBConds(const ParticleBConds< T, Dim > &bc)
bool getUpdateFlag(UpdateFlags f) const
unsigned Index_t
Definition: Inform.h:42