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