OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
ParticleSpatialLayout.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  ***************************************************************************/
7 
8 #ifndef PARTICLE_SPATIAL_LAYOUT_H
9 #define PARTICLE_SPATIAL_LAYOUT_H
10 
11 /*
12  * ParticleSpatialLayout - particle layout based on spatial decomposition.
13  *
14  * This is a specialized version of ParticleLayout, which places particles
15  * on processors based on their spatial location relative to a fixed grid.
16  * In particular, this can maintain particles on processors based on a
17  * specified FieldLayout or RegionLayout, so that particles are always on
18  * the same node as the node containing the Field region to which they are
19  * local. This may also be used if there is no associated Field at all,
20  * in which case a grid is selected based on an even distribution of
21  * particles among processors.
22  */
23 
24 // include files
27 #include "Region/RegionLayout.h"
28 #include "Message/Message.h"
29 #include "Message/Format.h"
30 #include "Message/MsgBuffer.h"
32 #include "Utility/IpplException.h"
33 
34 #include <cstddef>
35 
36 #include <functional>
37 #include <iostream>
38 #include <map>
39 #include <memory>
40 #include <vector>
41 
43 
44 #include <mpi.h>
45 
46 // forward declarations
47 class UserList;
48 template <class T> class ParticleAttrib;
49 template <unsigned Dim, class T> class UniformCartesian;
50 template <class T, unsigned Dim, class Mesh, class CachingPolicy> class ParticleSpatialLayout;
51 template <class T, unsigned Dim, class Mesh, class CachingPolicy>
52 std::ostream& operator<<(std::ostream&, const ParticleSpatialLayout<T,Dim,Mesh,CachingPolicy>&);
53 
54 // ParticleSpatialLayout class definition. Template parameters are the type
55 // and dimension of the ParticlePos object used for the particles. The
56 // dimension of the position must match the dimension of the FieldLayout
57 // object used in this particle layout, if any.
58 // Optional template parameter for the mesh type
59 template < class T, unsigned Dim, class Mesh=UniformCartesian<Dim,T>, class CachingPolicy=BoxParticleCachingPolicy<T,Dim,Mesh > >
60 class ParticleSpatialLayout : public ParticleLayout<T, Dim>,
61  public FieldLayoutUser, public CachingPolicy
62 {
63  /*
64  Enable cashing of particles. The size is
65  given in multiples of the mesh size in each dimension.
66  */
67 
68 public:
69  // pair iterator definition ... this layout does not allow for pairlists
70  typedef int pair_t;
75 
76  // type of attributes this layout should use for position and ID
80 
81 public:
82  // constructor: The Field layout to which we match our particle's
83  // locations.
85 
86  // constructor: this one also takes a Mesh
88 
89  // a similar constructor, but this one takes a RegionLayout.
91 
92  // a default constructor ... in this case, no layout will
93  // be assumed by this class. A layout may be given later via the
94  // 'setLayout' method, either as a FieldLayout or as a RegionLayout.
96 
97  // destructor
99 
100  //
101  // spatial decomposition layout information
102  //
103 
104  // retrieve a reference to the FieldLayout object in use. This may be used,
105  // e.g., to construct a Field with the same layout as the Particles. Note
106  // that if this object was constructed by providing a RegionLayout in the
107  // constructor, then this generated FieldLayout will not necessarily match
108  // up with the Region (it will be offset by some amount). But, if this
109  // object was either 1) created with a FieldLayout to begin with, or 2)
110  // created with no layout, and one was generated internally, then the
111  // returned FieldLayout will match and can be used to make new Fields or
112  // Particles.
114  {
115  return RLayout.getFieldLayout();
116  }
117 
118  // retrieve a reference to the RegionLayout object in use
120  {
121  return RLayout;
122  }
124  {
125  return RLayout;
126  }
127 
128  // get number of particles on a physical node
129  int getNodeCount(unsigned i) const
130  {
131  PAssert_LT(i, (unsigned int) Ippl::getNodes());
132  return NodeCount[i];
133  }
134 
135  // get flag for empty node domain
136  bool getEmptyNode(unsigned i) const
137  {
138  PAssert_LT(i, (unsigned int) Ippl::getNodes());
139  return EmptyNode[i];
140  }
141 
142  //
143  // Particle swapping/update routines
144  //
145 
146  // Update the location and indices of all atoms in the given IpplParticleBase
147  // object. This handles swapping particles among processors if
148  // needed, and handles create and destroy requests. When complete,
149  // all nodes have correct layout information.
151  const ParticleAttrib<char>* canSwap=0);
152 
153 
154  //
155  // I/O
156  //
157 
158  // Print out information for debugging purposes.
159  void printDebug(Inform&);
160 
161  //
162  // virtual functions for FieldLayoutUser's (and other UserList users)
163  //
164 
165  // Repartition onto a new layout
166  virtual void Repartition(UserList *);
167 
168  // Tell this object that an object is being deleted
169  virtual void notifyUserOfDelete(UserList *);
170 
171  void enableCaching() { caching = true; }
172  void disableCaching() { caching = false; }
173 
174 protected:
175  // The RegionLayout which determines where our particles go.
177 
178  // The number of particles located on each physical node.
179  size_t *NodeCount;
180 
181  // Flag for which nodes have no local domain
182  bool* EmptyNode;
183 
184  // a list of Message pointers used in swapping particles, and flags
185  // for which nodes expect messages in each dimension
188  unsigned NeighborNodes[Dim];
189  std::vector<size_t>* PutList;
190 
191  bool caching;
192 
193  // perform common constructor tasks
194  void setup();
195 
197  // Rebuild the RegionLayout entirely, by recalculating our min and max
198  // domains, adding a buffer region, and then giving this new Domain to
199  // our internal RegionLayout. When this is done, we must rebuild all
200  // our other data structures as well.
201  template < class PB >
202  void rebuild_layout(size_t haveLocal, PB& PData)
203  {
204  size_t i;
205  unsigned d; // loop variables
206 
207  //~ Inform dbgmsg("SpatialLayout::rebuild_layout", INFORM_ALL_NODES);
208  //~ dbgmsg << "rebuild..." << endl;
209  SingleParticlePos_t minpos = 0;
210  SingleParticlePos_t maxpos = 0;
213 
214  // if we have local particles, then find the min and max positions
215  if (haveLocal > 0)
216  {
217  minpos = PData.R[0];
218  maxpos = PData.R[0];
219  for (i=1; i < haveLocal; ++i)
220  {
221  for (d=0; d < Dim; ++d)
222  {
223  if (PData.R[i][d] < minpos[d])
224  minpos[d] = PData.R[i][d];
225  if (PData.R[i][d] > maxpos[d])
226  maxpos[d] = PData.R[i][d];
227  }
228  }
229  }
230 
231  // if we're not on node 0, send data to node 0
232  if (Ippl::myNode() != 0)
233  {
234  Message *msg = new Message;
235  msg->put(haveLocal);
236  if (haveLocal > 0)
237  {
238  minpos.putMessage(*msg);
239  maxpos.putMessage(*msg);
240  }
241  Ippl::Comm->send(msg, 0, tag);
242 
243  // now receive back min and max range as provided by the master node.
244  // These will include some buffer region, and will be integral values,
245  // so we can make a FieldLayout and use it to initialize the RegionLayout.
246  int node = 0;
247  msg = Ippl::Comm->receive_block(node, btag);
248  minpos.getMessage(*msg);
249  maxpos.getMessage(*msg);
250  delete msg;
251 
252  }
253  else // on node 0, collect data and compute region
254  {
255  SingleParticlePos_t tmpminpos;
256  SingleParticlePos_t tmpmaxpos;
257  size_t tmphaveLocal = 0;
258  unsigned unreceived = Ippl::getNodes() - 1;
259 
260  // collect data from other nodes
261  while (unreceived > 0)
262  {
263  int node = COMM_ANY_NODE;
264  Message *msg = Ippl::Comm->receive_block(node, tag);
265  msg->get(tmphaveLocal);
266  if (tmphaveLocal > 0)
267  {
268  tmpminpos.getMessage(*msg);
269  tmpmaxpos.getMessage(*msg);
270  for (i=0; i < Dim; ++i)
271  {
272  if (tmpminpos[i] < minpos[i])
273  minpos[i] = tmpminpos[i];
274  if (tmpmaxpos[i] > maxpos[i])
275  maxpos[i] = tmpmaxpos[i];
276  }
277  }
278  delete msg;
279  unreceived--;
280  }
281 
282  // adjust min and max to include a buffer region and fall on integral
283  // values
284  SingleParticlePos_t extrapos = (maxpos - minpos) * ((T)0.125);
285  maxpos += extrapos;
286  minpos -= extrapos;
287  for (i=0; i < Dim; ++i)
288  {
289  if (minpos[i] >= 0.0)
290  minpos[i] = (int)(minpos[i]);
291  else
292  minpos[i] = (int)(minpos[i] - 1);
293  maxpos[i] = (int)(maxpos[i] + 1);
294  }
295 
296  // send these values out to the other nodes
297  if (Ippl::getNodes() > 1)
298  {
299  Message *bmsg = new Message;
300  minpos.putMessage(*bmsg);
301  maxpos.putMessage(*bmsg);
302  Ippl::Comm->broadcast_others(bmsg, btag);
303  }
304  }
305 
306  // determine the size of the new domain, and the number of blocks into
307  // which it should be broken
308  NDIndex<Dim> range;
309  for (i=0; i < Dim; ++i)
310  range[i] = Index((int)(minpos[i]), (int)(maxpos[i]));
311  int vn = -1;
312  if (RLayout.initialized())
313  vn = RLayout.size_iv() + RLayout.size_rdv();
314 
315  // ask the RegionLayout to change the paritioning to match this size
316  // and block count. This will eventually end up by calling Repartition
317  // here, which will lead to rebuilding the neighbor data, etc., so we
318  // are done.
319  RLayout.changeDomain(range, vn);
320  }
321 
322  // swap particles to neighboring nodes if they have moved too far
323  // PB is the type of IpplParticleBase which should have it's layout rebuilt.
324  //mwerks template<class PB>
325  //mwerks unsigned swap_particles(unsigned, PB&);
327  // go through all our local particles, and send particles which must
328  // be swapped to another node to that node.
329  template < class PB >
330  size_t swap_particles(size_t LocalNum, PB& PData)
331  {
332 
333 //~ Inform dbgmsg("SpatialLayout::swap_particles", INFORM_ALL_NODES);
334  //~ dbgmsg << "swap..." << endl;
335 
336  Inform msg("ParticleSpatialLayout ERROR ", INFORM_ALL_NODES);
337 
338  unsigned d, i, j; // loop variables
339  size_t ip;
340  unsigned N = Ippl::getNodes();
341  unsigned myN = Ippl::myNode();
342 
343  // iterators used to search local domains
344  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
345 
346  // iterators used to search remote domains
347  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV; // remoteEnd = RLayout.end_rdv();
348 
349  // JCC: This "nudge factor" stuff was added when we were experiencing
350  // problems with particles getting lost in between PRegions on
351  // neighboring nodes. This problem has since been resolved by
352  // fixing the way in which PRegion boundaries are computed, so I am
353  // commenting this out for now. We can bring it back later if the
354  // need arises.
355 
356  /*
357 
358  // Calculate a 'nudge factor', an amount that can get added to a
359  // particle position to determine where it should be located. The nudge
360  // factor equals 1/100th the smallest width of the rnodes in each dimension.
361  // When we try to find where a particle is located, we check what vnode
362  // contains this particle 'nudge region', a box around the particle's pos
363  // of the size of the nudge factor.
364  T pNudge[Dim];
365  for (d=0; d < Dim; ++d) {
366  // initialize to the first rnode's width
367  T minval = (*(RLayout.begin_iv())).second->getDomain()[d].length();
368 
369  // check the local rnodes
370  for (localV = RLayout.begin_iv(); localV != localEnd; ++localV) {
371  T checkval = (*localV).second->getDomain()[d].length();
372  if (checkval < minval)
373  minval = checkval;
374  }
375 
376  // check the remote rnodes
377  for (remoteV = RLayout.begin_rdv(); remoteV != remoteEnd; ++remoteV) {
378  T checkval = (*remoteV).second->getDomain()[d].length();
379  if (checkval < minval)
380  minval = checkval;
381  }
382 
383  // now rescale the minval, and save it
384  pNudge[d] = 0.00001 * minval;
385  }
386 
387  */
388 
389  // An NDRegion object used to store a particle position.
390  NDRegion<T,Dim> pLoc;
391 
392  // get new message tag for particle exchange with empty domains
394 
395  if (!getEmptyNode(myN))
396  {
397 
398  // Particles are swapped in multipple passes, one for each dimension.
399  // The tasks completed here for each dimension are the following:
400  // 1. For each local Vnode, find the remote Vnodes which exist along
401  // same axis as the current axis (i.e. all Vnodes along the x-axis).
402  // 2. From this list, determine which nodes we send messages to.
403  // 3. Go through all the particles, finding those which have moved to
404  // an off-processor vnode, and store index in an array for that node
405  // 4. Send off the particles to the nodes (if no particles are
406  // going to a node, send them a message with 0 in it)
407  // 5. Delete the send particles from our local list
408  // 6. Receive particles sent to us by other nodes (some messages may
409  // say that we're receiving 0 particles from that node).
410 
411  // Initialize NDRegion with a position inside the first Vnode.
412  // We can skip dim 0, since it will be filled below.
413  for (d = 1; d < Dim; ++d)
414  {
415  T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
416  T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
417  T mid = first + 0.5 * (last - first);
418  pLoc[d] = PRegion<T>(mid, mid);
419  }
420 
421  for (d = 0; d < Dim; ++d)
422  {
423 
424  // get new message tag for particle exchange along this dimension
426 
427  // we only need to do the rest if there are other nodes in this dim
428  if (NeighborNodes[d] > 0)
429  {
430  // create new messages to send to our neighbors
431  for (i = 0; i < N; i++)
432  if (SwapNodeList[d][i])
433  SwapMsgList[i] = new Message;
434 
435  // Go through the particles and find those moving in the current dir.
436  // When one is found, copy it into outgoing message and delete it.
437  for (ip=0; ip<LocalNum; ++ip)
438  {
439  // get the position of particle ip, and find the closest grid pnt
440  // for just the dimensions 0 ... d
441  for (j = 0; j <= d; j++)
442  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
443 
444  // first check local domains (in this dimension)
445  bool foundit = false;
446  // JCC: int nudged = 0;
447  while (!foundit)
448  {
449  for (localV = RLayout.begin_iv();
450  localV != localEnd && !foundit; ++localV)
451  {
452  foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
453  }
454 
455  // if not found, it might be remote
456  if (!foundit)
457  {
458  // see which Vnode this postion is in
459  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
460  RLayout.touch_range_rdv(pLoc);
461 
462  // make sure we have a vnode to send it to
463  if (touchingVN.first == touchingVN.second)
464  {
465  // JCC: if (nudged >= Dim) {
466  ERRORMSG("Local particle " << ip << " with ID=");
467  ERRORMSG(PData.ID[ip] << " at ");
468  ERRORMSG(PData.R[ip] << " is outside of global domain ");
469  ERRORMSG(RLayout.getDomain() << endl);
470  ERRORMSG("This occurred when searching for point " << pLoc);
471  ERRORMSG(" in RegionLayout = " << RLayout << endl);
472  Ippl::abort();
473  }
474  else
475  {
476 
477  // the node has been found - add index to put list
478  unsigned node = (*(touchingVN.first)).second->getNode();
479  PAssert_EQ(SwapNodeList[d][node], true);
480  PutList[node].push_back(ip);
481 
482  // .. and then add to DestroyList
483  PData.destroy(1, ip);
484 
485  // indicate we found it to quit this check
486  foundit = true;
487  }
488  }
489  }
490  }
491 
492  // send the particles to their destination nodes
493  for (i = 0; i < N; i++)
494  {
495  if (SwapNodeList[d][i])
496  {
497  // put data for particles on this put list into message
498  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
499 
500  // add a final 'zero' number of particles to indicate the end
501  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
502 
503  // send the message
504  // Inform dbgmsg("SpatialLayout", INFORM_ALL_NODES);
505  //dbgmsg << "Swapping "<<PutList[i].size() << " particles to node ";
506  //dbgmsg << i<<" with tag " << tag << " (" << 'x' + d << ")" << endl;
507  //dbgmsg << " ... msg = " << *(SwapMsgList[i]) << endl;
508  int node = i;
509  Ippl::Comm->send(SwapMsgList[i], node, tag);
510 
511  // clear the list
512  PutList[i].erase(PutList[i].begin(), PutList[i].end());
513  }
514  }
515 
516  LocalNum -= PData.getDestroyNum(); // update local num
517  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
518  PData.performDestroy();
519 
520  // receive particles from neighbor nodes, and add them to our list
521  unsigned sendnum = NeighborNodes[d];
522  while (sendnum-- > 0)
523  {
524  int node = Communicate::COMM_ANY_NODE;
525  Message *recmsg = Ippl::Comm->receive_block(node, tag);
526  size_t recvd;
527  while ((recvd = PData.getMessage(*recmsg)) > 0)
528  LocalNum += recvd;
529  delete recmsg;
530  }
531  } // end if (NeighborNodes[d] > 0)
532 
533  if (d == 0)
534  {
535  // receive messages from any empty nodes
536  for (i = 0; i < N; ++i)
537  {
538  if (getEmptyNode(i))
539  {
540  int node = i;
541  Message *recmsg = Ippl::Comm->receive_block(node, etag);
542  size_t recvd;
543  while ((recvd = PData.getMessage(*recmsg)) > 0)
544  LocalNum += recvd;
545  delete recmsg;
546  }
547  }
548  }
549 
550  } // end for (d=0; d<Dim; ++d)
551 
552  }
553  else // empty node sends, but does not receive
554  {
555  msg << "case getEmptyNode(myN) " << endl;
556  // create new messages to send to our neighbors along dim 0
557  for (i = 0; i < N; i++)
558  if (SwapNodeList[0][i])
559  SwapMsgList[i] = new Message;
560 
561  // Go through the particles and find those moving to other nodes.
562  // When one is found, copy it into outgoing message and delete it.
563  for (ip=0; ip<LocalNum; ++ip)
564  {
565  // get the position of particle ip, and find the closest grid pnt
566  for (j = 0; j < Dim; j++)
567  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
568 
569  // see which remote Vnode this postion is in
570  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
571  RLayout.touch_range_rdv(pLoc);
572 
573  // make sure we have a vnode to send it to
574  if (touchingVN.first == touchingVN.second)
575  {
576  ERRORMSG("Local particle " << ip << " with ID=");
577  ERRORMSG(PData.ID[ip] << " at ");
578  ERRORMSG(PData.R[ip] << " is outside of global domain ");
579  ERRORMSG(RLayout.getDomain() << endl);
580  ERRORMSG("This occurred when searching for point " << pLoc);
581  ERRORMSG(" in RegionLayout = " << RLayout << endl);
582  Ippl::abort();
583  }
584  else
585  {
586  // the node has been found - add index to put list
587  unsigned node = (*(touchingVN.first)).second->getNode();
588  PAssert_EQ(SwapNodeList[0][node], true);
589  PutList[node].push_back(ip);
590 
591  // .. and then add to DestroyList
592  PData.destroy(1, ip);
593  }
594  }
595 
596  // send the particles to their destination nodes
597  for (i = 0; i < N; i++)
598  {
599  if (SwapNodeList[0][i])
600  {
601  // put data for particles on this put list into message
602  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
603 
604  // add a final 'zero' number of particles to indicate the end
605  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
606 
607  // send the message
608  int node = i;
609  Ippl::Comm->send(SwapMsgList[i], node, etag);
610 
611  // clear the list
612  PutList[i].erase(PutList[i].begin(), PutList[i].end());
613  }
614  }
615 
616  LocalNum -= PData.getDestroyNum(); // update local num
617  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
618  PData.performDestroy();
619 
620  }
621 
622  // return how many particles we have now
623  return LocalNum;
624  }
625 
626 
627 /*
628  * Simplified version for testing purposes.
629  */
630 
631  template < class PB >
632  size_t short_swap_particles(size_t LocalNum, PB& PData)
633  {
634  static int sent = 0, old_sent=0;
635 
636 
637  unsigned d, i, j; // loop variables
638  size_t ip;
639  unsigned N = Ippl::getNodes();
640 
641  // iterators used to search local domains
642  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
643 
644  // iterators used to search remote domains
645  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV; // remoteEnd = RLayout.end_rdv();
646 
647 
648  // An NDRegion object used to store a particle position.
649  NDRegion<T,Dim> pLoc;
650 
651  // Initialize NDRegion with a position inside the first Vnode.
652  // We can skip dim 0, since it will be filled below.
653  for (d = 1; d < Dim; ++d)
654  {
655  T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
656  T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
657  T mid = first + 0.5 * (last - first);
658  pLoc[d] = PRegion<T>(mid, mid);
659  }
660 
661  for (d = 0; d < Dim; ++d)
662  {
663 
664  // get new message tag for particle exchange along this dimension
666 
667  // we only need to do the rest if there are other nodes in this dim
668  if (NeighborNodes[d] > 0)
669  {
670  // create new messages to send to our neighbors
671  for (i = 0; i < N; i++)
672  if (SwapNodeList[d][i])
673  SwapMsgList[i] = new Message;
674 
675  // Go through the particles and find those moving in the current dir.
676  // When one is found, copy it into outgoing message and delete it.
677  for (ip=0; ip<LocalNum; ++ip)
678  {
679  // get the position of particle ip, and find the closest grid pnt
680  // for just the dimensions 0 ... d
681  for (j = 0; j <= d; j++)
682  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
683 
684  // first check local domains (in this dimension)
685  bool foundit = false;
686 
687  for (localV = RLayout.begin_iv();
688  localV != localEnd && !foundit; ++localV)
689  {
690  foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
691  }
692 
693  // if not found, it might be remote
694  if (!foundit)
695  {
696  // see which Vnode this postion is in
697  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
698  RLayout.touch_range_rdv(pLoc);
699 
700 
701  // the node has been found - add index to put list
702  unsigned node = (*(touchingVN.first)).second->getNode();
703  PAssert_EQ(SwapNodeList[d][node], true);
704  PutList[node].push_back(ip);
705 
706  // .. and then add to DestroyList
707  PData.destroy(1, ip);
708 
709  // indicate we found it to quit this check
710  foundit = true;
711  sent++;
712  }
713  }
714 
715  std::vector<MPI_Request> requests;
716  std::vector<MsgBuffer*> buffers;
717 
718  // send the particles to their destination nodes
719  for (i = 0; i < N; i++)
720  {
721  if (SwapNodeList[d][i])
722  {
723 
724  // put data for particles on this put list into message
725  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
726 
727  // add a final 'zero' number of particles to indicate the end
728  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
729 
730  int node = i;
731  Ippl::Comm->send(SwapMsgList[i], node, tag);
732 
733  // clear the list
734  PutList[i].erase(PutList[i].begin(), PutList[i].end());
735 
736 
737 
738  }
739  }
740 
741  LocalNum -= PData.getDestroyNum(); // update local num
742  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
743  PData.performDestroy();
744 
745  // receive particles from neighbor nodes, and add them to our list
746  unsigned sendnum = NeighborNodes[d];
747  while (sendnum-- > 0)
748  {
749  int node = Communicate::COMM_ANY_NODE;
750  Message *recmsg = Ippl::Comm->receive_block(node, tag);
751  size_t recvd;
752  while ((recvd = PData.getMessage(*recmsg)) > 0)
753  LocalNum += recvd;
754  delete recmsg;
755  }
756 
757  } // end if (NeighborNodes[d] > 0)
758 
759  } // end for (d=0; d<Dim; ++d)
760 
761  //std::cout << "node " << Ippl::myNode() << " sent particles " << sent - old_sent << std::endl;
762  old_sent = sent;
763 
764  // return how many particles we have now
765  return LocalNum;
766  }
767 
768 
769 
770 
771 
772  // PB is the type of IpplParticleBase which should have it's layout rebuilt.
773  //mwerks template<class PB>
774  //mwerks unsigned swap_particles(unsigned, PB&, const ParticleAttrib<char>&);
776  // go through all our local particles, and send particles which must
777  // be swapped to another node to that node.
778  template < class PB >
779  size_t swap_particles(size_t LocalNum, PB& PData,
780  const ParticleAttrib<char>& canSwap)
781  {
782 
783  unsigned d, i, j; // loop variables
784  size_t ip;
785  unsigned N = Ippl::getNodes();
786  unsigned myN = Ippl::myNode();
787 
788  // iterators used to search local domains
789  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
790 
791  // iterators used to search remote domains
792  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV; // remoteEnd = RLayout.end_rdv();
793 
794  // JCC: This "nudge factor" stuff was added when we were experiencing
795  // problems with particles getting lost in between PRegions on
796  // neighboring nodes. This problem has since been resolved by
797  // fixing the way in which PRegion boundaries are computed, so I am
798  // commenting this out for now. We can bring it back later if the
799  // need arises.
800 
801  /*
802 
803  // Calculate a 'nudge factor', an amount that can get added to a
804  // particle position to determine where it should be located. The nudge
805  // factor equals 1/100th the smallest width of the rnodes in each dimension.
806  // When we try to find where a particle is located, we check what vnode
807  // contains this particle 'nudge region', a box around the particle's pos
808  // of the size of the nudge factor.
809  T pNudge[Dim];
810  for (d=0; d < Dim; ++d) {
811  // initialize to the first rnode's width
812  T minval = (*(RLayout.begin_iv())).second->getDomain()[d].length();
813 
814  // check the local rnodes
815  for (localV = RLayout.begin_iv(); localV != localEnd; ++localV) {
816  T checkval = (*localV).second->getDomain()[d].length();
817  if (checkval < minval)
818  minval = checkval;
819  }
820 
821  // check the remote rnodes
822  for (remoteV = RLayout.begin_rdv(); remoteV != remoteEnd; ++remoteV) {
823  T checkval = (*remoteV).second->getDomain()[d].length();
824  if (checkval < minval)
825  minval = checkval;
826  }
827 
828  // now rescale the minval, and save it
829  pNudge[d] = 0.00001 * minval;
830  }
831 
832  */
833 
834  // An NDRegion object used to store a particle position.
835  NDRegion<T,Dim> pLoc;
836 
837  // get new message tag for particle exchange with empty domains
839 
840  if (!getEmptyNode(myN))
841  {
842 
843  // Particles are swapped in multipple passes, one for each dimension.
844  // The tasks completed here for each dimension are the following:
845  // 1. For each local Vnode, find the remote Vnodes which exist along
846  // same axis as the current axis (i.e. all Vnodes along the x-axis).
847  // 2. From this list, determine which nodes we send messages to.
848  // 3. Go through all the particles, finding those which have moved to
849  // an off-processor vnode, and store index in an array for that node
850  // 4. Send off the particles to the nodes (if no particles are
851  // going to a node, send them a message with 0 in it)
852  // 5. Delete the send particles from our local list
853  // 6. Receive particles sent to us by other nodes (some messages may
854  // say that we're receiving 0 particles from that node).
855 
856  // Initialize NDRegion with a position inside the first Vnode.
857  // We can skip dim 0, since it will be filled below.
858  for (d = 1; d < Dim; ++d)
859  {
860  T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
861  T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
862  T mid = first + 0.5 * (last - first);
863  pLoc[d] = PRegion<T>(mid, mid);
864  }
865 
866  for (d = 0; d < Dim; ++d)
867  {
868 
869  // get new message tag for particle exchange along this dimension
871 
872  // we only need to do the rest if there are other nodes in this dim
873  if (NeighborNodes[d] > 0)
874  {
875  // create new messages to send to our neighbors
876  for (i = 0; i < N; i++)
877  if (SwapNodeList[d][i])
878  SwapMsgList[i] = new Message;
879 
880  // Go through the particles and find those moving in the current dir.
881  // When one is found, copy it into outgoing message and delete it.
882  for (ip=0; ip<LocalNum; ++ip)
883  {
884  if (!bool(canSwap[ip])) continue; // skip if can't swap
885  // get the position of particle ip, and find the closest grid pnt
886  // for just the dimensions 0 ... d
887  for (j = 0; j <= d; j++)
888  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
889 
890  // first check local domains (in this dimension)
891  bool foundit = false;
892  // JCC: int nudged = 0;
893  while (!foundit)
894  {
895  for (localV = RLayout.begin_iv();
896  localV != localEnd && !foundit; ++localV)
897  {
898  foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
899  }
900 
901  // if not found, it might be remote
902  if (!foundit)
903  {
904  // see which Vnode this postion is in
905  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
906  RLayout.touch_range_rdv(pLoc);
907 
908  // make sure we have a vnode to send it to
909  if (touchingVN.first == touchingVN.second)
910  {
911  // JCC: if (nudged >= Dim) {
912  ERRORMSG("Local particle " << ip << " with ID=");
913  ERRORMSG(PData.ID[ip] << " at ");
914  ERRORMSG(PData.R[ip] << " is outside of global domain ");
915  ERRORMSG(RLayout.getDomain() << endl);
916  ERRORMSG("This occurred when searching for point " << pLoc);
917  ERRORMSG(" in RegionLayout = " << RLayout << endl);
918  Ippl::abort();
919  }
920  else
921  {
922  // the node has been found - add index to put list
923  unsigned node = (*(touchingVN.first)).second->getNode();
924  PAssert_EQ(SwapNodeList[d][node], true);
925  PutList[node].push_back(ip);
926 
927  // .. and then add to DestroyList
928  PData.destroy(1, ip);
929 
930  // indicate we found it to quit this check
931  foundit = true;
932  }
933  }
934  }
935  }
936 
937  // send the particles to their destination nodes
938  for (i = 0; i < N; i++)
939  {
940  if (SwapNodeList[d][i])
941  {
942  // put data for particles on this put list into message
943  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
944 
945  // add a final 'zero' number of particles to indicate the end
946  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
947 
948  // send the message
949  //Inform dbgmsg("SpatialLayout", INFORM_ALL_NODES);
950  //dbgmsg << "Swapping "<<PutList[i].size() << " particles to node ";
951  //dbgmsg << i<<" with tag " << tag << " (" << 'x' + d << ")" << endl;
952  //dbgmsg << " ... msg = " << *(SwapMsgList[i]) << endl;
953  int node = i;
954  Ippl::Comm->send(SwapMsgList[i], node, tag);
955 
956  // clear the list
957  PutList[i].erase(PutList[i].begin(), PutList[i].end());
958  }
959  }
960 
961  LocalNum -= PData.getDestroyNum(); // update local num
962  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
963  PData.performDestroy();
964 
965  // receive particles from neighbor nodes, and add them to our list
966  unsigned sendnum = NeighborNodes[d];
967  while (sendnum-- > 0)
968  {
969  int node = Communicate::COMM_ANY_NODE;
970  Message *recmsg = Ippl::Comm->receive_block(node, tag);
971  size_t recvd;
972  while ((recvd = PData.getMessage(*recmsg)) > 0)
973  LocalNum += recvd;
974  delete recmsg;
975  }
976  } // end if (NeighborNodes[d] > 0)
977 
978  if (d == 0)
979  {
980  // receive messages from any empty nodes
981  for (i = 0; i < N; ++i)
982  {
983  if (getEmptyNode(i))
984  {
985  int node = i;
986  Message *recmsg = Ippl::Comm->receive_block(node, etag);
987  size_t recvd;
988  while ((recvd = PData.getMessage(*recmsg)) > 0)
989  LocalNum += recvd;
990  delete recmsg;
991  }
992  }
993  }
994 
995  } // end for (d=0; d<Dim; ++d)
996 
997  }
998  else // empty node sends, but does not receive
999  {
1000  // create new messages to send to our neighbors along dim 0
1001  for (i = 0; i < N; i++)
1002  if (SwapNodeList[0][i])
1003  SwapMsgList[i] = new Message;
1004 
1005  // Go through the particles and find those moving to other nodes.
1006  // When one is found, copy it into outgoing message and delete it.
1007  for (ip=0; ip<LocalNum; ++ip)
1008  {
1009  if (!bool(canSwap[ip])) continue; // skip if can't swap
1010  // get the position of particle ip, and find the closest grid pnt
1011  for (j = 0; j < Dim; j++)
1012  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
1013 
1014  // see which remote Vnode this postion is in
1015  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
1016  RLayout.touch_range_rdv(pLoc);
1017 
1018  // make sure we have a vnode to send it to
1019  if (touchingVN.first == touchingVN.second)
1020  {
1021  ERRORMSG("Local particle " << ip << " with ID=");
1022  ERRORMSG(PData.ID[ip] << " at ");
1023  ERRORMSG(PData.R[ip] << " is outside of global domain ");
1024  ERRORMSG(RLayout.getDomain() << endl);
1025  ERRORMSG("This occurred when searching for point " << pLoc);
1026  ERRORMSG(" in RegionLayout = " << RLayout << endl);
1027  Ippl::abort();
1028  }
1029  else
1030  {
1031  // the node has been found - add index to put list
1032  unsigned node = (*(touchingVN.first)).second->getNode();
1033  PAssert_EQ(SwapNodeList[0][node], true);
1034  PutList[node].push_back(ip);
1035 
1036  // .. and then add to DestroyList
1037  PData.destroy(1, ip);
1038  }
1039  }
1040 
1041  // send the particles to their destination nodes
1042  for (i = 0; i < N; i++)
1043  {
1044  if (SwapNodeList[0][i])
1045  {
1046  // put data for particles on this put list into message
1047  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
1048 
1049  // add a final 'zero' number of particles to indicate the end
1050  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
1051 
1052  // send the message
1053  int node = i;
1054  Ippl::Comm->send(SwapMsgList[i], node, etag);
1055 
1056  // clear the list
1057  PutList[i].erase(PutList[i].begin(), PutList[i].end());
1058  }
1059  }
1060 
1061  LocalNum -= PData.getDestroyNum(); // update local num
1062  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
1063  PData.performDestroy();
1064 
1065  }
1066 
1067  // return how many particles we have now
1068  return LocalNum;
1069  }
1070 
1071 
1072 
1073 
1074 /*
1075  * Newer (cleaner) version of swap particles that uses less bandwidth
1076  * and drastically lowers message counts for real cases.
1077  */
1078  template < class PB >
1079  size_t new_swap_particles(size_t LocalNum, PB& PData)
1080  {
1081  Ippl::Comm->barrier();
1082  static int sent = 0;
1083 
1084  unsigned N = Ippl::getNodes();
1085  unsigned myN = Ippl::myNode();
1086 
1087  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
1088  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV;
1089 
1090  std::vector<int> msgsend(N, 0);
1091  std::vector<int> msgrecv(N, 0);
1092 
1093  NDRegion<T,Dim> pLoc;
1094 
1095  std::multimap<unsigned, unsigned> p2n; //<node ID, particle ID>
1096 
1097  int particlesLeft = LocalNum;
1098  bool responsibleNodeNotFound = false;
1099  for (unsigned int ip=0; ip<LocalNum; ++ip)
1100  {
1101  for (unsigned int j = 0; j < Dim; j++)
1102  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
1103 
1104  unsigned destination = myN;
1105  bool found = false;
1106  for (localV = RLayout.begin_iv(); localV != localEnd && !found; ++localV)
1107  {
1108  if ((((*localV).second)->getDomain()).touches(pLoc))
1109  found = true; // particle is local and doesn't need to be sent anywhere
1110  }
1111 
1112  if (found)
1113  continue;
1114 
1115  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN = RLayout.touch_range_rdv(pLoc);
1116 
1117  //external location
1118  if (touchingVN.first == touchingVN.second) {
1119  responsibleNodeNotFound = true;
1120  break;
1121  }
1122  destination = (*(touchingVN.first)).second->getNode();
1123 
1124  msgsend[destination] = 1;
1125 
1126  p2n.insert(std::pair<unsigned, unsigned>(destination, ip));
1127  sent++;
1128  particlesLeft--;
1129  }
1130 
1131  allreduce(&responsibleNodeNotFound,
1132  1,
1133  std::logical_or<bool>());
1134 
1135  if (responsibleNodeNotFound) {
1136  throw IpplException("ParticleSpatialLayout::new_swap_particles",
1137  "could not find node responsible for particle");
1138  }
1139 
1140  //reduce message count so every node knows how many messages to receive
1141  allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
1142 
1144 
1145  typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
1146 
1147  std::unique_ptr<Format> format(PData.getFormat());
1148 
1149 
1150  std::vector<MPI_Request> requests;
1151  std::vector<std::shared_ptr<MsgBuffer> > buffers;
1152 
1153  while (i!=p2n.end())
1154  {
1155  unsigned cur_destination = i->first;
1156 
1157  std::shared_ptr<MsgBuffer> msgbuf(new MsgBuffer(format.get(), p2n.count(i->first)));
1158 
1159  for (; i!=p2n.end() && i->first == cur_destination; ++i)
1160  {
1161  Message msg;
1162  PData.putMessage(msg, i->second);
1163  PData.destroy(1, i->second);
1164  msgbuf->add(&msg);
1165  }
1166 
1167  MPI_Request request = Ippl::Comm->raw_isend( msgbuf->getBuffer(), msgbuf->getSize(), cur_destination, tag);
1168 
1169  //remember request and buffer so we can delete them later
1170  requests.push_back(request);
1171  buffers.push_back(msgbuf);
1172  }
1173 
1174  LocalNum -= PData.getDestroyNum(); // update local num
1175  PData.performDestroy();
1176 
1177  //receive new particles
1178  for (int k = 0; k<msgrecv[myN]; ++k)
1179  {
1180  int node = Communicate::COMM_ANY_NODE;
1181  char *buffer = 0;
1182  int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
1183  MsgBuffer recvbuf(format.get(), buffer, bufsize);
1184 
1185  Message *msg = recvbuf.get();
1186  while (msg != 0)
1187  {
1188  LocalNum += PData.getSingleMessage(*msg);
1189  delete msg;
1190  msg = recvbuf.get();
1191  }
1192 
1193 
1194  }
1195 
1196  //wait for communication to finish and clean up buffers
1197  MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
1198  MPI_Waitall(requests.size(), requests_ptr, MPI_STATUSES_IGNORE);
1199 
1200  return LocalNum;
1201  }
1202 
1203  template < class PB >
1204  size_t new_swap_particles(size_t LocalNum, PB& PData,
1205  const ParticleAttrib<char>& canSwap)
1206  {
1207  Ippl::Comm->barrier();
1208  static int sent = 0;
1209 
1210  unsigned N = Ippl::getNodes();
1211  unsigned myN = Ippl::myNode();
1212 
1213  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
1214  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV;
1215 
1216  std::vector<int> msgsend(N, 0);
1217  std::vector<int> msgrecv(N, 0);
1218 
1219  NDRegion<T,Dim> pLoc;
1220 
1221  std::multimap<unsigned, unsigned> p2n; //<node ID, particle ID>
1222 
1223  int particlesLeft = LocalNum;
1224  bool responsibleNodeNotFound = false;
1225  for (unsigned int ip=0; ip<LocalNum; ++ip)
1226  {
1227  if (!bool(canSwap[ip]))//skip if it can't be swapped
1228  continue;
1229 
1230  for (unsigned int j = 0; j < Dim; j++)
1231  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
1232 
1233  unsigned destination = myN;
1234  bool found = false;
1235  for (localV = RLayout.begin_iv(); localV != localEnd && !found; ++localV)
1236  {
1237  if ((((*localV).second)->getDomain()).touches(pLoc))
1238  found = true; // particle is local and doesn't need to be sent anywhere
1239  }
1240 
1241  if (found)
1242  continue;
1243 
1244  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN = RLayout.touch_range_rdv(pLoc);
1245 
1246  //external location
1247  if (touchingVN.first == touchingVN.second) {
1248  responsibleNodeNotFound = true;
1249  break;
1250  }
1251  destination = (*(touchingVN.first)).second->getNode();
1252 
1253  msgsend[destination] = 1;
1254 
1255  p2n.insert(std::pair<unsigned, unsigned>(destination, ip));
1256  sent++;
1257  particlesLeft--;
1258  }
1259 
1260  allreduce(&responsibleNodeNotFound,
1261  1,
1262  std::logical_or<bool>());
1263 
1264  if (responsibleNodeNotFound) {
1265  throw IpplException("ParticleSpatialLayout::new_swap_particles",
1266  "could not find node responsible for particle");
1267  }
1268 
1269  //reduce message count so every node knows how many messages to receive
1270  allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
1271 
1273 
1274  typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
1275 
1276  std::unique_ptr<Format> format(PData.getFormat());
1277 
1278  std::vector<MPI_Request> requests;
1279  std::vector<std::shared_ptr<MsgBuffer> > buffers;
1280 
1281  while (i!=p2n.end())
1282  {
1283  unsigned cur_destination = i->first;
1284 
1285  std::shared_ptr<MsgBuffer> msgbuf(new MsgBuffer(format.get(), p2n.count(i->first)));
1286 
1287  for (; i!=p2n.end() && i->first == cur_destination; ++i)
1288  {
1289  Message msg;
1290  PData.putMessage(msg, i->second);
1291  PData.destroy(1, i->second);
1292  msgbuf->add(&msg);
1293  }
1294 
1295  MPI_Request request = Ippl::Comm->raw_isend( msgbuf->getBuffer(), msgbuf->getSize(), cur_destination, tag);
1296 
1297  //remember request and buffer so we can delete them later
1298  requests.push_back(request);
1299  buffers.push_back(msgbuf);
1300  }
1301 
1302  LocalNum -= PData.getDestroyNum(); // update local num
1303  PData.performDestroy();
1304 
1305  //receive new particles
1306  for (int k = 0; k<msgrecv[myN]; ++k)
1307  {
1308  int node = Communicate::COMM_ANY_NODE;
1309  char *buffer = 0;
1310  int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
1311  MsgBuffer recvbuf(format.get(), buffer, bufsize);
1312 
1313  Message *msg = recvbuf.get();
1314  while (msg != 0)
1315  {
1316  LocalNum += PData.getSingleMessage(*msg);
1317  delete msg;
1318  msg = recvbuf.get();
1319  }
1320  }
1321 
1322  //wait for communication to finish and clean up buffers
1323  MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
1324  MPI_Waitall(requests.size(), requests_ptr, 0);
1325 
1326  return LocalNum;
1327  }
1328 
1329 };
1330 
1332 
1333 #endif // PARTICLE_SPATIAL_LAYOUT_H
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
PartBunchBase< T, Dim >::ConstIterator begin(PartBunchBase< T, Dim > const &bunch)
const unsigned Dim
const int COMM_ANY_NODE
Definition: Communicate.h:40
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
#define P_SPATIAL_TRANSFER_TAG
Definition: Tags.h:82
#define P_SPATIAL_RANGE_TAG
Definition: Tags.h:84
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
#define P_SPATIAL_RETURN_TAG
Definition: Tags.h:81
std::ostream & operator<<(std::ostream &, const ParticleSpatialLayout< T, Dim, Mesh, CachingPolicy > &)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFORM_ALL_NODES
Definition: Inform.h:39
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
#define ADDIPPLSTAT(stat, amount)
Definition: IpplStats.h:237
#define PAssert_LT(a, b)
Definition: PAssert.h:106
#define PAssert_EQ(a, b)
Definition: PAssert.h:104
std::string::iterator iterator
Definition: MSLang.h:16
Message & putMessage(Message &m) const
Definition: Vektor.h:174
Message & getMessage(Message &m)
Definition: Vektor.h:180
Definition: Index.h:237
Definition: Mesh.h:35
virtual MPI_Request raw_isend(void *, int, int, int)
Definition: Communicate.h:196
bool send(Message *, int node, int tag, bool delmsg=true)
virtual int raw_probe_receive(char *&, int &, int &)
Definition: Communicate.h:208
virtual int broadcast_others(Message *, int, bool delmsg=true)
Message * receive_block(int &node, int &tag)
void barrier(void)
Message & put(const T &val)
Definition: Message.h:406
bool empty() const
Definition: Message.h:300
Message & get(const T &cval)
Definition: Message.h:476
Message * get()
Definition: MsgBuffer.cpp:71
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
int getNodeCount(unsigned i) const
void rebuild_layout(size_t haveLocal, PB &PData)
ParticleAttrib< Index_t > ParticleIndex_t
ParticleAttrib< SingleParticlePos_t > ParticlePos_t
bool getEmptyNode(unsigned i) const
RegionLayout< T, Dim, Mesh > & getLayout()
ParticleLayout< T, Dim >::Index_t Index_t
virtual void Repartition(UserList *)
virtual void notifyUserOfDelete(UserList *)
RegionLayout< T, Dim, Mesh > RLayout
void update(IpplParticleBase< ParticleSpatialLayout< T, Dim, Mesh, CachingPolicy > > &p, const ParticleAttrib< char > *canSwap=0)
size_t new_swap_particles(size_t LocalNum, PB &PData, const ParticleAttrib< char > &canSwap)
size_t new_swap_particles(size_t LocalNum, PB &PData)
std::vector< size_t > * PutList
size_t swap_particles(size_t LocalNum, PB &PData)
size_t short_swap_particles(size_t LocalNum, PB &PData)
FieldLayout< Dim > & getFieldLayout()
ParticleLayout< T, Dim >::SingleParticlePos_t SingleParticlePos_t
RegionLayout< T, Dim, Mesh > RegionLayout_t
const RegionLayout< T, Dim, Mesh > & getLayout() const
size_t swap_particles(size_t LocalNum, PB &PData, const ParticleAttrib< char > &canSwap)
unsigned Index_t
ac_id_vnodes::iterator iterator_iv
Definition: RegionLayout.h:66
std::pair< touch_iterator_dv, touch_iterator_dv > touch_range_dv
Definition: RegionLayout.h:71
Definition: Inform.h:42
static void abort(const char *=0)
Definition: IpplInfo.cpp:616
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84