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