OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
ParticleInteractLayout.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 
37 #include <algorithm>
38 
40 // constructor, from a FieldLayout
41 template < class T, unsigned Dim, class Mesh >
43  fl)
45  setup(); // perform necessary setup
46 }
47 
48 
50 // constructor, from a FieldLayout
51 template < class T, unsigned Dim, class Mesh >
53  fl, Mesh& mesh)
54  : ParticleSpatialLayout<T,Dim,Mesh>(fl,mesh) {
55  setup(); // perform necessary setup
56 }
57 
58 
60 // constructor, from a RegionLayout
61 template < class T, unsigned Dim, class Mesh >
64  setup(); // perform necessary setup
65 }
66 
67 
69 // default constructor ... this does not initialize the RegionLayout,
70 // it will be instead initialized during the first update.
71 template < class T, unsigned Dim, class Mesh >
74  setup(); // perform necessary setup
75 }
76 
77 
79 // perform common constructor tasks
80 template < class T, unsigned Dim, class Mesh >
82 
83  // create storage for message pointers used in swapping particles
84  unsigned N = Ippl::getNodes();
85  InterNodeList = new bool[N];
86  SentToNodeList = new bool[N];
87  InteractionNodes = 0;
88 
89  // initialize interaction radius information
90  InterRadius = 0;
91  InterRadiusArray = 0;
92  MaxGlobalInterRadius = 0;
93 }
94 
95 
97 // destructor
98 template < class T, unsigned Dim, class Mesh >
100 
101  delete [] InterNodeList;
102  delete [] SentToNodeList;
103 
104  for (int i=(PairList.size() - 1); i >= 0; --i)
105  delete (PairList[i]);
106 }
107 
108 
110 // Return the maximum interaction radius of the local particles.
111 template < class T, unsigned Dim, class Mesh >
113 
114  if (InterRadiusArray != 0) {
115  if (InterRadiusArray->size() > 0)
116  return *(max_element(InterRadiusArray->begin(),
117  InterRadiusArray->end()));
118  else
119  return 0.0;
120  } else {
121  return InterRadius;
122  }
123 }
124 
125 
127 // Retrieve a Forward-style iterator for the beginning and end of the
128 // Nth (local) particle's nearest-neighbor pairlist.
129 // If this is the first call of this
130 // method after update(), this must make sure up-to-date info on particles
131 // from neighboring nodes is available.
132 template < class T, unsigned Dim, class Mesh >
134  pair_iterator& bpi, pair_iterator& epi,
136 
137  // check if we have any particle boundary conditions
138  if (getUpdateFlag(ParticleLayout<T,Dim>::BCONDS)) {
139  // check which boundaries, if any, are periodic
140  ParticleBConds<T,Dim>& pBConds = this->getBConds();
141  bool periodicBC[2*Dim];
142  unsigned numPeriodicBC = 0;
144  for (unsigned d=0; d<2*Dim; ++d) {
145  periodicBC[d] = (pBConds[d] == periodicBCond);
146  if (periodicBC[d]) ++numPeriodicBC;
147  }
148  if (numPeriodicBC>0) {
149  // we need to reflect domains across all periodic boundaries
150  // call specialized function to update ghost particle data
151  swap_ghost_particles(PData.getLocalNum(), PData, periodicBC);
152  }
153  else { // no periodic boundaries, call standard function
154  swap_ghost_particles(PData.getLocalNum(), PData);
155  }
156  }
157  else { // no boundary conditions, call standard function
158  // update ghost particle data if necessary ... this will also build
159  // the pairlists if needed
160  swap_ghost_particles(PData.getLocalNum(), PData);
161  }
162 
163  // get iterators for Nth particle's pairlist ... no check for array sub.
164  bpi = PairList[n]->begin();
165  epi = PairList[n]->end();
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("ParticleInteractLayout: rebuilding interaction node data."<<endl);
181 
182  // initialize data about interaction nodes, and get the inter radius
183  InteractionNodes = 0;
184  T interRad = 2.0 * getMaxInteractionRadius();
185 
186  // initialize the message list and initial node count
187  unsigned N = Ippl::getNodes();
188  for (j=0; j < N; ++j)
189  InterNodeList[j] = false;
190 
191  // if no interaction radius, we're done
192  if (interRad <= 0.0)
193  return;
194 
195  // get RegionLayout iterators
196  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = this->RLayout.end_iv();
197  // determine which physical nodes are in our interaction domain
198  for (localVN = this->RLayout.begin_iv(); localVN != endLocalVN; ++localVN) {
199  // for each local Vnode, the domain to check equals the local Vnode dom
200  // plus twice the interaction radius
201  NDRegion<T,Dim> chkDom((*localVN).second->getDomain());
202  for (d=0; d < Dim; ++d) {
203  chkDom[d] = PRegion<T>(chkDom[d].first() - interRad,
204  chkDom[d].last() + interRad);
205  }
206 
207  // use the RegionLayout to find all remote Vnodes which touch the domain
208  // being checked here
209  DEBUGMSG(" Checking domain " << chkDom << endl);
210  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
211  this->RLayout.touch_range_rdv(chkDom);
212  typename RegionLayout<T,Dim,Mesh>::touch_iterator_dv tVN = touchingVN.first;
213  DEBUGMSG(" Touching vnodes:" << endl);
214  for ( ; tVN != touchingVN.second; ++tVN) {
215  // note that we need to send a message to the node which contains
216  // this remote Vnode
217  DEBUGMSG(" vnode: node = " << ((*tVN).second)->getNode());
218  DEBUGMSG(", domain = " << ((*tVN).second)->getDomain() << endl);
219  unsigned vn = ((*tVN).second)->getNode();
220  if ( ! InterNodeList[vn] ) {
221  InterNodeList[vn] = true;
222  InteractionNodes++;
223  }
224  }
225  }
226 
227  DEBUGMSG(" There are " << InteractionNodes << " inter. nodes." << endl);
228 
229  // set the flag indicating the swap ghost particle routine should
230  // be called the next time we try to access a pairlist or do anything
231  // of utility with the ghost particles
232  NeedGhostSwap = true;
233  return;
234 }
235 
236 
238 // for each dimension, calculate where neighboring Vnodes and physical
239 // nodes are located, and which nodes are within interaction distance
240 // of our own Vnodes. Save this info for use in sending ghost particles.
241 // Special version to handle periodic boundary conditions
242 template < class T, unsigned Dim, class Mesh >
244  const bool periodicBC[2*Dim])
245 {
246  unsigned int j, d; // loop variables
247  unsigned pe = Ippl::myNode();
248 
249  DEBUGMSG("ParticleInteractLayout: rebuilding interaction node data."<<endl);
250 
251  // initialize data about interaction nodes, and get the inter radius
252  InteractionNodes = 0;
253  T interRad = 2.0 * getMaxInteractionRadius();
254 
255  // initialize the message list and initial node count
256  unsigned N = Ippl::getNodes();
257  for (j=0; j < N; ++j)
258  InterNodeList[j] = false;
259 
260  // if no interaction radius, we're done
261  if (interRad <= 0.0)
262  return;
263 
264  // get domain info
265  const NDRegion<T,Dim>& globalDom = this->RLayout.getDomain();
266 
267  // some stuff for computing reflected domains
268  T offset[Dim];
269  unsigned numRef;
270  bool flipBit, activeBit[Dim], refBit[Dim];
271  NDRegion<T,Dim> chkDom, refDom;
272 
273  // get RegionLayout iterators
274  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = this->RLayout.end_iv();
275  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN2;
276  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN;
278 
279  // determine which physical nodes are in our interaction domain
280  for (localVN = this->RLayout.begin_iv(); localVN != endLocalVN; ++localVN) {
281  // for each local Vnode, the domain to check equals the local Vnode dom
282  // plus twice the interaction radius
283  chkDom = (*localVN).second->getDomain();
284  for (d=0; d<Dim; ++d) {
285  chkDom[d] = PRegion<T>(chkDom[d].first() - interRad,
286  chkDom[d].last() + interRad);
287  }
288 
289  // use the RegionLayout to find all remote Vnodes which touch
290  // the domain being checked here
291  DEBUGMSG(" Checking domain " << chkDom << endl);
292  touchingVN = this->RLayout.touch_range_rdv(chkDom);
293  DEBUGMSG(" Touching vnodes:" << endl);
294  for (tVN = touchingVN.first; tVN != touchingVN.second; ++tVN) {
295  // note that we need to send a message to the node which contains
296  // this remote Vnode
297  DEBUGMSG(" vnode: node = " << ((*tVN).second)->getNode());
298  DEBUGMSG(", domain = " << ((*tVN).second)->getDomain() << endl);
299  unsigned vn = ((*tVN).second)->getNode();
300  if ( ! InterNodeList[vn] ) {
301  InterNodeList[vn] = true;
302  InteractionNodes++;
303  }
304  }
305 
306  // look for boundary crossings and check reflected domains
307  numRef = 0;
308  for (d=0; d<Dim; ++d) {
309  if (periodicBC[2*d] && chkDom[d].first()<globalDom[d].first()) {
310  // crossed lower boundary
311  offset[d] = globalDom[d].length();
312  activeBit[d] = true;
313  numRef = 2 * numRef + 1;
314  }
315  else if (periodicBC[2*d+1] && chkDom[d].last()>globalDom[d].last()) {
316  // crossed upper boundary
317  offset[d] = -globalDom[d].length();
318  activeBit[d] = true;
319  numRef = 2 * numRef + 1;
320  }
321  else {
322  offset[d] = 0.0;
323  activeBit[d] = false;
324  }
325  refBit[d] = false; // reset reflected domain bools
326  }
327 
328  // compute and check each domain reflection
329  for (j=0; j<numRef; ++j) {
330  // set up reflected domain: first initialize to original domain
331  refDom = chkDom;
332  // find next combination of dimension offsets
333  d = 0;
334  flipBit = false;
335  while (d<Dim && !flipBit) {
336  // first check if this dim is active
337  if (activeBit[d]) {
338  // now flip bit for this dimension
339  if (refBit[d]) {
340  // flip this bit off and proceed to next dim
341  refBit[d] = false;
342  }
343  else { // refBit[d] is off
344  // flip this bit on and indicate we're done
345  refBit[d] = true;
346  flipBit = true;
347  }
348  }
349  ++d;
350  }
351  PAssert(flipBit); // check that we found next combination
352 
353  // now offset the reflected domain
354  for (d=0; d<Dim; ++d) {
355  if (refBit[d]) refDom[d] = refDom[d] + offset[d];
356  }
357 
358  // use the RegionLayout to find all remote Vnodes which touch
359  // the domain being checked here
360  DEBUGMSG(" Checking domain " << refDom << endl);
361  touchingVN = this->RLayout.touch_range_rdv(refDom);
362  DEBUGMSG(" Touching vnodes:" << endl);
363  for (tVN = touchingVN.first; tVN != touchingVN.second; ++tVN) {
364  // note that we need to send a message to the node which contains
365  // this remote Vnode
366  DEBUGMSG(" vnode: node = " << ((*tVN).second)->getNode());
367  DEBUGMSG(", domain = " << ((*tVN).second)->getDomain() << endl);
368  unsigned vn = ((*tVN).second)->getNode();
369  if ( ! InterNodeList[vn] ) {
370  InterNodeList[vn] = true;
371  InteractionNodes++;
372  }
373  }
374 
375  if (!InterNodeList[pe]) { // check if we interact with our own domains
376  // for reflected domains, we also must check against local domains
377  bool interact = false;
378  localVN2 = this->RLayout.begin_iv();
379  while (localVN2 != endLocalVN && !interact) {
380  interact = refDom.touches((*localVN2).second->getDomain());
381  ++localVN2;
382  }
383  if (interact) {
384  InterNodeList[pe] = true;
385  InteractionNodes++;
386  }
387  }
388  }
389 
390  }
391 
392  DEBUGMSG(" There are " << InteractionNodes << " inter. nodes." << endl);
393 
394  // set the flag indicating the swap ghost particle routine should
395  // be called the next time we try to access a pairlist or do anything
396  // of utility with the ghost particles
397  NeedGhostSwap = true;
398  return;
399 }
400 
401 
403 // Update the location and indices of all atoms in the given IpplParticleBase
404 // object. This handles swapping particles among processors if
405 // needed, and handles create and destroy requests. When complete,
406 // all nodes have correct layout information.
407 template < class T, unsigned Dim, class Mesh >
410  const ParticleAttrib<char>* canSwap) {
411 
412  unsigned N = Ippl::getNodes();
413  unsigned myN = Ippl::myNode();
414  unsigned LocalNum = PData.getLocalNum();
415  unsigned DestroyNum = PData.getDestroyNum();
416  unsigned TotalNum;
417  T maxrad = getMaxLocalInteractionRadius();
418  int node;
419 
420  // delete particles in destroy list, update local num
421  PData.performDestroy();
422  LocalNum -= DestroyNum;
423 
424  // set up our layout, if not already done ... we could also do this if
425  // we needed to expand our spatial region.
426  if ( ! this->RLayout.initialized())
427  rebuild_layout(LocalNum,PData);
428 
429  // apply boundary conditions to the particle positions
430  if (getUpdateFlag(ParticleLayout<T,Dim>::BCONDS))
431  apply_bconds(LocalNum, PData.R, this->getBConds(), this->RLayout.getDomain());
432 
433  // Now we can swap particles that have moved outside the region of
434  // local field space. This is done in several passes, one for each
435  // spatial dimension. The NodeCount values are updated by this routine.
436  if (N > 1 && getUpdateFlag(this->SWAP)) {
437  if (canSwap==0)
438  LocalNum = swap_particles(LocalNum, PData);
439  else
440  LocalNum = swap_particles(LocalNum, PData, *canSwap);
441  }
442 
443  // flag we need to update our ghost particles
444  NeedGhostSwap = true;
445 
446  // Save how many local particles we have.
447  TotalNum = this->NodeCount[myN] = LocalNum;
448 
449  // there is extra work to do if there are multipple nodes, to distribute
450  // the particle layout data to all nodes
451  if (N > 1) {
452  // At this point, we can send our particle count updates to node 0, and
453  // receive back the particle layout.
456  if (myN != 0) {
457  Message *msg = new Message;
458 
459  // put local particle count in the message
460  msg->put(LocalNum);
461 
462  // also put in our maximum interaction radius
463  msg->put(maxrad);
464 
465  // send this info to node 0
466  Ippl::Comm->send(msg, 0, tag1);
467 
468  // receive back the number of particles on each node, and the maximum
469  // interaction radius
470  node = 0;
471  msg = Ippl::Comm->receive_block(node, tag2);
472  msg->get(this->NodeCount);
473  msg->get(maxrad);
474  msg->get(TotalNum);
475  } else { // do update tasks particular to node 0
476  // receive messages from other nodes describing what they have
477  int notrecvd = N - 1; // do not need to receive from node 0
478  TotalNum = LocalNum;
479  while (notrecvd > 0) {
480  // receive a message from another node. After recv, node == sender.
482  Message *msg = Ippl::Comm->receive_block(node, tag1);
483  int remNodeCount = 0;
484  T remMaxRad = 0.0;
485  msg->get(remNodeCount);
486  msg->get(remMaxRad);
487  delete msg;
488  notrecvd--;
489 
490  // update values based on data from remote node
491  TotalNum += remNodeCount;
492  this->NodeCount[node] = remNodeCount;
493  if (remMaxRad > maxrad)
494  maxrad = remMaxRad;
495  }
496 
497  // send info back to all the client nodes
498  Message *msg = new Message;
499  msg->put(this->NodeCount, this->NodeCount + N);
500  msg->put(maxrad);
501  msg->put(TotalNum);
502  Ippl::Comm->broadcast_others(msg, tag2);
503  }
504  }
505 
506  // update our particle number counts
507  PData.setTotalNum(TotalNum); // set the total atom count
508  PData.setLocalNum(LocalNum); // set the number of local atoms
509 
510  // if the interaction radius changed, must recalculate some things
511  if (maxrad != getMaxInteractionRadius()) {
512  setMaxInteractionRadius(maxrad);
513  // check if we have any particle boundary conditions
514  if (getUpdateFlag(ParticleLayout<T,Dim>::BCONDS)) {
515  // check which boundaries, if any, are periodic
516  ParticleBConds<T,Dim>& pBConds = this->getBConds();
517  bool periodicBC[2*Dim];
518  unsigned numPeriodicBC = 0;
520  for (unsigned d=0; d<2*Dim; ++d) {
521  periodicBC[d] = (pBConds[d] == periodicBCond);
522  if (periodicBC[d]) ++numPeriodicBC;
523  }
524  if (numPeriodicBC>0) {
525  // we need to reflect domains across all periodic boundaries
526  // call specialized function
527  rebuild_interaction_data(periodicBC);
528  }
529  else { // no periodic boundaries, call standard function
530  rebuild_interaction_data();
531  }
532  }
533  else { // no boundary conditions, call standard function
534  rebuild_interaction_data();
535  }
536  }
537  return;
538 }
539 
540 
542 // copy particles to other nodes for pairlist computation. The arguments
543 // are the current number of local particles, and the ParticleBase object.
544 // Make sure not to send any particles to, or receive particles from,
545 // nodes which have no particles on them. This also takes care of
546 // building the pairlists.
547 template < class T, unsigned Dim, class Mesh >
549  LocalNum,
551 
552  unsigned int i; // loop variables
553 
554  // if we've already swapped particles since the last update, we're done
555  if ( ! NeedGhostSwap ) return;
556 
557  // clear flag indicating we need to do this ghost particle swap again
558  NeedGhostSwap = false;
559 
560  // delete all our current ghost particles; even if we have no local
561  // particles now, we may have pairlists left over from earlier when we did
562  // have local particles
563  PData.ghostDestroy(PData.getGhostNum(), 0);
564 
565  // find the number of nodes we need to communicate with
566  unsigned N = Ippl::getNodes();
567  unsigned sendnum = 0;
568  for (i=0; i < N; i++)
569  if (InterNodeList[i] && this->NodeCount[i] > 0)
570  sendnum++;
571 
572  // if there are no interaction nodes, we can just compute local pairlists
573  // and then return
574  if (sendnum == 0 || LocalNum == 0) {
575  find_pairs(LocalNum, 0, LocalNum, true, PData);
576  return;
577  }
578 
579  // get the maximum interaction radius for the particles
580  // we actually check twice the radius
581  T interRad = 2.0 * getMaxInteractionRadius();
582 
583  // an NDRegion object used to store the interaction region of a particle
584  NDRegion<T,Dim> pLoc;
585 
586  // Ghost particles are swapped in one pass: an interaction region for a
587  // particle is created, and intersected with all the vnodes, and if the
588  // particle needs to go to that vnode, it is sent.
589 
590  // create new messages to send to our neighbors
591  for (i=0; i < N; i++)
592  if (InterNodeList[i] && this->NodeCount[i] > 0)
593  this->SwapMsgList[i] = new Message;
594 
595  // Go through the particles, find those with interaction radius
596  // which overlaps with a neighboring left node, and copy into a message.
597  // The interaction radius used to check for whether to send the particle
598  // is (max inter. radius of system)*2.
599 
600 
601  // for (i=0; i < LocalNum; ++i) {
602 
603  // initialize the flags which indicate which node the particle will be
604  // sent to
605 
606  // ada memset((void *)SentToNodeList, 0, N * sizeof(bool));
607 
608  // get the position of the ith particle, and form an NDRegion which
609  // is a cube with sides of length twice the interaction radius
610  // ada for (j=0; j < Dim; ++j)
611  // ada pLoc[j] = PRegion<T>(PData.R[i][j] - interRad,
612  // PData.R[i][j] + interRad);
613 
614  // see which Vnodes this postion is in; if none, it is local
615  // ada typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN = this->RLayout.touch_range_rdv(pLoc);
616  // ada typename RegionLayout<T,Dim,Mesh>::touch_iterator_dv tVNit = touchingVN.first;
617  // ada for ( ; tVNit != touchingVN.second; ++tVNit) {
618  // ada Rnode<T,Dim> *tVN = (*tVNit).second;
619  // ada unsigned node = tVN->getNode();
620 
621  // the node has been found - copy particle data into a message,
622  // ada if (this->NodeCount[node] > 0 && ! SentToNodeList[node]) {
623  // ada if (! InterNodeList[node]) {
624  // ada ERRORMSG("ParticleInteractLayout: Cannot send ghost " << i);
625  // ada ERRORMSG(" to node " << node << " ... skipping." << endl);
626  // ada }
627  // ada else {
628  // ada PData.ghostPutMessage(*(this->SwapMsgList[node]), 1, i);
629  // ada SentToNodeList[node] = true;
630  // }
631  // }
632  // }
633  // }
634 
635  // send out messages with ghost particles
636 
637  /*
638  ada: buggy BUGGY node hangs in later receive_block
639 
640  int tag = Ippl::Comm->next_tag(P_SPATIAL_GHOST_TAG, P_LAYOUT_CYCLE);
641  for (i=0; i < N; ++i) {
642  if (InterNodeList[i] && this->NodeCount[i] > 0) {
643  // add a final 'zero' number of particles to indicate the end
644  PData.ghostPutMessage(*(this->SwapMsgList[i]), (unsigned)0, (unsigned)0);
645 
646  // send the message
647  Ippl::Comm->send(this->SwapMsgList[i], i, tag);
648  }
649  }
650  */
651 
652  // while we're waiting for messages to arrive, calculate our local pairs
653  find_pairs(LocalNum, 0, LocalNum, true, PData);
654 
655  // receive ghost particles from other nodes, and add them to our list
656 
657  /*
658  while (sendnum-- > 0) {
659  int node = Communicate::COMM_ANY_NODE;
660  unsigned oldGN = PData.getGhostNum();
661  Message *recmsg = Ippl::Comm->receive_block(node, tag);
662 
663  while (PData.ghostGetMessage(*recmsg, node) > 0);
664  delete recmsg;
665 
666  // find pairs with these ghost particles
667  find_pairs(LocalNum, LocalNum + oldGN, LocalNum + PData.getGhostNum(),
668  false, PData);
669  }
670  */
671 
672 }
673 
674 
676 // copy particles to other nodes for pairlist computation. The arguments
677 // are the current number of local particles, and the IpplParticleBase object.
678 // Make sure not to send any particles to, or receive particles from,
679 // nodes which have no particles on them. This also takes care of
680 // building the pairlists.
681 // special version to take care of periodic boundaries
682 template < class T, unsigned Dim, class Mesh >
684  unsigned LocalNum,
686  const bool periodicBC[2*Dim])
687 {
688  unsigned int i, j; // loop variables
689  unsigned d;
690 
691  // if we've already swapped particles since the last update, we're done
692  if ( ! NeedGhostSwap ) return;
693 
694  // clear flag indicating we need to do this ghost particle swap again
695  NeedGhostSwap = false;
696 
697  // delete all our current ghost particles; even if we have no local
698  // particles now, we may have pairlists left over from earlier when we did
699  // have local particles
700  PData.ghostDestroy(PData.getGhostNum(), 0);
701 
702  // find the number of nodes we need to communicate with
703  unsigned N = Ippl::getNodes();
704  unsigned pe = Ippl::myNode();
705  unsigned sendnum = 0;
706  for (i=0; i < N; i++)
707  if (InterNodeList[i] && this->NodeCount[i] > 0)
708  sendnum++;
709 
710  // if there are no interaction nodes, we can just compute local pairlists
711  // and then return
712  if (sendnum == 0 || LocalNum == 0) {
713  find_pairs(LocalNum, 0, LocalNum, true, PData);
714  return;
715  }
716 
717  // get the maximum interaction radius for the particles
718  // we actually check twice the radius
719  T interRad = 2.0 * getMaxInteractionRadius();
720 
721  // get domain info
722  const NDRegion<T,Dim>& globalDom = this->RLayout.getDomain();
723 
724  // some stuff for computing reflected domains
725  T offset[Dim];
726  unsigned numRef;
727  bool flipBit, activeBit[Dim], refBit[Dim];
728  NDRegion<T,Dim> pLoc, refLoc;
729 
730  // region layout iterators
731  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = this->RLayout.end_iv();
732  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN;
734  SingleParticlePos_t savePos; // save position of reflected ghosts
735 
736  // Ghost particles are swapped in one pass: an interaction region for a
737  // particle is created, and intersected with all the vnodes, and if the
738  // particle needs to go to that vnode, it is sent.
739 
740  // create new messages to send to our neighbors
741  for (i=0; i < N; i++)
742  if (InterNodeList[i] && this->NodeCount[i] > 0)
743  this->SwapMsgList[i] = new Message;
744 
745  // Go through the particles, find those with interaction radius
746  // which overlaps with a neighboring left node, and copy into a message.
747  // The interaction radius used to check for whether to send the particle
748  // is (max inter. radius of system)*2.
749  for (i=0; i < LocalNum; ++i) {
750 
751  // initialize flags indicating which nodes the particle has been sent to
752  memset((void *)SentToNodeList, 0, N * sizeof(bool));
753 
754  // get the position of the ith particle, and form an NDRegion which
755  // is a cube with sides of length twice the interaction radius
756  for (j=0; j < (unsigned int) Dim; ++j)
757  pLoc[j] = PRegion<T>(PData.R[i][j] - interRad,
758  PData.R[i][j] + interRad);
759 
760  // see which Vnodes this postion is in; if none, it is local
761  touchingVN = this->RLayout.touch_range_rdv(pLoc);
762  for (tVNit = touchingVN.first; tVNit != touchingVN.second; ++tVNit) {
763  Rnode<T,Dim> *tVN = (*tVNit).second;
764  unsigned node = tVN->getNode();
765 
766  // the node has been found - copy particle data into a message,
767  if (this->NodeCount[node] > 0 && ! SentToNodeList[node]) {
768  if (! InterNodeList[node]) {
769  ERRORMSG("ParticleInteractLayout: Cannot send ghost " << i);
770  ERRORMSG(" to node " << node << " ... skipping." << endl);
771  }
772  else {
773  PData.ghostPutMessage(*(this->SwapMsgList[node]), 1, i);
774  SentToNodeList[node] = true;
775  }
776  }
777  }
778 
779  // look for boundary crossings and check reflected domains
780  numRef = 0;
781  for (d=0; d<Dim; ++d) {
782  if (periodicBC[2*d] && pLoc[d].first()<globalDom[d].first()) {
783  // crossed lower boundary
784  offset[d] = globalDom[d].length();
785  activeBit[d] = true;
786  numRef = 2 * numRef + 1;
787  }
788  else if (periodicBC[2*d+1] && pLoc[d].last()>globalDom[d].last()) {
789  // crossed upper boundary
790  offset[d] = -globalDom[d].length();
791  activeBit[d] = true;
792  numRef = 2 * numRef + 1;
793  }
794  else {
795  offset[d] = 0.0;
796  activeBit[d] = false;
797  }
798  refBit[d] = false; // reset bools indicating reflecting dims
799  }
800 
801  if (numRef>0) savePos = PData.R[i]; // copy current particle position
802 
803  // loop over reflected domains
804  for (j=0; j<numRef; ++j) {
805  // set up reflected neighborhood and position
806  refLoc = pLoc;
807  PData.R[i] = savePos;
808  // find next combination of dimension offsets
809  d = 0;
810  flipBit = false;
811  while (d<Dim && !flipBit) {
812  // first check if this dim is active
813  if (activeBit[d]) {
814  // now flip bit for this dimension
815  if (refBit[d]) {
816  // flip this bit off and proceed to next dim
817  refBit[d] = false;
818  }
819  else { // refBit[d] is off
820  // flip this bit on and indicate we're done
821  refBit[d] = true;
822  flipBit = true;
823  }
824  }
825  ++d;
826  }
827  PAssert(flipBit); // check that we found next combination
828 
829  // now offset the reflected neighborhood and particle position
830  for (d=0; d<Dim; ++d) {
831  if (refBit[d]) {
832  refLoc[d] = refLoc[d] + offset[d];
833  PData.R[i][d] = PData.R[i][d] + offset[d];
834  }
835  }
836 
837  // initialize flags indicating which nodes the particle has been sent to
838  memset((void *)SentToNodeList, 0, N * sizeof(bool));
839 
840  // see which Vnodes this postion is in; if none, it is local
841  touchingVN = this->RLayout.touch_range_rdv(refLoc);
842  for (tVNit = touchingVN.first; tVNit != touchingVN.second; ++tVNit) {
843  Rnode<T,Dim> *tVN = (*tVNit).second;
844  unsigned node = tVN->getNode();
845 
846  // the node has been found - copy particle data into a message,
847  if (this->NodeCount[node] > 0 && ! SentToNodeList[node]) {
848  if (! InterNodeList[node]) {
849  ERRORMSG("ParticleInteractLayout: Cannot send ghost " << i);
850  ERRORMSG(" to node " << node << " ... skipping." << endl);
851  }
852  else {
853  PData.ghostPutMessage(*(this->SwapMsgList[node]), 1, i);
854  SentToNodeList[node] = true;
855  }
856  }
857  }
858 
859  if (InterNodeList[pe]) { // we may interact with local domains
860  // for reflected domains, we also must check against local domains
861  bool interact = false;
862  localVN = this->RLayout.begin_iv();
863  while (localVN != endLocalVN && !interact) {
864  interact = refLoc.touches((*localVN).second->getDomain());
865  ++localVN;
866  }
867  if (interact) {
868  PData.ghostPutMessage(*(this->SwapMsgList[pe]), 1, i);
869  }
870  }
871  }
872  if (numRef>0) PData.R[i] = savePos; // restore particle position data
873 
874  }
875 
876  // send out messages with ghost particles
878  for (i=0; i < N; ++i) {
879  if (InterNodeList[i] && this->NodeCount[i] > 0) {
880  // add a final 'zero' number of particles to indicate the end
881  PData.ghostPutMessage(*(this->SwapMsgList[i]), (unsigned)0, (unsigned)0);
882 
883  // send the message
884  Ippl::Comm->send(this->SwapMsgList[i], i, tag);
885  }
886  }
887 
888  // while we're waiting for messages to arrive, calculate our local pairs
889  find_pairs(LocalNum, 0, LocalNum, true, PData);
890 
891  // receive ghost particles from other nodes, and add them to our list
892  while (sendnum-- > 0) {
893  int node = Communicate::COMM_ANY_NODE;
894  unsigned oldGN = PData.getGhostNum();
895  Message *recmsg = Ippl::Comm->receive_block(node, tag);
896 
897  while (PData.ghostGetMessage(*recmsg, node) > 0);
898  delete recmsg;
899 
900  // find pairs with these ghost particles
901  find_pairs(LocalNum, LocalNum + oldGN, LocalNum + PData.getGhostNum(),
902  false, PData);
903  }
904 }
905 
906 
908 // find the pairs between our local particles and particles a1 ... (a2 - 1).
909 // if the last argument is true, initialize all the pairlists to be empty.
910 template < class T, unsigned Dim, class Mesh >
912  const unsigned a1, const unsigned a2, const bool initLists,
914 
915  unsigned i, j; // loop variables
916 
917  // initialize the pairlist storage if requested
918  if (initLists) {
919  unsigned vlen = PairList.size();
920  if (vlen > LocalNum)
921  vlen = LocalNum;
922  for (i=0; i < vlen; ++i)
923  PairList[i]->erase(PairList[i]->begin(), PairList[i]->end());
924 
925  // make sure there are enough single particle pairlists
926  if (PairList.size() < LocalNum) {
927  int newamt = LocalNum - PairList.size();
928  PairList.reserve(newamt);
929  for (int k=0; k < newamt; ++k)
930  PairList.push_back(new std::vector<pair_t>);
931  }
932  }
933 
934  // make sure we have something to do
935  if (a2 <= a1) return;
936 
937  // find pairs between local particles and particles a1 ... a2
938  for (i=0; i < LocalNum; ++i) {
939  // get interaction radius of this particle
940  T intrad1 = getInteractionRadius(i);
941 
942  // find starting index of inner loop
943  j = (a1 > i ? a1 : i + 1);
944 
945  // do inner loop for particles up to the last local one
946  // (these pairs must be stored twice)
947  for (; j < LocalNum; ++j) {
948  // add interaction radius of this particle
949  T intrad2 = intrad1 + getInteractionRadius(j);
950  intrad2 *= intrad2; // (intrad1 + intrad2)^2
951 
952  // find distance^2 between these two particles
953  Vektor<T,Dim> rsep = PData.R[j];
954  rsep -= PData.R[i];
955  T sep2 = dot(rsep, rsep);
956 
957  // if the separation is less than their interaction distance, book it
958  // we store the pair twice, since we know both i and j are < LocalNum
959  if (sep2 < intrad2) {
960  PairList[i]->push_back(pair_t(j, sep2));
961  PairList[j]->push_back(pair_t(i, sep2));
962  }
963  }
964 
965  // now do rest of loop for just ghost particles (only store the
966  // pair once in this case)
967  for (; j < a2; ++j) {
968  // get interaction radius of this particle
969  T intrad2 = intrad1 + getInteractionRadius(j);
970  intrad2 *= intrad2; // (intrad1 + intrad2)^2
971 
972  // find distance^2 between these two particles
973  Vektor<T,Dim> rsep = PData.R[j];
974  rsep -= PData.R[i];
975  T sep2 = dot(rsep, rsep);
976 
977  // if the separation is less than their interaction distance, book it
978  // we only store the pair for the local atom i once, since the other
979  // atom j is a ghost atom
980  if (sep2 < intrad2) {
981  PairList[i]->push_back(pair_t(j, sep2));
982  }
983  }
984  }
985 }
986 
987 
989 // print it out
990 template < class T, unsigned Dim, class Mesh >
991 std::ostream& operator<<(std::ostream& out, const ParticleInteractLayout<T,Dim,Mesh>& L) {
992 
993  out << "ParticleInteractLayout, with particle distribution:\n ";
994  for (unsigned int i=0; i < (unsigned int) Ippl::getNodes(); ++i)
995  out << L.getNodeCount(i) << " ";
996  out << "\nInteractLayout decomposition = " << L.getLayout();
997  return out;
998 }
999 
1000 
1002 // Repartition onto a new layout, if the layout changes ... this is a
1003 // virtual function called by a UserList, as opposed to the RepartitionLayout
1004 // function used by the particle load balancing mechanism.
1005 template < class T, unsigned Dim, class Mesh >
1007 
1008  // perform actions to restructure our data due to a change in the
1009  // RegionLayout
1010  if (userlist->getUserListID() == this->RLayout.get_Id()) {
1011  // recalculate which nodes are our neighbors in each dimension
1012  this->rebuild_neighbor_data();
1013 
1014  // clear out current interaction node storage; if the next update
1015  // indicates we have a non-zero interaction radius, this info will be
1016  // rebuilt (by calling rebuild_interaction_data)
1017  InteractionNodes = 0;
1018  setMaxInteractionRadius(0);
1019  NeedGhostSwap = true;
1020  }
1021 }
1022 
1023 
1024 /***************************************************************************
1025  * $RCSfile: ParticleInteractLayout.cpp,v $ $Author: adelmann $
1026  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:29 $
1027  * IPPL_VERSION_ID: $Id: ParticleInteractLayout.cpp,v 1.1.1.1 2003/01/23 07:40:29 adelmann Exp $
1028  ***************************************************************************/
static int getNodes()
Definition: IpplInfo.cpp:773
Definition: Rnode.h:30
Definition: Mesh.h:35
void swap_ghost_particles(unsigned, IpplParticleBase< ParticleInteractLayout< T, Dim, Mesh > > &)
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
virtual void Repartition(UserList *)
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
int next_tag(int t, int s=1000)
Definition: TagMaker.h:43
void update(IpplParticleBase< ParticleInteractLayout< T, Dim, Mesh > > &p, const ParticleAttrib< char > *canSwap=0)
#define P_SPATIAL_RETURN_TAG
Definition: Tags.h:81
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
iterator_iv end_iv()
Definition: RegionLayout.h:147
bool touches(const NDRegion< T, Dim > &nr) const
Definition: NDRegion.h:175
std::vector< pair_t >::iterator pair_iterator
#define P_SPATIAL_GHOST_TAG
Definition: Tags.h:83
void getPairlist(unsigned, pair_iterator &, pair_iterator &, IpplParticleBase< ParticleInteractLayout< T, Dim, Mesh > > &)
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
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
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)
void find_pairs(const unsigned LocalNum, const unsigned a1, const unsigned a2, const bool initLists, IpplParticleBase< ParticleInteractLayout< T, Dim, Mesh > > &PData)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42