OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
ParticleCashedLayout.hpp
Go to the documentation of this file.
1 //
2 // Class ParticleCashedLayout
3 // Please note: for the time being this class is *not* used! But since it
4 // might be used in future projects, we keep this file.
5 //
6 // Copyright (c) 2003 - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
7 // All rights reserved
8 //
9 // This file is part of OPAL.
10 //
11 // OPAL is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
18 //
19 
23 #include "Region/RegionLayout.h"
25 #include "Utility/IpplInfo.h"
26 #include "Message/Communicate.h"
27 #include "Message/Message.h"
28 
29 #include <algorithm>
30 
31 /* Here we check for every particle if its in one of the cashed region
32  * of a neighbour and then add it as a ghost particle to this neighbor.
33  *
34  * o we dont need a pairlist, but another particle container
35  * maybe we can forget about the whole pairlist thingy and just
36  * USE the ghost particles! so we actually only have to make sure the
37  * ghost particles are uptodate and correct...
38  * o cashed particles are stored int ghost holder of particles!
39  *
40  * FIXME:
41  * o CHECK RADIUS, UNITS! and stuff
42  * checkdist = r - d/2 + eps
43  * o WE MUST ALLOW NO LOCAL GHOST NODES!
44  */
45 
47 // constructor, from a FieldLayout
48 template < class T, unsigned Dim, class Mesh >
50  fl)
52  setup(); // perform necessary setup
53 }
54 
55 
57 // constructor, from a FieldLayout
58 template < class T, unsigned Dim, class Mesh >
60  fl, Mesh& mesh)
61  : ParticleSpatialLayout<T,Dim,Mesh>(fl,mesh) {
62  setup(); // perform necessary setup
63 }
64 
65 
67 // constructor, from a RegionLayout
68 template < class T, unsigned Dim, class Mesh >
71  setup(); // perform necessary setup
72 }
73 
74 
76 // default constructor ... this does not initialize the RegionLayout,
77 // it will be instead initialized during the first update.
78 template < class T, unsigned Dim, class Mesh >
81  setup(); // perform necessary setup
82 }
83 
84 
86 // perform common constructor tasks
87 template < class T, unsigned Dim, class Mesh >
89 
90  // create storage for message pointers used in swapping particles
91  unsigned N = Ippl::getNodes();
92  InterNodeList = new bool[N];
93  SentToNodeList = new bool[N];
94  InteractionNodes = 0;
95 
96  // initialize interaction radius information
97  InterRadius = 0;
98  MaxGlobalInterRadius = 0;
99 }
100 
101 
103 // destructor
104 template < class T, unsigned Dim, class Mesh >
106 
107  delete [] InterNodeList;
108  delete [] SentToNodeList;
109 
110 }
111 
112 
114 // Return the maximum interaction radius of the local particles.
115 template < class T, unsigned Dim, class Mesh >
117 
118  return InterRadius;
119 }
120 
121 
123 // Filling ghost particle data
124 // If this is the first call of this
125 // method after update(), this must make sure up-to-date info on particles
126 // from neighboring nodes is available.
127 template < class T, unsigned Dim, class Mesh >
129 
130  //IFF: all the swap_ghost_particle methods will return immediately if
131  //no swap is necessary
132 
133  // check if we have any particle boundary conditions
134  if (getUpdateFlag(ParticleLayout<T,Dim>::BCONDS)) {
135  // check which boundaries, if any, are periodic
136  ParticleBConds<T,Dim>& pBConds = this->getBConds();
137  bool periodicBC[2*Dim];
138  unsigned numPeriodicBC = 0;
140  for (unsigned d=0; d<2*Dim; ++d) {
141  periodicBC[d] = (pBConds[d] == periodicBCond);
142  if (periodicBC[d]) ++numPeriodicBC;
143  }
144  if (numPeriodicBC>0) {
145  // we need to reflect domains across all periodic boundaries
146  // call specialized function to update ghost particle data
147  swap_ghost_particles(PData.getLocalNum(), PData, periodicBC);
148  }
149  else { // no periodic boundaries, call standard function
150  swap_ghost_particles(PData.getLocalNum(), PData);
151  }
152  }
153  else { // no boundary conditions, call standard function
154  // update ghost particle data if necessary
155  swap_ghost_particles(PData.getLocalNum(), PData);
156  }
157 
158  //IFF: PData now holds ghost particles
159 
160  return;
161 }
162 
163 
165 // for each dimension, calculate where neighboring Vnodes and physical
166 // nodes are located, and which nodes are within interaction distance
167 // of our own Vnodes. Save this info for use in sending ghost particles.
168 template < class T, unsigned Dim, class Mesh >
170 
171  unsigned int j, d; // loop variables
172 
173  // initialize data about interaction nodes, and get the inter radius
174  InteractionNodes = 0;
175  //FIXME: SAME FIX AS BELOW
176  T interRad = getMaxInteractionRadius();
177 
178  // initialize the message list and initial node count
179  unsigned N = Ippl::getNodes();
180  for (j=0; j < N; ++j)
181  InterNodeList[j] = false;
182 
183  // if no interaction radius, we're done
184  if (interRad <= 0.0)
185  return;
186 
187  // get RegionLayout iterators
188  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = this->RLayout.end_iv();
189  // determine which physical nodes are in our interaction domain
190  for (localVN = this->RLayout.begin_iv(); localVN != endLocalVN; ++localVN) {
191  // for each local Vnode, the domain to check equals the local Vnode dom
192  // plus twice the interaction radius
193  NDRegion<T,Dim> chkDom((*localVN).second->getDomain());
194  for (d=0; d < Dim; ++d) {
195  chkDom[d] = PRegion<T>(chkDom[d].first() - interRad,
196  chkDom[d].last() + interRad);
197  }
198 
199  // use the RegionLayout to find all remote Vnodes which touch the domain
200  // being checked here
201  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
202  this->RLayout.touch_range_rdv(chkDom);
203  typename RegionLayout<T,Dim,Mesh>::touch_iterator_dv tVN = touchingVN.first;
204  for ( ; tVN != touchingVN.second; ++tVN) {
205  // note that we need to send a message to the node which contains
206  // this remote Vnode
207  unsigned vn = ((*tVN).second)->getNode();
208  if ( ! InterNodeList[vn] ) {
209  InterNodeList[vn] = true;
210  InteractionNodes++;
211  }
212  }
213  }
214 
215  // set the flag indicating the swap ghost particle routine should
216  // be called the next time we try to access the cashed particles
217  // or do anything of utility with the ghost particles
218  NeedGhostSwap = true;
219  return;
220 }
221 
222 
224 // for each dimension, calculate where neighboring Vnodes and physical
225 // nodes are located, and which nodes are within interaction distance
226 // of our own Vnodes. Save this info for use in sending ghost particles.
227 // Special version to handle periodic boundary conditions
228 template < class T, unsigned Dim, class Mesh >
230  const bool periodicBC[2*Dim])
231 {
232  unsigned j, d; // loop variables
233  unsigned pe = Ippl::myNode();
234 
235  // initialize data about interaction nodes, and get the inter radius
236  InteractionNodes = 0;
237  //FIXME: SAME FIX AS BELOW
238  T interRad = getMaxInteractionRadius();
239 
240  // initialize the message list and initial node count
241  unsigned N = Ippl::getNodes();
242  for (j=0; j < N; ++j)
243  InterNodeList[j] = false;
244 
245  // if no interaction radius, we're done
246  if (interRad <= 0.0)
247  return;
248 
249  // get domain info
250  const NDRegion<T,Dim>& globalDom = this->RLayout.getDomain();
251 
252  // some stuff for computing reflected domains
253  T offset[Dim];
254  unsigned numRef;
255  bool flipBit, activeBit[Dim], refBit[Dim];
256  NDRegion<T,Dim> chkDom, refDom;
257 
258  // get RegionLayout iterators
259  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = this->RLayout.end_iv();
260  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN2;
261  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN;
263 
264  // determine which physical nodes are in our interaction domain
265  for (localVN = this->RLayout.begin_iv(); localVN != endLocalVN; ++localVN) {
266  // for each local Vnode, the domain to check equals the local Vnode dom
267  // plus twice the interaction radius
268  chkDom = (*localVN).second->getDomain();
269  for (d=0; d<Dim; ++d) {
270  chkDom[d] = PRegion<T>(chkDom[d].first() - interRad,
271  chkDom[d].last() + interRad);
272  }
273 
274  // use the RegionLayout to find all remote Vnodes which touch
275  // the domain being checked here
276  touchingVN = this->RLayout.touch_range_rdv(chkDom);
277  for (tVN = touchingVN.first; tVN != touchingVN.second; ++tVN) {
278  // note that we need to send a message to the node which contains
279  // this remote Vnode
280  unsigned vn = ((*tVN).second)->getNode();
281  if ( ! InterNodeList[vn] ) {
282  InterNodeList[vn] = true;
283  InteractionNodes++;
284  }
285  }
286 
287  // look for boundary crossings and check reflected domains
288  numRef = 0;
289  for (d=0; d<Dim; ++d) {
290  if (periodicBC[2*d] && chkDom[d].first()<globalDom[d].first()) {
291  // crossed lower boundary
292  offset[d] = globalDom[d].length();
293  activeBit[d] = true;
294  numRef = 2 * numRef + 1;
295  }
296  else if (periodicBC[2*d+1] && chkDom[d].last()>globalDom[d].last()) {
297  // crossed upper boundary
298  offset[d] = -globalDom[d].length();
299  activeBit[d] = true;
300  numRef = 2 * numRef + 1;
301  }
302  else {
303  offset[d] = 0.0;
304  activeBit[d] = false;
305  }
306  refBit[d] = false; // reset reflected domain bools
307  }
308 
309  // compute and check each domain reflection
310  for (j=0; j<numRef; ++j) {
311  // set up reflected domain: first initialize to original domain
312  refDom = chkDom;
313  // find next combination of dimension offsets
314  d = 0;
315  flipBit = false;
316  while (d<Dim && !flipBit) {
317  // first check if this dim is active
318  if (activeBit[d]) {
319  // now flip bit for this dimension
320  if (refBit[d]) {
321  // flip this bit off and proceed to next dim
322  refBit[d] = false;
323  }
324  else { // refBit[d] is off
325  // flip this bit on and indicate we're done
326  refBit[d] = true;
327  flipBit = true;
328  }
329  }
330  ++d;
331  }
332  PAssert(flipBit); // check that we found next combination
333 
334  // now offset the reflected domain
335  for (d=0; d<Dim; ++d) {
336  if (refBit[d]) refDom[d] = refDom[d] + offset[d];
337  }
338 
339  // use the RegionLayout to find all remote Vnodes which touch
340  // the domain being checked here
341  touchingVN = this->RLayout.touch_range_rdv(refDom);
342  for (tVN = touchingVN.first; tVN != touchingVN.second; ++tVN) {
343  // note that we need to send a message to the node which contains
344  // this remote Vnode
345  unsigned vn = ((*tVN).second)->getNode();
346  if ( ! InterNodeList[vn] ) {
347  InterNodeList[vn] = true;
348  InteractionNodes++;
349  }
350  }
351 
352  if (!InterNodeList[pe]) { // check if we interact with our own domains
353  // for reflected domains, we also must check against local domains
354  bool interact = false;
355  localVN2 = this->RLayout.begin_iv();
356  while (localVN2 != endLocalVN && !interact) {
357  interact = refDom.touches((*localVN2).second->getDomain());
358  ++localVN2;
359  }
360  if (interact) {
361  InterNodeList[pe] = true;
362  InteractionNodes++;
363  }
364  }
365  }
366 
367  }
368 
369  // set the flag indicating the swap ghost particle routine should
370  // be called the next time we try to access the cashed particles
371  // or do anything of utility with the ghost particles
372  NeedGhostSwap = true;
373  return;
374 }
375 
376 
378 // Update the location and indices of all atoms in the given IpplParticleBase
379 // object. This handles swapping particles among processors if
380 // needed, and handles create and destroy requests. When complete,
381 // all nodes have correct layout information.
382 template < class T, unsigned Dim, class Mesh >
385  const ParticleAttrib<char>* canSwap) {
386 
387  unsigned N = Ippl::getNodes();
388  unsigned myN = Ippl::myNode();
389  unsigned LocalNum = PData.getLocalNum();
390  unsigned DestroyNum = PData.getDestroyNum();
391  unsigned TotalNum;
392  //FIXME:
393  //T maxrad = getMaxLocalInteractionRadius();
394  T maxrad = 32.0;
395  int node;
396 
397  // delete particles in destroy list, update local num
398  PData.performDestroy();
399  LocalNum -= DestroyNum;
400 
401  // set up our layout, if not already done ... we could also do this if
402  // we needed to expand our spatial region.
403  if ( ! this->RLayout.initialized())
404  this->rebuild_layout(LocalNum,PData);
405 
406  // apply boundary conditions to the particle positions
407  if (this->getUpdateFlag(ParticleLayout<T,Dim>::BCONDS))
408  this->apply_bconds(LocalNum, PData.R, this->getBConds(), this->RLayout.getDomain());
409 
410  // Now we can swap particles that have moved outside the region of
411  // local field space. This is done in several passes, one for each
412  // spatial dimension. The NodeCount values are updated by this routine.
413  if (N > 1 && this->getUpdateFlag(this->SWAP)) {
414  if (canSwap==0)
415  LocalNum = this->swap_particles(LocalNum, PData);
416  else
417  LocalNum = this->swap_particles(LocalNum, PData, *canSwap);
418  }
419 
420  // flag we need to update our ghost particles
421  NeedGhostSwap = true;
422 
423  // Save how many local particles we have.
424  TotalNum = this->NodeCount[myN] = LocalNum;
425 
426  // there is extra work to do if there are multipple nodes, to distribute
427  // the particle layout data to all nodes
428  if (N > 1) {
429  // At this point, we can send our particle count updates to node 0, and
430  // receive back the particle layout.
433  if (myN != 0) {
434  Message *msg = new Message;
435 
436  // put local particle count in the message
437  msg->put(LocalNum);
438 
439  // also put in our maximum interaction radius
440  msg->put(maxrad);
441 
442  // send this info to node 0
443  Ippl::Comm->send(msg, 0, tag1);
444 
445  // receive back the number of particles on each node, and the maximum
446  // interaction radius
447  node = 0;
448  msg = Ippl::Comm->receive_block(node, tag2);
449  msg->get(this->NodeCount);
450  msg->get(maxrad);
451  msg->get(TotalNum);
452  } else { // do update tasks particular to node 0
453  // receive messages from other nodes describing what they have
454  int notrecvd = N - 1; // do not need to receive from node 0
455  TotalNum = LocalNum;
456  while (notrecvd > 0) {
457  // receive a message from another node. After recv, node == sender.
459  Message *msg = Ippl::Comm->receive_block(node, tag1);
460  int remNodeCount = 0;
461  T remMaxRad = 0.0;
462  msg->get(remNodeCount);
463  msg->get(remMaxRad);
464  delete msg;
465  notrecvd--;
466 
467  // update values based on data from remote node
468  TotalNum += remNodeCount;
469  this->NodeCount[node] = remNodeCount;
470  if (remMaxRad > maxrad)
471  maxrad = remMaxRad;
472  }
473 
474  // send info back to all the client nodes
475  Message *msg = new Message;
476  msg->put(this->NodeCount, this->NodeCount + N);
477  msg->put(maxrad);
478  msg->put(TotalNum);
479  Ippl::Comm->broadcast_others(msg, tag2);
480  }
481  }
482 
483  // update our particle number counts
484  PData.setTotalNum(TotalNum); // set the total atom count
485  PData.setLocalNum(LocalNum); // set the number of local atoms
486 
487  // if the interaction radius changed, must recalculate some things
488  if (maxrad != getMaxInteractionRadius()) {
489  setMaxInteractionRadius(maxrad);
490  // check if we have any particle boundary conditions
491  if (this->getUpdateFlag(ParticleLayout<T,Dim>::BCONDS)) {
492  // check which boundaries, if any, are periodic
493  ParticleBConds<T,Dim>& pBConds = this->getBConds();
494  bool periodicBC[2*Dim];
495  unsigned numPeriodicBC = 0;
497  for (unsigned d=0; d<2*Dim; ++d) {
498  periodicBC[d] = (pBConds[d] == periodicBCond);
499  if (periodicBC[d]) ++numPeriodicBC;
500  }
501  if (numPeriodicBC>0) {
502  // we need to reflect domains across all periodic boundaries
503  // call specialized function
504  rebuild_interaction_data(periodicBC);
505  }
506  else { // no periodic boundaries, call standard function
507  rebuild_interaction_data();
508  }
509  }
510  else { // no boundary conditions, call standard function
511  rebuild_interaction_data();
512  }
513  }
514  return;
515 }
516 
517 
519 // copy particles to other nodes for pairlist computation. The arguments
520 // are the current number of local particles, and the IpplParticleBase object.
521 // Make sure not to send any particles to, or receive particles from,
522 // nodes which have no particles on them. This also takes care of
523 // building the pairlists.
524 //FIXME: is this not working anyways?
525 template < class T, unsigned Dim, class Mesh >
527  LocalNum,
529 
530  unsigned int i; // loop variables
531 
532  // if we've already swapped particles since the last update, we're done
533  if ( ! NeedGhostSwap ) return;
534 
535  // clear flag indicating we need to do this ghost particle swap again
536  NeedGhostSwap = false;
537 
538  // delete all our current ghost particles; even if we have no local
539  // particles now, we may have pairlists left over from earlier when we did
540  // have local particles
541  PData.ghostDestroy(PData.getGhostNum(), 0);
542 
543  // find the number of nodes we need to communicate with
544  unsigned N = Ippl::getNodes();
545  unsigned sendnum = 0;
546  for (i=0; i < N; i++)
547  if (InterNodeList[i] && this->NodeCount[i] > 0)
548  sendnum++;
549 
550  // if there are no interaction nodes, we can just compute local pairlists
551  // and then return
552  if (sendnum == 0 || LocalNum == 0) {
553  return;
554  }
555 
556  // get the maximum interaction radius for the particles
557  // we actually check twice the radius
558  T interRad = 2.0 * getMaxInteractionRadius();
559 
560  // an NDRegion object used to store the interaction region of a particle
561  NDRegion<T,Dim> pLoc;
562 
563  // Ghost particles are swapped in one pass: an interaction region for a
564  // particle is created, and intersected with all the vnodes, and if the
565  // particle needs to go to that vnode, it is sent.
566 
567  // create new messages to send to our neighbors
568  for (i=0; i < N; i++)
569  if (InterNodeList[i] && this->NodeCount[i] > 0)
570  this->SwapMsgList[i] = new Message;
571 
572  // Go through the particles, find those with interaction radius
573  // which overlaps with a neighboring left node, and copy into a message.
574  // The interaction radius used to check for whether to send the particle
575  // is (max inter. radius of system)*2.
576 
577 
578  // for (i=0; i < LocalNum; ++i) {
579 
580  // initialize the flags which indicate which node the particle will be
581  // sent to
582 
583  // ada memset((void *)SentToNodeList, 0, N * sizeof(bool));
584 
585  // get the position of the ith particle, and form an NDRegion which
586  // is a cube with sides of length twice the interaction radius
587  // ada for (j=0; j < Dim; ++j)
588  // ada pLoc[j] = PRegion<T>(PData.R[i][j] - interRad,
589  // PData.R[i][j] + interRad);
590 
591  // see which Vnodes this postion is in; if none, it is local
592  // ada typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN = this->RLayout.touch_range_rdv(pLoc);
593  // ada typename RegionLayout<T,Dim,Mesh>::touch_iterator_dv tVNit = touchingVN.first;
594  // ada for ( ; tVNit != touchingVN.second; ++tVNit) {
595  // ada Rnode<T,Dim> *tVN = (*tVNit).second;
596  // ada unsigned node = tVN->getNode();
597 
598  // the node has been found - copy particle data into a message,
599  // ada if (this->NodeCount[node] > 0 && ! SentToNodeList[node]) {
600  // ada if (! InterNodeList[node]) {
601  // ada ERRORMSG("ParticleCashedLayout: Cannot send ghost " << i);
602  // ada ERRORMSG(" to node " << node << " ... skipping." << endl);
603  // ada }
604  // ada else {
605  // ada PData.ghostPutMessage(*(this->SwapMsgList[node]), 1, i);
606  // ada SentToNodeList[node] = true;
607  // }
608  // }
609  // }
610  // }
611 
612  // send out messages with ghost particles
613 
614  /*
615  ada: buggy BUGGY node hangs in later receive_block
616 
617  int tag = Ippl::Comm->next_tag(P_SPATIAL_GHOST_TAG, P_LAYOUT_CYCLE);
618  for (i=0; i < N; ++i) {
619  if (InterNodeList[i] && this->NodeCount[i] > 0) {
620  // add a final 'zero' number of particles to indicate the end
621  PData.ghostPutMessage(*(this->SwapMsgList[i]), (unsigned)0, (unsigned)0);
622 
623  // send the message
624  Ippl::Comm->send(this->SwapMsgList[i], i, tag);
625  }
626  }
627  */
628 
629  // receive ghost particles from other nodes, and add them to our list
630 
631  /*
632  while (sendnum-- > 0) {
633  int node = Communicate::COMM_ANY_NODE;
634  unsigned oldGN = PData.getGhostNum();
635  Message *recmsg = Ippl::Comm->receive_block(node, tag);
636 
637  while (PData.ghostGetMessage(*recmsg, node) > 0);
638  delete recmsg;
639 
640  // find pairs with these ghost particles
641  find_pairs(LocalNum, LocalNum + oldGN, LocalNum + PData.getGhostNum(),
642  false, PData);
643  }
644  */
645 
646 }
647 
648 
650 // copy particles to other nodes to cashed particle container. The arguments
651 // are the current number of local particles, and the IpplParticleBase object.
652 // Make sure not to send any particles to, or receive particles from,
653 // nodes which have no particles on them.
654 //
655 // special version to take care of periodic boundaries
656 template < class T, unsigned Dim, class Mesh >
658  unsigned LocalNum,
660  const bool periodicBC[2*Dim])
661 {
662  unsigned int i, j; // loop variables
663  unsigned d;
664 
665  // if we've already swapped particles since the last update, we're done
666  if ( ! NeedGhostSwap ) return;
667 
668  // clear flag indicating we need to do this ghost particle swap again
669  NeedGhostSwap = false;
670 
671  // delete all our current ghost particles; even if we have no local
672  // particles now, we may have pairlists left over from earlier when we did
673  // have local particles
674  // FIXME: still necessary?
675  PData.ghostDestroy(PData.getGhostNum(), 0);
676 
677  // find the number of nodes we need to communicate with
678  unsigned N = Ippl::getNodes();
679  unsigned pe = Ippl::myNode();
680  unsigned sendnum = 0;
681  for (i=0; i < N; i++)
682  if (InterNodeList[i] && this->NodeCount[i] > 0)
683  sendnum++;
684 
685  // if there are no interaction nodes, we can just return
686  if (sendnum == 0 || LocalNum == 0)
687  return;
688 
689  // get the maximum interaction radius for the particles
690  // we actually check twice the radius
691  //FIXME: interRad = r - domain/2
692  T interRad = getMaxInteractionRadius(); // - this->RLayout.getDomain().getLocalNDIndex().length() / 2.0;
693 
694  //if(interRad < 0) return;
695 
696  // get domain info
697  const NDRegion<T,Dim>& globalDom = this->RLayout.getDomain();
698 
699  // some stuff for computing reflected domains
700  T offset[Dim];
701  unsigned numRef;
702  bool flipBit, activeBit[Dim], refBit[Dim];
703  NDRegion<T,Dim> pLoc, refLoc;
704 
705  // region layout iterators
706  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = this->RLayout.end_iv();
707  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN;
709  SingleParticlePos_t savePos; // save position of reflected ghosts
710 
711  // Ghost particles are swapped in one pass: an interaction region for a
712  // particle is created, and intersected with all the vnodes, and if the
713  // particle needs to go to that vnode, it is sent.
714 
715  // create new messages to send to our neighbors
716  for (i=0; i < N; i++)
717  if (InterNodeList[i] && this->NodeCount[i] > 0)
718  this->SwapMsgList[i] = new Message;
719 
720  // Go through the particles, find those with interaction radius
721  // which overlaps with a neighboring left node, and copy into a message.
722  // The interaction radius used to check for whether to send the particle
723  // is (max inter. radius of system)*2.
724  for (i=0; i < LocalNum; ++i) {
725 
726  // initialize flags indicating which nodes the particle has been sent to
727  memset((void *)SentToNodeList, 0, N * sizeof(bool));
728 
729  // get the position of the ith particle, and form an NDRegion which
730  // is a cube with sides of length twice the interaction radius
731  for (j=0; j < Dim; ++j)
732  pLoc[j] = PRegion<T>(PData.R[i][j] - interRad,
733  PData.R[i][j] + interRad);
734 
735 
736  // see which Vnodes this postion is in; if none, it is local
737  touchingVN = this->RLayout.touch_range_rdv(pLoc);
738  for (tVNit = touchingVN.first; tVNit != touchingVN.second; ++tVNit) {
739  Rnode<T,Dim> *tVN = (*tVNit).second;
740  unsigned node = tVN->getNode();
741 
742  // the node has been found - copy particle data into a message,
743  if (this->NodeCount[node] > 0 && ! SentToNodeList[node]) {
744  if (! InterNodeList[node]) {
745  ERRORMSG("ParticleCashedLayout: Cannot send ghost " << i);
746  ERRORMSG(" to node " << node << " ... skipping." << endl);
747  }
748  else {
749  PData.ghostPutMessage(*(this->SwapMsgList[node]), 1, i);
750  SentToNodeList[node] = true;
751  }
752  }
753  }
754 
755  // look for boundary crossings and check reflected domains
756  numRef = 0;
757  for (d=0; d<Dim; ++d) {
758  if (periodicBC[2*d] && pLoc[d].first()<globalDom[d].first()) {
759  // crossed lower boundary
760  offset[d] = globalDom[d].length();
761  activeBit[d] = true;
762  numRef = 2 * numRef + 1;
763  }
764  else if (periodicBC[2*d+1] && pLoc[d].last()>globalDom[d].last()) {
765  // crossed upper boundary
766  offset[d] = -globalDom[d].length();
767  activeBit[d] = true;
768  numRef = 2 * numRef + 1;
769  }
770  else {
771  offset[d] = 0.0;
772  activeBit[d] = false;
773  }
774  refBit[d] = false; // reset bools indicating reflecting dims
775  }
776 
777  if (numRef>0) savePos = PData.R[i]; // copy current particle position
778 
779  // loop over reflected domains
780  for (j=0; j<numRef; ++j) {
781  // set up reflected neighborhood and position
782  refLoc = pLoc;
783  PData.R[i] = savePos;
784  // find next combination of dimension offsets
785  d = 0;
786  flipBit = false;
787  while (d<Dim && !flipBit) {
788  // first check if this dim is active
789  if (activeBit[d]) {
790  // now flip bit for this dimension
791  if (refBit[d]) {
792  // flip this bit off and proceed to next dim
793  refBit[d] = false;
794  }
795  else { // refBit[d] is off
796  // flip this bit on and indicate we're done
797  refBit[d] = true;
798  flipBit = true;
799  }
800  }
801  ++d;
802  }
803  PAssert(flipBit); // check that we found next combination
804 
805  // now offset the reflected neighborhood and particle position
806  for (d=0; d<Dim; ++d) {
807  if (refBit[d]) {
808  refLoc[d] = refLoc[d] + offset[d];
809  PData.R[i][d] = PData.R[i][d] + offset[d];
810  }
811  }
812 
813  // initialize flags indicating which nodes the particle has been sent to
814  memset((void *)SentToNodeList, 0, N * sizeof(bool));
815 
816  // see which Vnodes this postion is in; if none, it is local
817  touchingVN = this->RLayout.touch_range_rdv(refLoc);
818  for (tVNit = touchingVN.first; tVNit != touchingVN.second; ++tVNit) {
819  Rnode<T,Dim> *tVN = (*tVNit).second;
820  unsigned node = tVN->getNode();
821 
822  // the node has been found - copy particle data into a message,
823  if (this->NodeCount[node] > 0 && ! SentToNodeList[node]) {
824  if (! InterNodeList[node]) {
825  ERRORMSG("ParticleCashedLayout: Cannot send ghost " << i);
826  ERRORMSG(" to node " << node << " ... skipping." << endl);
827  }
828  else {
829  PData.ghostPutMessage(*(this->SwapMsgList[node]), 1, i);
830  SentToNodeList[node] = true;
831  }
832  }
833  }
834 
835  //FIXME: NO LOCAL GHOST NODES!
836  if (InterNodeList[pe]) { // we may interact with local domains
837  // for reflected domains, we also must check against local domains
838  bool interact = false;
839  localVN = this->RLayout.begin_iv();
840  while (localVN != endLocalVN && !interact) {
841  interact = refLoc.touches((*localVN).second->getDomain());
842  ++localVN;
843  }
844  if (interact) {
845  PData.ghostPutMessage(*(this->SwapMsgList[pe]), 1, i);
846  }
847  }
848  }
849  if (numRef>0) PData.R[i] = savePos; // restore particle position data
850 
851  }
852 
853  // send out messages with ghost particles
855  for (i=0; i < N; ++i) {
856  if (InterNodeList[i] && this->NodeCount[i] > 0) {
857  // add a final 'zero' number of particles to indicate the end
858  PData.ghostPutMessage(*(this->SwapMsgList[i]), (unsigned)0, (unsigned)0);
859 
860  // send the message
861  Ippl::Comm->send(this->SwapMsgList[i], i, tag);
862  }
863  }
864 
865  // receive ghost particles from other nodes, and add them to our list
866  while (sendnum-- > 0) {
867  int node = Communicate::COMM_ANY_NODE;
868  Message *recmsg = Ippl::Comm->receive_block(node, tag);
869 
870  while (PData.ghostGetMessage(*recmsg, node) > 0);
871  delete recmsg;
872 
873  }
874  //FIXME: ghost parts now in ghost holders of PData?
875 
876 }
877 
879 // print it out
880 template < class T, unsigned Dim, class Mesh >
881 std::ostream& operator<<(std::ostream& out, const ParticleCashedLayout<T,Dim,Mesh>& L) {
882 
883  out << "ParticleCashedLayout, with particle distribution:\n ";
884  for (unsigned int i=0; i < (unsigned int) Ippl::getNodes(); ++i)
885  out << L.getNodeCount(i) << " ";
886  out << "\nInteractLayout decomposition = " << L.getLayout();
887  return out;
888 }
889 
890 
892 // Repartition onto a new layout, if the layout changes ... this is a
893 // virtual function called by a UserList, as opposed to the RepartitionLayout
894 // function used by the particle load balancing mechanism.
895 template < class T, unsigned Dim, class Mesh >
897 
898  // perform actions to restructure our data due to a change in the
899  // RegionLayout
900  if (userlist->getUserListID() == this->RLayout.get_Id()) {
901  // clear out current interaction node storage; if the next update
902  // indicates we have a non-zero interaction radius, this info will be
903  // rebuilt (by calling rebuild_interaction_data)
904  InteractionNodes = 0;
905  setMaxInteractionRadius(0);
906  NeedGhostSwap = true;
907  }
908 }
ID_t getUserListID() const
Definition: UserList.cpp:54
Message & put(const T &val)
Definition: Message.h:406
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two distribute and or modify the software for each author s protection and we want to make certain that everyone understands that there is no warranty for this free software If the software is modified by someone else and passed we want its recipients to know that what they have is not the so that any problems introduced by others will not reflect on the original authors reputations any free program is threatened constantly by software patents We wish to avoid the danger that redistributors of a free program will individually obtain patent in effect making the program proprietary To prevent this
Definition: LICENSE:43
void update(IpplParticleBase< ParticleCashedLayout< T, Dim, Mesh > > &p, const ParticleAttrib< char > *canSwap=0)
Message * receive_block(int &node, int &tag)
static int myNode()
Definition: IpplInfo.cpp:691
iterator_iv begin_iv()
Definition: RegionLayout.h:146
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
#define P_SPATIAL_GHOST_TAG
Definition: Tags.h:83
Message & get(const T &cval)
Definition: Message.h:476
Definition: Rnode.h:30
virtual void Repartition(UserList *)
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
clearpage the user may choose between constant or variable radius This model includes fringe fields L
Definition: multipole_t.tex:7
static int getNodes()
Definition: IpplInfo.cpp:670
touch_range_dv touch_range_rdv(const NDRegion< T, Dim > &domain)
Definition: RegionLayout.h:159
static Communicate * Comm
Definition: IpplInfo.h:84
#define SWAP(a, b, type)
Definition: fftpack.cpp:83
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
#define P_SPATIAL_LAYOUT_TAG
Definition: Tags.h:80
const unsigned Dim
bool send(Message *, int node, int tag, bool delmsg=true)
Definition: Mesh.h:35
void getCashedParticles(IpplParticleBase< ParticleCashedLayout< T, Dim, Mesh > > &)
void swap_ghost_particles(unsigned, IpplParticleBase< ParticleCashedLayout< T, Dim, Mesh > > &)
#define PAssert(c)
Definition: PAssert.h:102
T ParticlePeriodicBCond(const T t, const T minval, const T maxval)
int getNode()
Definition: Rnode.h:52
iterator_iv end_iv()
Definition: RegionLayout.h:147
bool touches(const NDRegion< T, Dim > &nr) const
Definition: NDRegion.h:175