IpplParticleBase.h 14.8 KB
Newer Older
gsell's avatar
gsell committed
1 2 3 4
// -*- C++ -*-
/***************************************************************************
 *
 * The IPPL Framework
5
 *
gsell's avatar
gsell committed
6 7 8 9 10 11 12 13 14
 *
 * Visit http://people.web.psi.ch/adelmann/ for more details
 *
 ***************************************************************************/

#ifndef PARTICLE_BASE_H
#define PARTICLE_BASE_H

/*
15
 * IpplParticleBase - Base class for all user-defined particle classes.
gsell's avatar
gsell committed
16
 *
17 18
 * IpplParticleBase is a container and manager for a set of particles.
 * The user must define a class derived from IpplParticleBase which describes
gsell's avatar
gsell committed
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
gsell's avatar
gsell committed
21 22 23 24
 * keeps a list of pointers to these attributes, and performs global
 * operations on them such as update, particle creation and destruction,
 * and inter-processor particle migration.
 *
25
 * IpplParticleBase is templated on the ParticleLayout mechanism for the particles.
gsell's avatar
gsell committed
26 27 28 29 30
 * This template parameter should be a class derived from ParticleLayout.
 * ParticleLayout-derived classes maintain the info on which particles are
 * located on which processor, and performs the specific communication
 * required between processors for the particles.  The ParticleLayout is
 * templated on the type and dimension of the atom position attribute, and
31
 * IpplParticleBase uses the same types for these items as the given
gsell's avatar
gsell committed
32 33
 * ParticleLayout.
 *
34
 * IpplParticleBase and all derived classes have the following common
gsell's avatar
gsell committed
35 36 37 38 39 40
 * characteristics:
 *     - The spatial positions of the N particles are stored in the
 *       ParticlePos_t variable R
 *     - The global index of the N particles are stored in the
 *       ParticleIndex_t variable ID
 *     - A pointer to an allocated layout class.  When you construct a
41 42
 *       IpplParticleBase, you must provide a layout instance, and IpplParticleBase
 *       will delete this instance when it (the IpplParticleBase) is deleted.
gsell's avatar
gsell committed
43 44 45 46 47
 *
 * To use this class, the user defines a derived class with the same
 * structure as in this example:
 *
 *   class UserParticles :
48
 *            public IpplParticleBase< ParticleSpatialLayout<double,2> > {
gsell's avatar
gsell committed
49 50 51 52 53 54
 *   public:
 *     // attributes for this class
 *     ParticleAttribute<double> rad;  // radius
 *     ParticlePos_t             vel;  // velocity, same storage type as R
 *
 *     // constructor: add attributes to base class
55
 *     UserParticles(ParticleSpatialLayout<double,2>* L) : IpplParticleBase(L) {
gsell's avatar
gsell committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
 *       addAttribute(rad);
 *       addAttribute(vel);
 *     }
 *   };
 *
 * This example defines a user class with 2D position and two extra
 * attributes: a radius rad (double), and a velocity vel (a 2D Vektor).
 *
 * After each 'time step' in a calculation, which is defined as a period
 * in which the particle positions may change enough to affect the global
 * layout, the user must call the 'update' routine, which will move
 * particles between processors, etc.  After the Nth call to update, a
 * load balancing routine will be called instead.  The user may set the
 * frequency of load balancing (N), or may supply a function to
 * determine if load balancing should be done or not.
 *
72
 * Each IpplParticleBase can contain zero or more 'ghost' particles, which are
gsell's avatar
gsell committed
73 74 75 76 77 78 79
 * copies of particle data collected from other nodes.  These ghost particles
 * have many of the same function calls as for the 'regular' particles, with
 * the word 'ghost' prepended.  They are not necessary; but may be used to
 * improve performance of some parallel algorithms (such as calculating
 * neighbor lists).  The actual determination of what ghost particles should
 * be stored in this object (if any) is done by the specific layout object.
 *
80 81
 * IpplParticleBase also contains information on the types of boundary conditions
 * to use.  IpplParticleBase contains a ParticleBConds object, which is an array
gsell's avatar
gsell committed
82 83 84 85 86
 * of particle boundary condition functions.  By default, these BC's are null,
 * so that nothing special happens at the boundary, but the user may set these
 * BC's by using the 'getBConds' method to access the BC container.  The BC's
 * will then be used at the next update.  In fact, the BC container is stored
 * within the ParticleLayout object, but the interface the user uses to access
87
 * it is via IpplParticleBase.
gsell's avatar
gsell committed
88
 *
89
 * You can create an uninitialized IpplParticleBase, by using the default
gsell's avatar
gsell committed
90 91
 * constructor.  In this case, it will not do any initialization of data
 * 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()'
gsell's avatar
gsell committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
 * method which takes as an argument the layout instance to use.
 */

// include files
#include "Particle/ParticleAttrib.h"
#include "AppTypes/Vektor.h"
#include "DataSource/DataSource.h"
#include "DataSource/MakeDataSource.h"
#include "Message/Formatter.h"
#include <vector>
#include <algorithm>  // Include algorithms
#include <utility>
#include <iostream>

// forward declarations
class Inform;
class Message;
110
template <class PLayout> class IpplParticleBase;
gsell's avatar
gsell committed
111
template <class PLayout>
112
std::ostream& operator<<(std::ostream&, const IpplParticleBase<PLayout>&);
gsell's avatar
gsell committed
113 114 115
template <class T, unsigned D> class ParticleBConds;


116
// IpplParticleBase class definition.  Template parameter is the specific
gsell's avatar
gsell committed
117 118 119
// ParticleLayout-derived class which determines how the particles are
// distributed among processors.
template<class PLayout>
120
class IpplParticleBase : public DataSource {
gsell's avatar
gsell committed
121 122

public:
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    // useful enums
    enum { Dim = PLayout::Dimension };

    // useful typedefs and enums
    typedef PLayout                           Layout_t;
    typedef typename PLayout::Position_t      Position_t;
    typedef typename PLayout::Index_t         Index_t;

    typedef typename PLayout::ParticlePos_t   ParticlePos_t;
    typedef typename PLayout::ParticleIndex_t ParticleIndex_t;

    typedef typename PLayout::pair_iterator   pair_iterator;
    typedef typename PLayout::pair_t          pair_t;
    typedef typename PLayout::UpdateFlags     UpdateFlags;
    typedef std::vector<ParticleAttribBase *>      attrib_container_t;
    typedef attrib_container_t::iterator      attrib_iterator;
    typedef ParticleAttribBase::SortList_t    SortList_t;

141 142 143
    // useful constants
    unsigned int MIN_NUM_PART_PER_CORE;

144 145 146
    // our position, and our global ID's
    ParticlePos_t   R;
    ParticleIndex_t ID;
gsell's avatar
gsell committed
147 148

public:
149
    // constructor 1: no arguments, so create an uninitialized IpplParticleBase.
150 151
    // If this constructor is used, the user must call 'initialize' with
    // a layout object in order to use this.
152
    IpplParticleBase() :
adelmann's avatar
adelmann committed
153
        MIN_NUM_PART_PER_CORE(0),
154
        Layout(NULL),
155 156 157 158 159 160 161
        TotalNum(0),
        LocalNum(0),
        DestroyNum(0),
        GhostNum(0)
    { }

    // constructor 2: arguments = layout to use.
162
    IpplParticleBase(PLayout *layout) :
adelmann's avatar
adelmann committed
163
        MIN_NUM_PART_PER_CORE(0),
164
        Layout(layout),
165 166 167 168 169 170 171 172 173
        TotalNum(0),
        LocalNum(0),
        DestroyNum(0),
        GhostNum(0)
    {
        setup();
    }

    // destructor - delete the layout if necessary
174
    ~IpplParticleBase() {
175 176 177 178 179 180 181 182
        if (Layout != 0)
            delete Layout;
    }

    //
    // Initialization methods
    //

183
    // For a IpplParticleBase that was created with the default constructor,
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    // initialize performs the same actions as are done in the non-default
    // constructor.  If this object has already been initialized, it is
    // an error.  For initialize, you must supply a layout instance.
    void initialize(PLayout *);


    //
    // Accessor functions for this class
    //

    // return/change the total or local number of particles
    size_t getTotalNum() const { return TotalNum; }
    size_t getLocalNum() const { return LocalNum; }
    size_t getDestroyNum() const { return DestroyNum; }
    size_t getGhostNum() const { return GhostNum; }
    void setTotalNum(size_t n) { TotalNum = n; }
    void setLocalNum(size_t n) { LocalNum = n; }

kraus's avatar
kraus committed
202
    unsigned int getMinimumNumberOfParticlesPerCore() const { return MIN_NUM_PART_PER_CORE; };
203
    void setMinimumNumberOfParticlesPerCore(unsigned int n) { MIN_NUM_PART_PER_CORE=n; };
204 205


206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    // get the layout manager
    PLayout& getLayout() { return *Layout; }
    const PLayout& getLayout() const { return *Layout; }

    // get or set the boundary conditions container
    ParticleBConds<Position_t,PLayout::Dimension>& getBConds() {
        return Layout->getBConds();
    }
    void setBConds(const ParticleBConds<Position_t,PLayout::Dimension>& bc) {
        Layout->setBConds(bc);
    }

    // Return a boolean value indicating if we are on a processor which can
    // be used for single-node particle creation and initialization
    bool singleInitNode() const;

    // get or set the flags used to indicate what to do during the update
    bool getUpdateFlag(UpdateFlags f) const {
        return getLayout().getUpdateFlag(f);
    }
    void setUpdateFlag(UpdateFlags f, bool val) {
        getLayout().setUpdateFlag(f, val);
    }

    //
    // attribute manipulation methods
    //

    // add a new attribute ... called by constructor of this and derived classes
    void addAttribute(ParticleAttribBase& pa) { AttribList.push_back(&pa); }

    // get a pointer to the base class for the Nth attribute
    ParticleAttribBase&
    getAttribute(attrib_container_t::size_type N) { return *(AttribList[N]); }

    // return the number of attributes in our list
    attrib_container_t::size_type
    numAttributes() const { return AttribList.size(); }

    // obtain the beginning and end iterators for our attribute list
    attrib_iterator begin() { return AttribList.begin(); }
    attrib_iterator end()   { return AttribList.end(); }

    // reset the particle ID's to be globally consecutive, 0 thru TotalNum-1.
    void resetID();

    //
    // Global operations on all attributes
    //

    // Update the particle object after a timestep.  This routine will change
    // our local, total, create particle counts properly.
    void update();
    void update(const ParticleAttrib<char>& canSwap);

    // create 1 new particle with a given ID
    void createWithID(unsigned id);

    // create M new particles on this processor
    void create(size_t);

    // create np new particles globally, equally distributed among all processors
    void globalCreate(size_t np);

    // delete M particles, starting with the Ith particle.  If the last argument
    // is true, the destroy will be done immediately, otherwise the request
    // will be cached.
    void destroy(size_t, size_t, bool = false);

    // Put the data for M particles starting from local index I in a Message.
    // Return the number of particles put in the Message.
    size_t putMessage(Message&, size_t, size_t);
    // put the data for particles on a list into a Message, given list of indices
    // Return the number of particles put in the Message.
    size_t putMessage(Message&, const std::vector<size_t>&);

    size_t putMessage(Message&, size_t);


    Format* getFormat();

    size_t writeMsgBuffer(MsgBuffer*&, const std::vector<size_t>&);

    template<class O>
    size_t writeMsgBufferWithOffsets(MsgBuffer*&, const std::vector<size_t>&, const std::vector<O>&);

    size_t readMsgBuffer(MsgBuffer *);
    size_t readGhostMsgBuffer(MsgBuffer *, int);

    // Retrieve particles from the given message and store them.
    // Return the number of particles retrieved.
    size_t getMessage(Message&);

    size_t getSingleMessage(Message&);

    // retrieve particles from the given message and store them, also
    // signaling we are creating the given number of particles.  Return the
    // number of particles created.
    size_t getMessageAndCreate(Message&);

    // Actually perform the delete atoms action for all the attributes; the
    // calls to destroy() only stored a list of what to do.  This actually
    // does it.  This should in most cases only be called by the layout manager.
309
    void performDestroy(bool updateLocalNum = false);
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

    // Apply the given sortlist to all the attributes.
    void sort(SortList_t &);

    //
    // Global operations on all ghost attributes ... generally, these should
    // only be used by the layout object
    //

    // Put the data for M particles starting from local index I in a Message.
    // Return the number of particles put in the Message.  This is for building
    // ghost particle interaction lists.
    size_t ghostPutMessage(Message&, size_t, size_t);

    // put the data for particles on a list into a Message, given list of indices
    // Return the number of particles put in the Message.  This is for building
    // ghost particle interaction lists.
    size_t ghostPutMessage(Message&, const std::vector<size_t>&);

    // Retrieve particles from the given message and sending node and store them.
    // Return the number of particles retrieved.
    size_t ghostGetMessage(Message&, int);

    size_t ghostGetSingleMessage(Message&, int);

    // delete M ghost particles, starting with the Ith particle.  This is
    // always done immediately.
    void ghostDestroy(size_t, size_t);

    //
    // I/O
    //

    // print out debugging information
    void printDebug(Inform&);
gsell's avatar
gsell committed
345 346

protected:
347 348 349 350 351 352 353
    // a virtual function which is called by this base class to get a
    // specific instance of DataSourceObject based on the type of data
    // and the connection method (the argument to the call).
    virtual DataSourceObject *createDataSourceObject(const char *nm,
                                                     DataConnect *dc, int tm) {
        return make_DataSourceObject(nm, dc, tm, *this);
    }
gsell's avatar
gsell committed
354 355

private:
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    // our layout object, which we delete in our destructor
    PLayout *Layout;

    // our list of attributes
    attrib_container_t AttribList;

    // our current number of total and local atoms, and
    // the number of particles we've deleted since the last update
    // also, the number of ghost particles
    size_t TotalNum;
    size_t LocalNum;
    size_t DestroyNum;
    size_t GhostNum;

    // unique particle ID number generation value
    unsigned NextID;

    // list of destroy events for the next update.  The data
    // is not actually destroyed until the update phase.
    // Each destroy is stored as a pair of unsigned ints, the particle
    // index I to start at and the number of particles M to destroy.
    std::vector< std::pair<size_t,size_t> > DestroyList;

    //
    // private methods
    //

    // set up this new object:  add attributes and check in to the layout
    void setup();

    // Return a new unique ID value for use by new particles.
    // The ID number = (i * numprocs) + myproc, i = 0, 1, 2, ...
    unsigned getNextID();
gsell's avatar
gsell committed
389 390
};

391
#include "Particle/IpplParticleBase.hpp"
gsell's avatar
gsell committed
392 393 394 395

#endif // PARTICLE_BASE_H

/***************************************************************************
396
 * $RCSfile: IpplParticleBase.h,v $   $Author: adelmann $
gsell's avatar
gsell committed
397
 * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:28 $
398
 * IPPL_VERSION_ID: $Id: IpplParticleBase.h,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $
399
 ***************************************************************************/