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