OPAL (Object Oriented Parallel Accelerator Library)  2024.1
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 ");
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 ");
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  unsigned d, i, j; // loop variables
635  size_t ip;
636  unsigned N = Ippl::getNodes();
637 
638  // iterators used to search local domains
639  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
640 
641  // iterators used to search remote domains
642  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV; // remoteEnd = RLayout.end_rdv();
643 
644 
645  // An NDRegion object used to store a particle position.
646  NDRegion<T,Dim> pLoc;
647 
648  // Initialize NDRegion with a position inside the first Vnode.
649  // We can skip dim 0, since it will be filled below.
650  for (d = 1; d < Dim; ++d)
651  {
652  T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
653  T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
654  T mid = first + 0.5 * (last - first);
655  pLoc[d] = PRegion<T>(mid, mid);
656  }
657 
658  for (d = 0; d < Dim; ++d)
659  {
660 
661  // get new message tag for particle exchange along this dimension
663 
664  // we only need to do the rest if there are other nodes in this dim
665  if (NeighborNodes[d] > 0)
666  {
667  // create new messages to send to our neighbors
668  for (i = 0; i < N; i++)
669  if (SwapNodeList[d][i])
670  SwapMsgList[i] = new Message;
671 
672  // Go through the particles and find those moving in the current dir.
673  // When one is found, copy it into outgoing message and delete it.
674  for (ip=0; ip<LocalNum; ++ip)
675  {
676  // get the position of particle ip, and find the closest grid pnt
677  // for just the dimensions 0 ... d
678  for (j = 0; j <= d; j++)
679  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
680 
681  // first check local domains (in this dimension)
682  bool foundit = false;
683 
684  for (localV = RLayout.begin_iv();
685  localV != localEnd && !foundit; ++localV)
686  {
687  foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
688  }
689 
690  // if not found, it might be remote
691  if (!foundit)
692  {
693  // see which Vnode this postion is in
694  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
695  RLayout.touch_range_rdv(pLoc);
696 
697 
698  // the node has been found - add index to put list
699  unsigned node = (*(touchingVN.first)).second->getNode();
700  PAssert_EQ(SwapNodeList[d][node], true);
701  PutList[node].push_back(ip);
702 
703  // .. and then add to DestroyList
704  PData.destroy(1, ip);
705 
706  // indicate we found it to quit this check
707  foundit = true;
708  }
709  }
710 
711  std::vector<MPI_Request> requests;
712  std::vector<MsgBuffer*> buffers;
713 
714  // send the particles to their destination nodes
715  for (i = 0; i < N; i++)
716  {
717  if (SwapNodeList[d][i])
718  {
719 
720  // put data for particles on this put list into message
721  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
722 
723  // add a final 'zero' number of particles to indicate the end
724  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
725 
726  int node = i;
727  Ippl::Comm->send(SwapMsgList[i], node, tag);
728 
729  // clear the list
730  PutList[i].erase(PutList[i].begin(), PutList[i].end());
731 
732 
733 
734  }
735  }
736 
737  LocalNum -= PData.getDestroyNum(); // update local num
738  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
739  PData.performDestroy();
740 
741  // receive particles from neighbor nodes, and add them to our list
742  unsigned sendnum = NeighborNodes[d];
743  while (sendnum-- > 0)
744  {
745  int node = Communicate::COMM_ANY_NODE;
746  Message *recmsg = Ippl::Comm->receive_block(node, tag);
747  size_t recvd;
748  while ((recvd = PData.getMessage(*recmsg)) > 0)
749  LocalNum += recvd;
750  delete recmsg;
751  }
752 
753  } // end if (NeighborNodes[d] > 0)
754 
755  } // end for (d=0; d<Dim; ++d)
756 
757 
758  // return how many particles we have now
759  return LocalNum;
760  }
761 
762 
763 
764 
765 
766  // PB is the type of IpplParticleBase which should have it's layout rebuilt.
767  //mwerks template<class PB>
768  //mwerks unsigned swap_particles(unsigned, PB&, const ParticleAttrib<char>&);
770  // go through all our local particles, and send particles which must
771  // be swapped to another node to that node.
772  template < class PB >
773  size_t swap_particles(size_t LocalNum, PB& PData,
774  const ParticleAttrib<char>& canSwap)
775  {
776 
777  unsigned d, i, j; // loop variables
778  size_t ip;
779  unsigned N = Ippl::getNodes();
780  unsigned myN = Ippl::myNode();
781 
782  // iterators used to search local domains
783  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
784 
785  // iterators used to search remote domains
786  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV; // remoteEnd = RLayout.end_rdv();
787 
788  // JCC: This "nudge factor" stuff was added when we were experiencing
789  // problems with particles getting lost in between PRegions on
790  // neighboring nodes. This problem has since been resolved by
791  // fixing the way in which PRegion boundaries are computed, so I am
792  // commenting this out for now. We can bring it back later if the
793  // need arises.
794 
795  /*
796 
797  // Calculate a 'nudge factor', an amount that can get added to a
798  // particle position to determine where it should be located. The nudge
799  // factor equals 1/100th the smallest width of the rnodes in each dimension.
800  // When we try to find where a particle is located, we check what vnode
801  // contains this particle 'nudge region', a box around the particle's pos
802  // of the size of the nudge factor.
803  T pNudge[Dim];
804  for (d=0; d < Dim; ++d) {
805  // initialize to the first rnode's width
806  T minval = (*(RLayout.begin_iv())).second->getDomain()[d].length();
807 
808  // check the local rnodes
809  for (localV = RLayout.begin_iv(); localV != localEnd; ++localV) {
810  T checkval = (*localV).second->getDomain()[d].length();
811  if (checkval < minval)
812  minval = checkval;
813  }
814 
815  // check the remote rnodes
816  for (remoteV = RLayout.begin_rdv(); remoteV != remoteEnd; ++remoteV) {
817  T checkval = (*remoteV).second->getDomain()[d].length();
818  if (checkval < minval)
819  minval = checkval;
820  }
821 
822  // now rescale the minval, and save it
823  pNudge[d] = 0.00001 * minval;
824  }
825 
826  */
827 
828  // An NDRegion object used to store a particle position.
829  NDRegion<T,Dim> pLoc;
830 
831  // get new message tag for particle exchange with empty domains
833 
834  if (!getEmptyNode(myN))
835  {
836 
837  // Particles are swapped in multipple passes, one for each dimension.
838  // The tasks completed here for each dimension are the following:
839  // 1. For each local Vnode, find the remote Vnodes which exist along
840  // same axis as the current axis (i.e. all Vnodes along the x-axis).
841  // 2. From this list, determine which nodes we send messages to.
842  // 3. Go through all the particles, finding those which have moved to
843  // an off-processor vnode, and store index in an array for that node
844  // 4. Send off the particles to the nodes (if no particles are
845  // going to a node, send them a message with 0 in it)
846  // 5. Delete the send particles from our local list
847  // 6. Receive particles sent to us by other nodes (some messages may
848  // say that we're receiving 0 particles from that node).
849 
850  // Initialize NDRegion with a position inside the first Vnode.
851  // We can skip dim 0, since it will be filled below.
852  for (d = 1; d < Dim; ++d)
853  {
854  T first = (*(RLayout.begin_iv())).second->getDomain()[d].first();
855  T last = (*(RLayout.begin_iv())).second->getDomain()[d].last();
856  T mid = first + 0.5 * (last - first);
857  pLoc[d] = PRegion<T>(mid, mid);
858  }
859 
860  for (d = 0; d < Dim; ++d)
861  {
862 
863  // get new message tag for particle exchange along this dimension
865 
866  // we only need to do the rest if there are other nodes in this dim
867  if (NeighborNodes[d] > 0)
868  {
869  // create new messages to send to our neighbors
870  for (i = 0; i < N; i++)
871  if (SwapNodeList[d][i])
872  SwapMsgList[i] = new Message;
873 
874  // Go through the particles and find those moving in the current dir.
875  // When one is found, copy it into outgoing message and delete it.
876  for (ip=0; ip<LocalNum; ++ip)
877  {
878  if (!bool(canSwap[ip])) continue; // skip if can't swap
879  // get the position of particle ip, and find the closest grid pnt
880  // for just the dimensions 0 ... d
881  for (j = 0; j <= d; j++)
882  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
883 
884  // first check local domains (in this dimension)
885  bool foundit = false;
886  // JCC: int nudged = 0;
887  while (!foundit)
888  {
889  for (localV = RLayout.begin_iv();
890  localV != localEnd && !foundit; ++localV)
891  {
892  foundit= (((*localV).second)->getDomain())[d].touches(pLoc[d]);
893  }
894 
895  // if not found, it might be remote
896  if (!foundit)
897  {
898  // see which Vnode this postion is in
899  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
900  RLayout.touch_range_rdv(pLoc);
901 
902  // make sure we have a vnode to send it to
903  if (touchingVN.first == touchingVN.second)
904  {
905  // JCC: if (nudged >= Dim) {
906  ERRORMSG("Local particle " << ip << " with ID=");
907  ERRORMSG(PData.ID[ip] << " at ");
908  ERRORMSG(PData.R[ip] << " is outside of global domain ");
910  ERRORMSG("This occurred when searching for point " << pLoc);
911  ERRORMSG(" in RegionLayout = " << RLayout << endl);
912  Ippl::abort();
913  }
914  else
915  {
916  // the node has been found - add index to put list
917  unsigned node = (*(touchingVN.first)).second->getNode();
918  PAssert_EQ(SwapNodeList[d][node], true);
919  PutList[node].push_back(ip);
920 
921  // .. and then add to DestroyList
922  PData.destroy(1, ip);
923 
924  // indicate we found it to quit this check
925  foundit = true;
926  }
927  }
928  }
929  }
930 
931  // send the particles to their destination nodes
932  for (i = 0; i < N; i++)
933  {
934  if (SwapNodeList[d][i])
935  {
936  // put data for particles on this put list into message
937  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
938 
939  // add a final 'zero' number of particles to indicate the end
940  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
941 
942  // send the message
943  //Inform dbgmsg("SpatialLayout", INFORM_ALL_NODES);
944  //dbgmsg << "Swapping "<<PutList[i].size() << " particles to node ";
945  //dbgmsg << i<<" with tag " << tag << " (" << 'x' + d << ")" << endl;
946  //dbgmsg << " ... msg = " << *(SwapMsgList[i]) << endl;
947  int node = i;
948  Ippl::Comm->send(SwapMsgList[i], node, tag);
949 
950  // clear the list
951  PutList[i].erase(PutList[i].begin(), PutList[i].end());
952  }
953  }
954 
955  LocalNum -= PData.getDestroyNum(); // update local num
956  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
957  PData.performDestroy();
958 
959  // receive particles from neighbor nodes, and add them to our list
960  unsigned sendnum = NeighborNodes[d];
961  while (sendnum-- > 0)
962  {
963  int node = Communicate::COMM_ANY_NODE;
964  Message *recmsg = Ippl::Comm->receive_block(node, tag);
965  size_t recvd;
966  while ((recvd = PData.getMessage(*recmsg)) > 0)
967  LocalNum += recvd;
968  delete recmsg;
969  }
970  } // end if (NeighborNodes[d] > 0)
971 
972  if (d == 0)
973  {
974  // receive messages from any empty nodes
975  for (i = 0; i < N; ++i)
976  {
977  if (getEmptyNode(i))
978  {
979  int node = i;
980  Message *recmsg = Ippl::Comm->receive_block(node, etag);
981  size_t recvd;
982  while ((recvd = PData.getMessage(*recmsg)) > 0)
983  LocalNum += recvd;
984  delete recmsg;
985  }
986  }
987  }
988 
989  } // end for (d=0; d<Dim; ++d)
990 
991  }
992  else // empty node sends, but does not receive
993  {
994  // create new messages to send to our neighbors along dim 0
995  for (i = 0; i < N; i++)
996  if (SwapNodeList[0][i])
997  SwapMsgList[i] = new Message;
998 
999  // Go through the particles and find those moving to other nodes.
1000  // When one is found, copy it into outgoing message and delete it.
1001  for (ip=0; ip<LocalNum; ++ip)
1002  {
1003  if (!bool(canSwap[ip])) continue; // skip if can't swap
1004  // get the position of particle ip, and find the closest grid pnt
1005  for (j = 0; j < Dim; j++)
1006  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
1007 
1008  // see which remote Vnode this postion is in
1009  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
1010  RLayout.touch_range_rdv(pLoc);
1011 
1012  // make sure we have a vnode to send it to
1013  if (touchingVN.first == touchingVN.second)
1014  {
1015  ERRORMSG("Local particle " << ip << " with ID=");
1016  ERRORMSG(PData.ID[ip] << " at ");
1017  ERRORMSG(PData.R[ip] << " is outside of global domain ");
1019  ERRORMSG("This occurred when searching for point " << pLoc);
1020  ERRORMSG(" in RegionLayout = " << RLayout << endl);
1021  Ippl::abort();
1022  }
1023  else
1024  {
1025  // the node has been found - add index to put list
1026  unsigned node = (*(touchingVN.first)).second->getNode();
1027  PAssert_EQ(SwapNodeList[0][node], true);
1028  PutList[node].push_back(ip);
1029 
1030  // .. and then add to DestroyList
1031  PData.destroy(1, ip);
1032  }
1033  }
1034 
1035  // send the particles to their destination nodes
1036  for (i = 0; i < N; i++)
1037  {
1038  if (SwapNodeList[0][i])
1039  {
1040  // put data for particles on this put list into message
1041  PData.putMessage( *(SwapMsgList[i]), PutList[i] );
1042 
1043  // add a final 'zero' number of particles to indicate the end
1044  PData.putMessage(*(SwapMsgList[i]), (size_t) 0, (size_t) 0);
1045 
1046  // send the message
1047  int node = i;
1048  Ippl::Comm->send(SwapMsgList[i], node, etag);
1049 
1050  // clear the list
1051  PutList[i].erase(PutList[i].begin(), PutList[i].end());
1052  }
1053  }
1054 
1055  LocalNum -= PData.getDestroyNum(); // update local num
1056  ADDIPPLSTAT(incParticlesSwapped, PData.getDestroyNum());
1057  PData.performDestroy();
1058 
1059  }
1060 
1061  // return how many particles we have now
1062  return LocalNum;
1063  }
1064 
1065 
1066 
1067 
1068 /*
1069  * Newer (cleaner) version of swap particles that uses less bandwidth
1070  * and drastically lowers message counts for real cases.
1071  */
1072  template < class PB >
1073  size_t new_swap_particles(size_t LocalNum, PB& PData)
1074  {
1075  Ippl::Comm->barrier();
1076 
1077  unsigned N = Ippl::getNodes();
1078  unsigned myN = Ippl::myNode();
1079 
1080  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
1081  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV;
1082 
1083  std::vector<int> msgsend(N, 0);
1084  std::vector<int> msgrecv(N, 0);
1085 
1086  NDRegion<T,Dim> pLoc;
1087 
1088  std::multimap<unsigned, unsigned> p2n; //<node ID, particle ID>
1089 
1090  bool responsibleNodeNotFound = false;
1091  for (unsigned int ip=0; ip<LocalNum; ++ip)
1092  {
1093  for (unsigned int j = 0; j < Dim; j++)
1094  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
1095 
1096  unsigned destination = myN;
1097  bool found = false;
1098  for (localV = RLayout.begin_iv(); localV != localEnd && !found; ++localV)
1099  {
1100  if ((((*localV).second)->getDomain()).touches(pLoc))
1101  found = true; // particle is local and doesn't need to be sent anywhere
1102  }
1103 
1104  if (found)
1105  continue;
1106 
1108 
1109  //external location
1110  if (touchingVN.first == touchingVN.second) {
1111  responsibleNodeNotFound = true;
1112  break;
1113  }
1114  destination = (*(touchingVN.first)).second->getNode();
1115 
1116  msgsend[destination] = 1;
1117 
1118  p2n.insert(std::pair<unsigned, unsigned>(destination, ip));
1119  }
1120 
1121  allreduce(&responsibleNodeNotFound,
1122  1,
1123  std::logical_or<bool>());
1124 
1125  if (responsibleNodeNotFound) {
1126  throw IpplException("ParticleSpatialLayout::new_swap_particles",
1127  "could not find node responsible for particle");
1128  }
1129 
1130  //reduce message count so every node knows how many messages to receive
1131  allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
1132 
1134 
1135  typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
1136 
1137  std::unique_ptr<Format> format(PData.getFormat());
1138 
1139 
1140  std::vector<MPI_Request> requests;
1141  std::vector<std::shared_ptr<MsgBuffer> > buffers;
1142 
1143  while (i!=p2n.end())
1144  {
1145  unsigned cur_destination = i->first;
1146 
1147  std::shared_ptr<MsgBuffer> msgbuf(new MsgBuffer(format.get(), p2n.count(i->first)));
1148 
1149  for (; i!=p2n.end() && i->first == cur_destination; ++i)
1150  {
1151  Message msg;
1152  PData.putMessage(msg, i->second);
1153  PData.destroy(1, i->second);
1154  msgbuf->add(&msg);
1155  }
1156 
1157  MPI_Request request = Ippl::Comm->raw_isend( msgbuf->getBuffer(), msgbuf->getSize(), cur_destination, tag);
1158 
1159  //remember request and buffer so we can delete them later
1160  requests.push_back(request);
1161  buffers.push_back(msgbuf);
1162  }
1163 
1164  LocalNum -= PData.getDestroyNum(); // update local num
1165  PData.performDestroy();
1166 
1167  //receive new particles
1168  for (int k = 0; k<msgrecv[myN]; ++k)
1169  {
1170  int node = Communicate::COMM_ANY_NODE;
1171  char *buffer = 0;
1172  int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
1173  MsgBuffer recvbuf(format.get(), buffer, bufsize);
1174 
1175  Message *msg = recvbuf.get();
1176  while (msg != 0)
1177  {
1178  LocalNum += PData.getSingleMessage(*msg);
1179  delete msg;
1180  msg = recvbuf.get();
1181  }
1182 
1183 
1184  }
1185 
1186  //wait for communication to finish and clean up buffers
1187  MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
1188  MPI_Waitall(requests.size(), requests_ptr, MPI_STATUSES_IGNORE);
1189 
1190  return LocalNum;
1191  }
1192 
1193  template < class PB >
1194  size_t new_swap_particles(size_t LocalNum, PB& PData,
1195  const ParticleAttrib<char>& canSwap)
1196  {
1197  Ippl::Comm->barrier();
1198 
1199  unsigned N = Ippl::getNodes();
1200  unsigned myN = Ippl::myNode();
1201 
1202  typename RegionLayout<T,Dim,Mesh>::iterator_iv localV, localEnd = RLayout.end_iv();
1203  typename RegionLayout<T,Dim,Mesh>::iterator_dv remoteV;
1204 
1205  std::vector<int> msgsend(N, 0);
1206  std::vector<int> msgrecv(N, 0);
1207 
1208  NDRegion<T,Dim> pLoc;
1209 
1210  std::multimap<unsigned, unsigned> p2n; //<node ID, particle ID>
1211 
1212  bool responsibleNodeNotFound = false;
1213  for (unsigned int ip=0; ip<LocalNum; ++ip)
1214  {
1215  if (!bool(canSwap[ip]))//skip if it can't be swapped
1216  continue;
1217 
1218  for (unsigned int j = 0; j < Dim; j++)
1219  pLoc[j] = PRegion<T>(PData.R[ip][j], PData.R[ip][j]);
1220 
1221  unsigned destination = myN;
1222  bool found = false;
1223  for (localV = RLayout.begin_iv(); localV != localEnd && !found; ++localV)
1224  {
1225  if ((((*localV).second)->getDomain()).touches(pLoc))
1226  found = true; // particle is local and doesn't need to be sent anywhere
1227  }
1228 
1229  if (found)
1230  continue;
1231 
1233 
1234  //external location
1235  if (touchingVN.first == touchingVN.second) {
1236  responsibleNodeNotFound = true;
1237  break;
1238  }
1239  destination = (*(touchingVN.first)).second->getNode();
1240 
1241  msgsend[destination] = 1;
1242 
1243  p2n.insert(std::pair<unsigned, unsigned>(destination, ip));
1244  }
1245 
1246  allreduce(&responsibleNodeNotFound,
1247  1,
1248  std::logical_or<bool>());
1249 
1250  if (responsibleNodeNotFound) {
1251  throw IpplException("ParticleSpatialLayout::new_swap_particles",
1252  "could not find node responsible for particle");
1253  }
1254 
1255  //reduce message count so every node knows how many messages to receive
1256  allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
1257 
1259 
1260  typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
1261 
1262  std::unique_ptr<Format> format(PData.getFormat());
1263 
1264  std::vector<MPI_Request> requests;
1265  std::vector<std::shared_ptr<MsgBuffer> > buffers;
1266 
1267  while (i!=p2n.end())
1268  {
1269  unsigned cur_destination = i->first;
1270 
1271  std::shared_ptr<MsgBuffer> msgbuf(new MsgBuffer(format.get(), p2n.count(i->first)));
1272 
1273  for (; i!=p2n.end() && i->first == cur_destination; ++i)
1274  {
1275  Message msg;
1276  PData.putMessage(msg, i->second);
1277  PData.destroy(1, i->second);
1278  msgbuf->add(&msg);
1279  }
1280 
1281  MPI_Request request = Ippl::Comm->raw_isend( msgbuf->getBuffer(), msgbuf->getSize(), cur_destination, tag);
1282 
1283  //remember request and buffer so we can delete them later
1284  requests.push_back(request);
1285  buffers.push_back(msgbuf);
1286  }
1287 
1288  LocalNum -= PData.getDestroyNum(); // update local num
1289  PData.performDestroy();
1290 
1291  //receive new particles
1292  for (int k = 0; k<msgrecv[myN]; ++k)
1293  {
1294  int node = Communicate::COMM_ANY_NODE;
1295  char *buffer = 0;
1296  int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
1297  MsgBuffer recvbuf(format.get(), buffer, bufsize);
1298 
1299  Message *msg = recvbuf.get();
1300  while (msg != 0)
1301  {
1302  LocalNum += PData.getSingleMessage(*msg);
1303  delete msg;
1304  msg = recvbuf.get();
1305  }
1306  }
1307 
1308  //wait for communication to finish and clean up buffers
1309  MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
1310  MPI_Waitall(requests.size(), requests_ptr, 0);
1311 
1312  return LocalNum;
1313  }
1314 
1315 };
1316 
1318 
1319 #endif // PARTICLE_SPATIAL_LAYOUT_H
int getNodeCount(unsigned i) const
size_t swap_particles(size_t LocalNum, PB &PData, const ParticleAttrib< char > &canSwap)
size_t swap_particles(size_t LocalNum, PB &PData)
#define PAssert_EQ(a, b)
Definition: PAssert.h:104
Message & put(const T &val)
Definition: Message.h:406
RegionLayout< T, Dim, Mesh > & getLayout()
RegionLayout< T, Dim, Mesh > RegionLayout_t
void barrier(void)
Message * receive_block(int &node, int &tag)
static int myNode()
Definition: IpplInfo.cpp:691
iterator_iv begin_iv()
Definition: RegionLayout.h:146
const RegionLayout< T, Dim, Mesh > & getLayout() const
virtual void notifyUserOfDelete(UserList *)
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
bool empty() const
Definition: Message.h:300
Message & getMessage(Message &m)
Definition: Vektor.h:180
FieldLayout< Dim > & getFieldLayout()
virtual void Repartition(UserList *)
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
#define ADDIPPLSTAT(stat, amount)
Definition: IpplStats.h:237
virtual MPI_Request raw_isend(void *, int, int, int)
Definition: Communicate.h:196
Message & get(const T &cval)
Definition: Message.h:476
const int COMM_ANY_NODE
Definition: Communicate.h:40
clearpage the user may choose between constant or variable radius This model includes fringe fields begin
Definition: multipole_t.tex:6
Definition: Index.h:236
virtual int broadcast_others(Message *, int, bool delmsg=true)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define P_SPATIAL_RETURN_TAG
Definition: Tags.h:81
unsigned Index_t
#define PAssert_LT(a, b)
Definition: PAssert.h:106
std::string::iterator iterator
Definition: MSLang.h:15
std::vector< size_t > * PutList
ParticleAttrib< SingleParticlePos_t > ParticlePos_t
static int getNodes()
Definition: IpplInfo.cpp:670
touch_range_dv touch_range_rdv(const NDRegion< T, Dim > &domain)
Definition: RegionLayout.h:159
void update(IpplParticleBase< ParticleSpatialLayout< T, Dim, Mesh, CachingPolicy > > &p, const ParticleAttrib< char > *canSwap=0)
static Communicate * Comm
Definition: IpplInfo.h:84
ParticleLayout< T, Dim >::Index_t Index_t
ParticleAttrib< Index_t > ParticleIndex_t
bool getEmptyNode(unsigned i) const
#define P_SPATIAL_TRANSFER_TAG
Definition: Tags.h:82
Definition: Inform.h:42
FieldLayout< Dim > & getFieldLayout()
Definition: RegionLayout.h:137
ac_id_vnodes::size_type size_iv() const
Definition: RegionLayout.h:145
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
#define INFORM_ALL_NODES
Definition: Inform.h:39
const unsigned Dim
virtual int raw_probe_receive(char *&, int &, int &)
Definition: Communicate.h:208
bool send(Message *, int node, int tag, bool delmsg=true)
size_t new_swap_particles(size_t LocalNum, PB &PData)
Message & putMessage(Message &m) const
Definition: Vektor.h:174
RegionLayout< T, Dim, Mesh > RLayout
size_t new_swap_particles(size_t LocalNum, PB &PData, const ParticleAttrib< char > &canSwap)
Definition: Mesh.h:35
const NDRegion< T, Dim > & getDomain() const
Definition: RegionLayout.h:131
ac_domain_vnodes::size_type size_rdv() const
Definition: RegionLayout.h:152
void changeDomain(FieldLayout< Dim > &)
#define P_SPATIAL_RANGE_TAG
Definition: Tags.h:84
bool initialized() const
Definition: RegionLayout.h:128
void rebuild_layout(size_t haveLocal, PB &PData)
ParticleLayout< T, Dim >::SingleParticlePos_t SingleParticlePos_t
iterator_iv end_iv()
Definition: RegionLayout.h:147
static void abort(const char *=0)
Definition: IpplInfo.cpp:616
size_t short_swap_particles(size_t LocalNum, PB &PData)
end
Definition: multipole_t.tex:9