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