OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
ParticleSpatialLayout.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
29 #include "Index/NDIndex.h"
30 #include "Region/RegionLayout.h"
31 #include "Message/Communicate.h"
32 #include "Message/Message.h"
33 #include "Utility/IpplInfo.h"
34 #include "Utility/IpplStats.h"
36 
37 
38 // forward declarations
39 template <unsigned Dim> class FieldLayout;
40 class UserList;
41 
43 // constructor, from a FieldLayout
44 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
46  : RLayout(fl)
47 {
48  setup(); // perform necessary setup
49 }
50 
51 
53 // constructor, from a FieldLayout
54 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
56  Mesh& mesh)
57  : RLayout(fl,mesh)
58 {
59  setup(); // perform necessary setup
60 }
61 
62 
64 // constructor, from a RegionLayout
65 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
67  RegionLayout<T,Dim,Mesh>& rl) : RLayout(rl)
68 {
69  setup(); // perform necessary setup
70 }
71 
72 
74 // default constructor ... this does not initialize the RegionLayout,
75 // it will be instead initialized during the first update.
76 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
78 {
79  setup(); // perform necessary setup
80 }
81 
82 
84 // perform common constructor tasks
85 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
87 {
88 
89  unsigned i; // loop variable
90 
91  caching = false;
92 
93  // check ourselves in as a user of the RegionLayout
94  RLayout.checkin(*this);
95 
96  // create storage for message pointers used in swapping particles
97  unsigned N = Ippl::getNodes();
98  SwapMsgList = new Message*[N];
99  for (i = 0; i < Dim; ++i)
100  SwapNodeList[i] = new bool[N];
101  PutList = new std::vector<size_t>[N];
102 
103  // create storage for the number of particles on each node
104  // and flag for empty node domain
105  NodeCount = new size_t[N];
106  EmptyNode = new bool[N];
107  for (i = 0; i < N; ++i)
108  {
109  NodeCount[i] = 0;
110  EmptyNode[i] = false;
111  }
112 
113  // recalculate which nodes are our neighbors in each dimension
114  if (RLayout.initialized())
115  rebuild_neighbor_data();
116 }
117 
118 
120 // destructor
121 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
123 {
124 
125  delete [] NodeCount;
126  delete [] EmptyNode;
127  delete [] SwapMsgList;
128  for (unsigned int i=0; i < Dim; i++)
129  delete [] (SwapNodeList[i]);
130  delete [] PutList;
131 
132  // check ourselves out as a user of the RegionLayout
133  RLayout.checkout(*this);
134 }
135 
136 
137 
138 
140 // for each dimension, calculate where neighboring Vnodes and physical
141 // nodes are located, and create a list of this data. This need only
142 // be updated when the layout changes.
143 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
145 {
146 #ifdef OLD_SWAP_PARTICLES
147 
148  int d, j; // loop variables
149  unsigned N = Ippl::getNodes();
150  unsigned myN = Ippl::myNode();
151  Inform msg2all("rebuild_neighbor_data ", INFORM_ALL_NODES);
152 
153  // initialize the message list and initial node count
154  for (d = 0; d < Dim; ++d)
155  {
156  NeighborNodes[d] = 0;
157  for (j = 0; j < N; j++)
158  SwapNodeList[d][j] = false;
159  }
160 
161  // local Rnode iterators
162  typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = RLayout.end_iv();
163 
164  // check for no local Rnodes
165  if (RLayout.begin_iv() == endLocalVN)
166  {
167  EmptyNode[myN] = true;
168  }
169  else
170  {
171  // we need to consider each spatial dimension separately
172  for (d = 0; d < Dim; ++d)
173  {
174  // determine number of neighbor nodes in this spatial dimension
175  for (localVN = RLayout.begin_iv(); localVN != endLocalVN; ++localVN)
176  {
177  // for each local Vnode, the domain to check equals the local Vnode dom
178  // except for current dimension, which is the total Field domain size
179  NDRegion<T,Dim> chkDom((*localVN).second->getDomain());
180  chkDom[d] = (RLayout.getDomain())[d];
181  // use the RegionLayout to find all remote Vnodes which touch the
182  // domain being checked here
183  typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
184  RLayout.touch_range_rdv(chkDom);
185  typename RegionLayout<T,Dim,Mesh>::touch_iterator_dv tVN = touchingVN.first;
186  for ( ; tVN != touchingVN.second; ++tVN)
187  {
188  // note that we need to send a message to the node which contains
189  // this remote Vnode
190  unsigned vn = ((*tVN).second)->getNode();
191  if ( ! SwapNodeList[d][vn] )
192  {
193  SwapNodeList[d][vn] = true;
194  NeighborNodes[d]++;
195  }
196  }
197  }
198  }
199  }
200 
201  // there is extra work to do if there are multipple nodes, to distribute
202  // the particle layout data to all nodes
203  if (N > 1)
204  {
205  // At this point, we can send our domain status to node 0, and
206  // receive back the complete domain status.
209  Message *msg1, *msg2;
210  if (myN != 0)
211  {
212  msg1 = new Message;
213  // put local domain status in the message
214  msg1->put(EmptyNode[myN]);
215  // send this info to node 0
216  int node = 0;
217  Ippl::Comm->send(msg1, node, tag1);
218 
219  // receive back the complete domain status
220  msg2 = Ippl::Comm->receive_block(node, tag2);
221  msg2->get(EmptyNode);
222  delete msg2;
223  }
224  else // do update tasks particular to node 0
225  {
226  // receive messages from other nodes describing their domain status
227  int notrecvd = N - 1; // do not need to receive from node 0
228  while (notrecvd > 0)
229  {
230  // receive a message from another node. After recv, node == sender.
231  int node = Communicate::COMM_ANY_NODE;
232  msg1 = Ippl::Comm->receive_block(node, tag1);
233  msg1->get(EmptyNode[node]);
234  delete msg1;
235  notrecvd--;
236  }
237 
238  // send info back to all the client nodes
239  msg2 = new Message;
240  msg2->put(EmptyNode, EmptyNode+N);
241  Ippl::Comm->broadcast_others(msg2, tag2);
242  }
243  }
244 
245  // fix-up for empty nodes
246  if (EmptyNode[myN])
247  {
248  // node with empty domain treats all non-empty nodes as neighbor
249  // nodes along dimension 0
250  for (j = 0; j < N; ++j)
251  {
252  if (!EmptyNode[j])
253  {
254  SwapNodeList[0][j] = true;
255  NeighborNodes[0]++;
256  }
257  }
258  }
259  return;
260 #endif
261 }
262 
263 
265 // Update the location and indices of all atoms in the given IpplParticleBase
266 // object. This handles swapping particles among processors if
267 // needed, and handles create and destroy requests. When complete,
268 // all nodes have correct layout information.
269 template <class T, unsigned Dim, class Mesh, class CachingPolicy>
272  const ParticleAttrib<char>* canSwap)
273 {
274 
275  unsigned N = Ippl::getNodes();
276  unsigned myN = Ippl::myNode();
277  size_t LocalNum = PData.getLocalNum();
278  size_t DestroyNum = PData.getDestroyNum();
279  size_t TotalNum;
280  int node;
281 
282  //Inform dbgmsg("SpatialLayout::update", INFORM_ALL_NODES);
283  //dbgmsg << "At start of update:" << endl;
284  //PData.printDebug(dbgmsg);
285 
286  // delete particles in destroy list, update local num
287  PData.performDestroy();
288  LocalNum -= DestroyNum;
289 
290  // set up our layout, if not already done ... we could also do this if
291  // we needed to expand our spatial region.
292  if ( ! RLayout.initialized())
293  rebuild_layout(LocalNum,PData);
294 
295  // apply boundary conditions to the particle positions
296  if (this->getUpdateFlag(ParticleLayout<T,Dim>::BCONDS))
297  this->apply_bconds(LocalNum, PData.R, this->getBConds(), RLayout.getDomain());
298 
299  if(caching)
300  this->updateCacheInformation(*this);
301 
302  // swap particles, if necessary
303  if (N > 1 && this->getUpdateFlag(ParticleLayout<T,Dim>::SWAP))
304  {
305  // Now we can swap particles that have moved outside the region of
306  // local field space. This is done in several passes, one for each
307  // spatial dimension. The NodeCount values are updated by this routine.
308 
309  static IpplMessageCounterRegion swapCounter("Swap Particles");
310  swapCounter.begin();
311  //MPI_Pcontrol( 1,"swap_particles");
312 
313 #ifndef OLD_SWAP_PARTICLES
314  if (canSwap==0)
315  LocalNum = new_swap_particles(LocalNum, PData);
316  else
317  LocalNum = new_swap_particles(LocalNum, PData, *canSwap);
318 #else
319  if (canSwap==0)
320  LocalNum = swap_particles(LocalNum, PData);
321  else
322  LocalNum = swap_particles(LocalNum, PData, *canSwap);
323 #endif
324 
325  //MPI_Pcontrol(-1,"swap_particles");
326  swapCounter.end();
327  }
328 
329  // Save how many local particles we have.
330  TotalNum = NodeCount[myN] = LocalNum;
331 
332  // there is extra work to do if there are multipple nodes, to distribute
333  // the particle layout data to all nodes
334  if (N > 1)
335  {
336  // At this point, we can send our particle count updates to node 0, and
337  // receive back the particle layout.
340  if (myN != 0)
341  {
342  Message *msg = new Message;
343 
344  // put local particle count in the message
345  msg->put(LocalNum);
346  // send this info to node 0
347  Ippl::Comm->send(msg, 0, tag1);
348 
349  // receive back the number of particles on each node
350  node = 0;
351  Message* recmsg = Ippl::Comm->receive_block(node, tag2);
352  recmsg->get(NodeCount);
353  recmsg->get(TotalNum);
354  delete recmsg;
355  }
356  else // do update tasks particular to node 0
357  {
358  // receive messages from other nodes describing what they have
359  int notrecvd = N - 1; // do not need to receive from node 0
360  TotalNum = LocalNum;
361  while (notrecvd > 0)
362  {
363  // receive a message from another node. After recv, node == sender.
365  Message *recmsg = Ippl::Comm->receive_block(node, tag1);
366  size_t remNodeCount = 0;
367  recmsg->get(remNodeCount);
368  delete recmsg;
369  notrecvd--;
370 
371  // update values based on data from remote node
372  TotalNum += remNodeCount;
373  NodeCount[node] = remNodeCount;
374  }
375 
376  // send info back to all the client nodes
377  Message *msg = new Message;
378  msg->put(NodeCount, NodeCount + N);
379  msg->put(TotalNum);
380  Ippl::Comm->broadcast_others(msg, tag2);
381  }
382  }
383 
384  // update our particle number counts
385  PData.setTotalNum(TotalNum); // set the total atom count
386  PData.setLocalNum(LocalNum); // set the number of local atoms
387 
388  if(caching)
389  this->updateGhostParticles(PData, *this);
390 
391  //dbgmsg << endl << "At end of update:" << endl;
392  //PData.printDebug(dbgmsg);
393 }
394 
395 
396 
397 
398 
400 // print it out
401 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
402 std::ostream& operator<<(std::ostream& out, const ParticleSpatialLayout<T,Dim,Mesh,CachingPolicy>& L)
403 {
404 
405  out << "ParticleSpatialLayout, with particle distribution:\n ";
406  for (unsigned int i=0; i < (unsigned int) Ippl::getNodes(); ++i)
407  out << "Number of particles " << L.getNodeCount(i) << " ";
408  out << "\nSpatialLayout decomposition = " << L.getLayout();
409  return out;
410 }
411 
412 
414 // Print out information for debugging purposes.
415 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
417 {
418 
419  o << "PSpatial: distrib = ";
420  for (int i=0; i < Ippl::getNodes(); ++i)
421  o << NodeCount[i] << " ";
422 }
423 
424 
426 // Repartition onto a new layout, if the layout changes ... this is a
427 // virtual function called by a UserList, as opposed to the RepartitionLayout
428 // function used by the particle load balancing mechanism.
429 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
431 {
432  // perform actions to restructure our data due to a change in the
433  // RegionLayout
434  if (userlist->getUserListID() == RLayout.get_Id())
435  {
436  //Inform dbgmsg("ParticleSpatialLayout::Repartition", INFORM_ALL_NODES);
437  //dbgmsg << "Repartitioning due to change in RegionLayout ..." << endl;
438 
439  // recalculate which nodes are our neighbors in each dimension
440  rebuild_neighbor_data();
441  }
442 }
443 
444 
446 // Tell the subclass that the FieldLayoutBase is being deleted, so
447 // don't use it anymore
448 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
450 {
451 
452  // really, nothing to do, since the RegionLayout we use only gets
453  // deleted when we are deleted ourselves.
454  return;
455 }
456 
457 
458 /***************************************************************************
459  * $RCSfile: ParticleSpatialLayout.cpp,v $ $Author: adelmann $
460  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:29 $
461  * IPPL_VERSION_ID: $Id: ParticleSpatialLayout.cpp,v 1.1.1.1 2003/01/23 07:40:29 adelmann Exp $
462  ***************************************************************************/
static int getNodes()
Definition: IpplInfo.cpp:773
Definition: Mesh.h:35
virtual void Repartition(UserList *)
#define INFORM_ALL_NODES
Definition: Inform.h:38
ID_t getUserListID() const
Definition: UserList.cpp:54
iterator_iv begin_iv()
Definition: RegionLayout.h:146
void update(IpplParticleBase< ParticleSpatialLayout< T, Dim, Mesh, CachingPolicy > > &p, const ParticleAttrib< char > *canSwap=0)
#define P_SPATIAL_LAYOUT_TAG
Definition: Tags.h:80
static int myNode()
Definition: IpplInfo.cpp:794
UserList_t userlist
Definition: UserList.h:100
int next_tag(int t, int s=1000)
Definition: TagMaker.h:43
#define P_SPATIAL_RETURN_TAG
Definition: Tags.h:81
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
iterator_iv end_iv()
Definition: RegionLayout.h:147
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
touch_range_dv touch_range_rdv(const NDRegion< T, Dim > &domain)
Definition: RegionLayout.h:159
virtual void notifyUserOfDelete(UserList *)
const unsigned Dim
Message * receive_block(int &node, int &tag)
Definition: Inform.h:41
static Communicate * Comm
Definition: IpplInfo.h:93
bool send(Message *, int node, int tag, bool delmsg=true)