OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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"
24 #include "Utility/IpplException.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.
32 template<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
48 template<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 
77 template<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, ...
85 template<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.
95 template <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
178 template<class PLayout>
179 size_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);
187 
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
207 template<class PLayout>
208 size_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 
230 template<class PLayout>
231 size_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 
249 template<class PLayout>
251 {
252  //create dummy particle so we can obtain the format
253  bool wasempty = false;
254  if(this->getLocalNum()==0)
255  {
256  this->create(1);
257  wasempty = true;
258  }
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);
269 
270  return format;
271 }
272 
273 template<class PLayout>
274 size_t
275 IpplParticleBase<PLayout>::writeMsgBuffer(MsgBuffer *&msgbuf, const std::vector<size_t> &list)
276 {
277  msgbuf = new MsgBuffer(this->getFormat(), list.size());
278 
279  for (unsigned int i = 0;i<list.size();++i)
280  {
281  Message msg;
282  this->putMessage(msg, list[i]);
283  msgbuf->add(&msg);
284  }
285  return list.size();
286 }
287 
288 template<class PLayout>
289 template<class O>
290 size_t
291 IpplParticleBase<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;
308  }
309  return list.size();
310  }
311 
312 template<class PLayout>
313 size_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();
323  }
324  return added;
325 }
326 
327 
328 template<class PLayout>
329 size_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
345 template<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
368 template<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  }
384 
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.
393 template<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
409 template<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
436 template<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
464 template<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.
490 template<class PLayout>
491 void 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.
522 template<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.
539 template<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.
556 template<class PLayout>
557 void IpplParticleBase<PLayout>::performDestroy(bool updateLocalNum) {
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.
602 template<class PLayout>
603 void IpplParticleBase<PLayout>::ghostDestroy(size_t M, size_t I) {
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.
626 template<class PLayout>
627 size_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.
661 template<class PLayout>
662 size_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
686 template<class PLayout>
687 size_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 
711 template<class PLayout>
712 size_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.
736 template<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
747 template<class PLayout>
748 std::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
762 template<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
const int COMM_ANY_NODE
Definition: Communicate.h:40
void putMessage(Message &m, const T &t)
Definition: Message.h:549
void getMessage(Message &m, T &t)
Definition: Message.h:572
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
#define P_RESET_ID_TAG
Definition: Tags.h:85
std::ostream & operator<<(std::ostream &out, const IpplParticleBase< PLayout > &P)
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1111
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define ADDIPPLSTAT(stat, amount)
Definition: IpplStats.h:237
#define INCIPPLSTAT(stat)
Definition: IpplStats.h:236
#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
std::string::iterator iterator
Definition: MSLang.h:16
size_t getMessageAndCreate(Message &)
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()
PLayout & getLayout()
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