OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
IpplParticleBase.hpp
Go to the documentation of this file.
1/***************************************************************************
2 *
3 * The IPPL Framework
4 *
5 * This program was prepared by PSI.
6 * All rights in the program are reserved by PSI.
7 * Neither PSI nor the author(s)
8 * makes any warranty, express or implied, or assumes any liability or
9 * responsibility for the use of this software
10 *
11 * Visit www.amas.web.psi for more details
12 *
13 ***************************************************************************/
14
18#include "Message/Message.h"
19#include "Message/Communicate.h"
20#include "Utility/Inform.h"
21#include "Utility/PAssert.h"
22#include "Utility/IpplInfo.h"
23#include "Utility/IpplStats.h"
25#include <algorithm>
26
28// For a IpplParticleBase that was created with the default constructor,
29// initialize performs the same actions as are done in the non-default
30// constructor. If this object has already been initialized, it is
31// an error. For initialize, you must supply a layout instance.
32template<class PLayout>
34
35 // make sure we have not already been initialized, and that we have
36 // been given a good layout
37 PAssert(Layout == 0);
38 PAssert(layout != 0);
39
40 // save the layout, and perform setup tasks
41 Layout = layout;
42 setup();
43}
44
45
47// set up this new object: add attributes and check in to the layout
48template<class PLayout>
50
51 TotalNum = 0;
52 LocalNum = 0;
53 DestroyNum = 0;
54 GhostNum = 0;
55
56 // shift ID back so that first ID retrieved is myNode
57 NextID = Ippl::Comm->myNode() - Ippl::Comm->getNodes();
58
59 // Create position R and index ID attributes for the particles,
60 // and add them to our list of attributes.
61 addAttribute(R);
62 addAttribute(ID);
63
64 // set pointer for base class AbstractParticle
65 this->R_p = &R;
66 this->ID_p = &ID;
67
68 // indicate we have created a new IpplParticleBase object
69 INCIPPLSTAT(incIpplParticleBases);
70}
71
72
74// Return a boolean value indicating if we are on a processor which can
75// be used for single-node particle creation and initialization
76
77template<class PLayout>
79 return (Ippl::Comm->myNode() == 0);
80}
81
83// Return a new unique ID value for use by new particles.
84// The ID number = (i * numprocs) + myproc, i = 0, 1, 2, ...
85template<class PLayout>
87
88
89
90 return (NextID += Ippl::Comm->getNodes());
91}
92
94// Reset the particle ID's to be globally consecutive, 0 thru TotalNum.
95template <class PLayout>
97
98
99
100 unsigned int nodes = Ippl::getNodes();
101 unsigned int myNode = Ippl::myNode();
102 size_t localNum = this->getLocalNum();
103 size_t ip;
104 int master = 0;
105 if (myNode == (unsigned int) master) {
106 // Node 0 can immediately set its ID's to 0 thru LocalNum-1
107 for (ip=0; ip<localNum; ++ip)
108 this->ID[ip] = ip;
109 // if there is only one processor, we are done
110 if (nodes == 1) return;
111 // parallel case: must find out how many particles each processor has
112 // Node 0 gathers this information into an array
113 size_t *lp;
114 lp = new size_t[nodes];
115 lp[0] = localNum; // enter our own number of particles
116 // get next message tag and receive messages
118 Message* msg1;
119 for (ip=1; ip<nodes; ++ip) {
120 int rnode = COMM_ANY_NODE;
121 msg1 = Ippl::Comm->receive_block(rnode,tag1);
122 PAssert(msg1);
123 msg1->get(lp[rnode]);
124 delete msg1;
125 }
126 // now we should have all the localnum values.
127 // figure out starting ID for each processor and send back
128 size_t current, sum = 0;
129 for (ip=0; ip<nodes; ++ip) {
130 current = lp[ip];
131 lp[ip] = sum;
132 sum += current;
133 }
134 // send initial ID values back out
136 for (ip=1; ip<nodes; ++ip) {
137 Message* msg2 = new Message;
138 msg2->put(lp[ip]);
139 bool success = Ippl::Comm->send(msg2,ip,tag2);
140 if (success == false) {
141 throw IpplException (
142 "IpplParticleBase<PLayout>::resetID()",
143 "sending initial ID values failed.");
144 }
145 }
146 // we are done
147 return;
148 }
149 else {
150 // first send number of local particles to Node 0
152 Message* msg1 = new Message;
153 msg1->put(localNum);
154 bool success = Ippl::Comm->send(msg1,master,tag1);
155 if (success == false) {
156 throw IpplException (
157 "IpplParticleBase<PLayout>::resetID()",
158 "sending initial ID values failed.");
159 }
160 // now receive back our initial ID number
161 size_t initialID = 0;
163 Message* msg2 = Ippl::Comm->receive_block(master,tag2);
164 PAssert(msg2);
165 msg2->get(initialID);
166 delete msg2;
167 // now reset our particle ID's using this initial value
168 for (ip=0; ip<localNum; ++ip)
169 this->ID[ip] = ip + initialID;
170 // we are done
171 return;
172 }
173}
174
175
177// put the data for M particles starting from local index I in a Message
178template<class PLayout>
179size_t
181
182 // make sure we've been initialized
183 PAssert(Layout != 0);
184
185 // put into message the number of items in the message
186 msg.put(M);
188 // go through all the attributes and put their data in the message
189 if (M > 0) {
190 // this routine should only be called for local particles; call
191 // ghostPutMessage to put in particles which might be ghost particles
192 PAssert_LT(I, R.size());
193 PAssert_LE(I + M, R.size());
194
195 attrib_container_t::iterator abeg = AttribList.begin();
196 attrib_container_t::iterator aend = AttribList.end();
197 for ( ; abeg != aend; abeg++ )
198 (*abeg)->putMessage(msg, M, I);
199 }
200
201 return M;
202}
203
204
206// put the data for a list of particles in a Message
207template<class PLayout>
208size_t
210 const std::vector<size_t>& putList)
211{
212
213 // make sure we've been initialized
214 PAssert(Layout != 0);
215
216 std::vector<size_t>::size_type M = putList.size();
217 msg.put(M);
218
219 // go through all the attributes and put their data in the message
220 if (M > 0) {
221 attrib_container_t::iterator abeg = AttribList.begin();
222 attrib_container_t::iterator aend = AttribList.end();
223 for ( ; abeg != aend; ++abeg )
224 (*abeg)->putMessage(msg, putList);
225 }
226
227 return M;
228}
229
230template<class PLayout>
231size_t
233
234 // make sure we've been initialized
235 PAssert(Layout != 0);
236
237 // put into message the number of items in the message
238
239 // go through all the attributes and put their data in the message
240
241 attrib_container_t::iterator abeg = AttribList.begin();
242 attrib_container_t::iterator aend = AttribList.end();
243 for ( ; abeg != aend; abeg++ )
244 (*abeg)->putMessage(msg, 1, I);
245
246 return 1;
247}
248
249template<class PLayout>
251{
252 //create dummy particle so we can obtain the format
253 bool wasempty = false;
254 if(this->getLocalNum()==0)
256 this->create(1);
257 wasempty = true;
259
260 //obtain the format
261 Message *msg = new Message;
262 this->putMessage(*msg, (size_t) 0);
263 Format *format = new Format(msg);
264 delete msg;
265
266 //remove the dummy particle again
267 if (wasempty)
268 this->destroy(1, 0, true);
270 return format;
271}
272
273template<class PLayout>
274size_t
275IpplParticleBase<PLayout>::writeMsgBuffer(MsgBuffer *&msgbuf, const std::vector<size_t> &list)
277 msgbuf = new MsgBuffer(this->getFormat(), list.size());
279 for (unsigned int i = 0;i<list.size();++i)
280 {
282 this->putMessage(msg, list[i]);
283 msgbuf->add(&msg);
284 }
285 return list.size();
287
288template<class PLayout>
289template<class O>
290size_t
291IpplParticleBase<PLayout>::writeMsgBufferWithOffsets(MsgBuffer *&msgbuf, const std::vector<size_t> &list, const std::vector<O> &offset)
292 {
293 msgbuf = new MsgBuffer(this->getFormat(), list.size());
294 typename PLayout::SingleParticlePos_t oldpos;
295 for (unsigned int i = 0;i<list.size();++i)
296 {
297 oldpos = R[list[i]];
298 for(int d = 0;d<Dim;++d)
299 {
300 R[list[i]][d] += offset[i][d];
301 }
302
303 Message msg;
304 this->putMessage(msg, list[i]);
305 msgbuf->add(&msg);
306
307 R[list[i]] = oldpos;
309 return list.size();
310 }
311
312template<class PLayout>
313size_t
315{
316 size_t added = 0;
317 Message *msg = msgbuf->get();
318 while (msg != 0)
319 {
320 added += this->getSingleMessage(*msg);
321 delete msg;
322 msg = msgbuf->get();
324 return added;
325}
326
328template<class PLayout>
329size_t
331{
332 size_t added = 0;
333 Message *msg = msgbuf->get();
334 while (msg != 0)
335 {
336 added += this->ghostGetSingleMessage(*msg, node);
337 delete msg;
338 msg = msgbuf->get();
339 }
340 return added;
341}
342
344// retrieve particles from the given message and store them
345template<class PLayout>
347
348 // make sure we've been initialized
349 PAssert(Layout != 0);
350
351 // get the number of items in the message
352 size_t numitems = 0;
353 msg.get(numitems);
354
355 // go through all the attributes and get their data from the message
356 if (numitems > 0) {
357 attrib_container_t::iterator abeg = AttribList.begin();
358 attrib_container_t::iterator aend = AttribList.end();
359 for ( ; abeg != aend; abeg++ )
360 (*abeg)->getMessage(msg, numitems);
361 }
362
363 return numitems;
364}
365
367// retrieve particles from the given message and store them
368template<class PLayout>
370
371 // make sure we've been initialized
372 PAssert(Layout != 0);
373
374 // get the number of items in the message
375 size_t numitems=1;
376
377 // go through all the attributes and get their data from the message
378 if (numitems > 0) {
379 attrib_container_t::iterator abeg = AttribList.begin();
380 attrib_container_t::iterator aend = AttribList.end();
381 for ( ; abeg != aend; abeg++ )
382 (*abeg)->getMessage(msg, numitems);
383 }
385 return numitems;
386}
387
388
390// retrieve particles from the given message and store them, also
391// signaling we are creating the given number of particles. Return the
392// number of particles created.
393template<class PLayout>
395
396 // make sure we've been initialized
397 PAssert(Layout != 0);
398
399 // call the regular create, and add in the particles to our LocalNum
400 size_t numcreate = getMessage(msg);
401 LocalNum += numcreate;
402 ADDIPPLSTAT(incParticlesCreated,numcreate);
403 return numcreate;
404}
405
406
408// create M new particles on this processor
409template<class PLayout>
411
412
413 // make sure we've been initialized
414 PAssert(Layout != 0);
415
416 // go through all the attributes, and allocate space for M new particles
417 attrib_container_t::iterator abeg = AttribList.begin();
418 attrib_container_t::iterator aend = AttribList.end();
419 for ( ; abeg != aend; abeg++ )
420 (*abeg)->create(M);
421
422 // set the unique ID value for these new particles
423 size_t i1 = LocalNum;
424 size_t i2 = i1 + M;
425 while (i1 < i2)
426 ID[i1++] = getNextID();
427
428 // remember that we're creating these new particles
429 LocalNum += M;
430 ADDIPPLSTAT(incParticlesCreated,M);
431}
432
433
435// create 1 new particle with a given ID
436template<class PLayout>
438
439
440 // make sure we've been initialized
441 PAssert(Layout != 0);
442
443 // go through all the attributes, and allocate space for M new particles
444 attrib_container_t::iterator abeg = AttribList.begin();
445 attrib_container_t::iterator aend = AttribList.end();
446 for ( ; abeg != aend; abeg++ )
447 (*abeg)->create(1);
448
449 const size_t M = 1;
450 // set the unique ID value for these new particles
451 size_t i1 = LocalNum;
452 size_t i2 = i1 + M;
453 while (i1 < i2)
454 ID[i1++] = id;
455
456 // remember that we're creating these new particles
457 LocalNum += M;
458 ADDIPPLSTAT(incParticlesCreated,1);
459}
460
461
463// create np new particles globally, equally distributed among all processors
464template<class PLayout>
466
467
468 // make sure we've been initialized
469 PAssert(Layout != 0);
470
471 // Compute the number of particles local to each processor:
472 unsigned nPE = IpplInfo::getNodes();
473 unsigned npLocal = np/nPE;
474
475 // Handle the case where np/nPE is not an integer:
476 unsigned myPE = IpplInfo::myNode();
477 unsigned rem = np - npLocal * nPE;
478 if (myPE < rem) ++npLocal;
479
480 // Now each PE calls the local IpplParticleBase::create() function to create it's
481 // local number of particles:
482 create(npLocal);
483}
484
485
487// delete M particles, starting with the Ith particle. If the last argument
488// is true, the destroy will be done immediately, otherwise the request
489// will be cached.
490template<class PLayout>
491void IpplParticleBase<PLayout>::destroy(size_t M, size_t I, bool doNow) {
492
493 // make sure we've been initialized
494 PAssert(Layout != 0);
495
496 if (M > 0) {
497 if (doNow) {
498 // find out if we are using optimized destroy method
499 bool optDestroy = getUpdateFlag(PLayout::OPTDESTROY);
500 // loop over attributes and carry out the destroy request
501 attrib_container_t::iterator abeg, aend = AttribList.end();
502 for (abeg = AttribList.begin(); abeg != aend; ++abeg)
503 (*abeg)->destroy(M,I,optDestroy);
504 LocalNum -= M;
505 }
506 else {
507 // add this group of particle indices to our list of items to destroy
508 std::pair<size_t,size_t> destroyEvent(I,M);
509 DestroyList.push_back(destroyEvent);
510 DestroyNum += M;
511 }
512
513 // remember we have this many more items to destroy (or have destroyed)
514 ADDIPPLSTAT(incParticlesDestroyed,M);
515 }
516}
517
518
520// Update the particle object after a timestep. This routine will change
521// our local, total, create particle counts properly.
522template<class PLayout>
524
525
526
527 // make sure we've been initialized
528 PAssert(Layout != 0);
529
530 // ask the layout manager to update our atoms, etc.
531 Layout->update(*this);
532 INCIPPLSTAT(incParticleUpdates);
533}
534
535
537// Update the particle object after a timestep. This routine will change
538// our local, total, create particle counts properly.
539template<class PLayout>
541
542
543
544 // make sure we've been initialized
545 PAssert(Layout != 0);
546
547 // ask the layout manager to update our atoms, etc.
548 Layout->update(*this, &canSwap);
549 INCIPPLSTAT(incParticleUpdates);
550}
551
552
553// Actually perform the delete atoms action for all the attributes; the
554// calls to destroy() only stored a list of what to do. This actually
555// does it. This should in most cases only be called by the layout manager.
556template<class PLayout>
558
559
560
561 // make sure we've been initialized
562 PAssert(Layout != 0);
563
564 // nothing to do if destroy list is empty
565 if (DestroyList.empty()) return;
566
567 // before processing the list, we should make sure it is sorted
568 bool isSorted = true;
569 typedef std::vector< std::pair<size_t,size_t> > dlist_t;
570 dlist_t::const_iterator curr = DestroyList.begin();
571 const dlist_t::const_iterator last = DestroyList.end();
572 dlist_t::const_iterator next = curr + 1;
573 while (next != last && isSorted) {
574 if (*next++ < *curr++) isSorted = false;
575 }
576 if (!isSorted)
577 std::sort(DestroyList.begin(),DestroyList.end());
578
579 // find out if we are using optimized destroy method
580 bool optDestroy = getUpdateFlag(PLayout::OPTDESTROY);
581
582 // loop over attributes and process destroy list
583 attrib_container_t::iterator abeg, aend = AttribList.end();
584 for (abeg = AttribList.begin(); abeg != aend; ++abeg)
585 (*abeg)->destroy(DestroyList,optDestroy);
586
587 if (updateLocalNum) {
588 for (curr = DestroyList.begin(); curr != last; ++ curr) {
589 LocalNum -= curr->second;
590 }
591 }
592
593 // clear destroy list and update destroy num counter
594 DestroyList.erase(DestroyList.begin(),DestroyList.end());
595 DestroyNum = 0;
596}
597
598
600// delete M ghost particles, starting with the Ith particle.
601// This is done immediately.
602template<class PLayout>
604
605
606
607 // make sure we've been initialized
608 PAssert(Layout != 0);
609
610 if (M > 0) {
611 // delete the data from the attribute containers
612 size_t dnum = 0;
613 attrib_container_t::iterator abeg = AttribList.begin();
614 attrib_container_t::iterator aend = AttribList.end();
615 for ( ; abeg != aend; ++abeg )
616 dnum = (*abeg)->ghostDestroy(M, I);
617 GhostNum -= dnum;
618 }
619}
620
621
623// Put the data for M particles starting from local index I in a Message.
624// Return the number of particles put in the Message. This is for building
625// ghost particle interaction lists.
626template<class PLayout>
627size_t
629
630 // make sure we've been initialized
631 PAssert(Layout != 0);
632
633 // put into message the number of items in the message
634 if (I >= R.size()) {
635 // we're putting in ghost particles ...
636 if ((I + M) > (R.size() + GhostNum))
637 M = (R.size() + GhostNum) - I;
638 } else {
639 // we're putting in local particles ...
640 if ((I + M) > R.size())
641 M = R.size() - I;
642 }
643 msg.put(M);
644
645 // go through all the attributes and put their data in the message
646 if (M > 0) {
647 attrib_container_t::iterator abeg = AttribList.begin();
648 attrib_container_t::iterator aend = AttribList.end();
649 for ( ; abeg != aend; abeg++ )
650 (*abeg)->ghostPutMessage(msg, M, I);
651 }
652
653 return M;
654}
655
656
658// put the data for particles on a list into a Message, given list of indices
659// Return the number of particles put in the Message. This is for building
660// ghost particle interaction lists.
661template<class PLayout>
662size_t
664 const std::vector<size_t>& pl) {
665
666 // make sure we've been initialized
667 PAssert(Layout != 0);
668
669 std::vector<size_t>::size_type M = pl.size();
670 msg.put(M);
671
672 // go through all the attributes and put their data in the message
673 if (M > 0) {
674 attrib_container_t::iterator abeg = AttribList.begin();
675 attrib_container_t::iterator aend = AttribList.end();
676 for ( ; abeg != aend; ++abeg )
677 (*abeg)->ghostPutMessage(msg, pl);
678 }
679
680 return M;
681}
682
683
685// retrieve particles from the given message and sending node and store them
686template<class PLayout>
687size_t
689
690
691
692 // make sure we've been initialized
693 PAssert(Layout != 0);
694
695 // get the number of items in the message
696 size_t numitems;
697 msg.get(numitems);
698 GhostNum += numitems;
699
700 // go through all the attributes and get their data from the message
701 if (numitems > 0) {
702 attrib_container_t::iterator abeg = AttribList.begin();
703 attrib_container_t::iterator aend = AttribList.end();
704 for ( ; abeg != aend; abeg++ )
705 (*abeg)->ghostGetMessage(msg, numitems);
706 }
707
708 return numitems;
709}
710
711template<class PLayout>
712size_t
714
715 // make sure we've been initialized
716 PAssert(Layout != 0);
717
718 // get the number of items in the message
719 size_t numitems=1;
720 GhostNum += numitems;
721
722 // go through all the attributes and get their data from the message
723 if (numitems > 0) {
724 attrib_container_t::iterator abeg = AttribList.begin();
725 attrib_container_t::iterator aend = AttribList.end();
726 for ( ; abeg != aend; abeg++ )
727 (*abeg)->ghostGetMessage(msg, numitems);
728 }
729
730 return numitems;
731}
732
734// Apply the given sort-list to all the attributes. The sort-list
735// may be temporarily modified, thus it must be passed by non-const ref.
736template<class PLayout>
738 attrib_container_t::iterator abeg = AttribList.begin();
739 attrib_container_t::iterator aend = AttribList.end();
740 for ( ; abeg != aend; ++abeg )
741 (*abeg)->sort(sortlist);
742}
743
744
746// print it out
747template<class PLayout>
748std::ostream& operator<<(std::ostream& out, const IpplParticleBase<PLayout>& P) {
749
750
751 out << "Particle object contents:";
752 out << "\n Total particles: " << P.getTotalNum();
753 out << "\n Local particles: " << P.getLocalNum();
754 out << "\n Attributes (including R and ID): " << P.numAttributes();
755 out << "\n Layout = " << P.getLayout();
756 return out;
757}
758
759
761// print out debugging information
762template<class PLayout>
764
765 o << "PBase: total = " << getTotalNum() << ", local = " << getLocalNum();
766 o << ", attributes = " << AttribList.size() << endl;
767 for (attrib_container_t::size_type i=0; i < AttribList.size(); ++i) {
768 o << " ";
769 AttribList[i]->printDebug(o);
770 o << endl;
771 }
772 o << " ";
773 Layout->printDebug(o);
774}
const unsigned Dim
void putMessage(Message &m, const T &t)
Definition: Message.h:549
void getMessage(Message &m, T &t)
Definition: Message.h:572
const int COMM_ANY_NODE
Definition: Communicate.h:40
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
#define P_RESET_ID_TAG
Definition: Tags.h:85
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1111
std::ostream & operator<<(std::ostream &out, const IpplParticleBase< PLayout > &P)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define PAssert_LE(a, b)
Definition: PAssert.h:107
#define PAssert_LT(a, b)
Definition: PAssert.h:106
#define PAssert(c)
Definition: PAssert.h:102
#define ADDIPPLSTAT(stat, amount)
Definition: IpplStats.h:237
#define INCIPPLSTAT(stat)
Definition: IpplStats.h:236
std::string::iterator iterator
Definition: MSLang.h:16
size_t getMessageAndCreate(Message &)
PLayout & getLayout()
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)
size_t getMessage(Message &)
void sort(SortList_t &)
size_t putMessage(Message &, size_t, size_t)
virtual void update()
size_t writeMsgBuffer(MsgBuffer *&, const std::vector< size_t > &)
bool singleInitNode() const
ParticleAttribBase::SortList_t SortList_t
size_t writeMsgBufferWithOffsets(MsgBuffer *&, const std::vector< size_t > &, const std::vector< O > &)
attrib_container_t::size_type numAttributes() const
void printDebug(Inform &)
size_t getLocalNum() const
void globalCreate(size_t np)
size_t readGhostMsgBuffer(MsgBuffer *, int)
size_t ghostGetSingleMessage(Message &, int)
void createWithID(unsigned id)
void destroy(size_t, size_t, bool=false)
bool send(Message *, int node, int tag, bool delmsg=true)
Message * receive_block(int &node, int &tag)
int getNodes() const
Definition: Communicate.h:143
int myNode() const
Definition: Communicate.h:155
Definition: Format.h:27
Message & put(const T &val)
Definition: Message.h:406
Message & get(const T &cval)
Definition: Message.h:476
bool add(Message *)
Definition: MsgBuffer.cpp:44
Message * get()
Definition: MsgBuffer.cpp:71
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
Definition: Inform.h:42
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84