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