OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
ParticleSpatialLayout.hpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  ***************************************************************************/
7 
8 // include files
11 #include "Index/NDIndex.h"
12 #include "Region/RegionLayout.h"
13 #include "Message/Communicate.h"
14 #include "Message/Message.h"
15 #include "Utility/IpplInfo.h"
16 #include "Utility/IpplStats.h"
18 
19 
20 // forward declarations
21 template <unsigned Dim> class FieldLayout;
22 class UserList;
23 
25 // constructor, from a FieldLayout
26 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
28  : RLayout(fl)
29 {
30  setup(); // perform necessary setup
31 }
32 
33 
35 // constructor, from a FieldLayout
36 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
38  Mesh& mesh)
39  : RLayout(fl,mesh)
40 {
41  setup(); // perform necessary setup
42 }
43 
44 
46 // constructor, from a RegionLayout
47 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
49  RegionLayout<T,Dim,Mesh>& rl) : RLayout(rl)
50 {
51  setup(); // perform necessary setup
52 }
53 
54 
56 // default constructor ... this does not initialize the RegionLayout,
57 // it will be instead initialized during the first update.
58 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
60 {
61  setup(); // perform necessary setup
62 }
63 
64 
66 // perform common constructor tasks
67 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
69 {
70 
71  unsigned i; // loop variable
72 
73  caching = false;
74 
75  // check ourselves in as a user of the RegionLayout
76  RLayout.checkin(*this);
77 
78  // create storage for message pointers used in swapping particles
79  unsigned N = Ippl::getNodes();
80  SwapMsgList = new Message*[N];
81  for (i = 0; i < Dim; ++i)
82  SwapNodeList[i] = new bool[N];
83  PutList = new std::vector<size_t>[N];
84 
85  // create storage for the number of particles on each node
86  // and flag for empty node domain
87  NodeCount = new size_t[N];
88  EmptyNode = new bool[N];
89  for (i = 0; i < N; ++i)
90  {
91  NodeCount[i] = 0;
92  EmptyNode[i] = false;
93  }
94 }
95 
96 
98 // destructor
99 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
101 {
102 
103  delete [] NodeCount;
104  delete [] EmptyNode;
105  delete [] SwapMsgList;
106  for (unsigned int i=0; i < Dim; i++)
107  delete [] (SwapNodeList[i]);
108  delete [] PutList;
109 
110  // check ourselves out as a user of the RegionLayout
111  RLayout.checkout(*this);
112 }
113 
114 
116 // Update the location and indices of all atoms in the given IpplParticleBase
117 // object. This handles swapping particles among processors if
118 // needed, and handles create and destroy requests. When complete,
119 // all nodes have correct layout information.
120 template <class T, unsigned Dim, class Mesh, class CachingPolicy>
123  const ParticleAttrib<char>* canSwap)
124 {
125 
126  unsigned N = Ippl::getNodes();
127  unsigned myN = Ippl::myNode();
128  size_t LocalNum = PData.getLocalNum();
129  size_t DestroyNum = PData.getDestroyNum();
130  size_t TotalNum;
131  int node;
132 
133  //Inform dbgmsg("SpatialLayout::update", INFORM_ALL_NODES);
134  //dbgmsg << "At start of update:" << endl;
135  //PData.printDebug(dbgmsg);
136 
137  // delete particles in destroy list, update local num
138  PData.performDestroy();
139  LocalNum -= DestroyNum;
140 
141  // set up our layout, if not already done ... we could also do this if
142  // we needed to expand our spatial region.
143  if ( ! RLayout.initialized())
144  rebuild_layout(LocalNum,PData);
145 
146  // apply boundary conditions to the particle positions
147  if (this->getUpdateFlag(ParticleLayout<T,Dim>::BCONDS))
148  this->apply_bconds(LocalNum, PData.R, this->getBConds(), RLayout.getDomain());
149 
150  if(caching)
151  this->updateCacheInformation(*this);
152 
153  // swap particles, if necessary
154  if (N > 1 && this->getUpdateFlag(ParticleLayout<T,Dim>::SWAP))
155  {
156  // Now we can swap particles that have moved outside the region of
157  // local field space. This is done in several passes, one for each
158  // spatial dimension. The NodeCount values are updated by this routine.
159 
160  static IpplMessageCounterRegion swapCounter("Swap Particles");
161  swapCounter.begin();
162  //MPI_Pcontrol( 1,"swap_particles");
163 
164  if (canSwap==0)
165  LocalNum = new_swap_particles(LocalNum, PData);
166  else
167  LocalNum = new_swap_particles(LocalNum, PData, *canSwap);
168 
169  swapCounter.end();
170  }
171 
172  // Save how many local particles we have.
173  TotalNum = NodeCount[myN] = LocalNum;
174 
175  // there is extra work to do if there are multipple nodes, to distribute
176  // the particle layout data to all nodes
177  if (N > 1)
178  {
179  // At this point, we can send our particle count updates to node 0, and
180  // receive back the particle layout.
183  if (myN != 0)
184  {
185  Message *msg = new Message;
186 
187  // put local particle count in the message
188  msg->put(LocalNum);
189  // send this info to node 0
190  Ippl::Comm->send(msg, 0, tag1);
191 
192  // receive back the number of particles on each node
193  node = 0;
194  Message* recmsg = Ippl::Comm->receive_block(node, tag2);
195  recmsg->get(NodeCount);
196  recmsg->get(TotalNum);
197  delete recmsg;
198  }
199  else // do update tasks particular to node 0
200  {
201  // receive messages from other nodes describing what they have
202  int notrecvd = N - 1; // do not need to receive from node 0
203  TotalNum = LocalNum;
204  while (notrecvd > 0)
205  {
206  // receive a message from another node. After recv, node == sender.
208  Message *recmsg = Ippl::Comm->receive_block(node, tag1);
209  size_t remNodeCount = 0;
210  recmsg->get(remNodeCount);
211  delete recmsg;
212  notrecvd--;
213 
214  // update values based on data from remote node
215  TotalNum += remNodeCount;
216  NodeCount[node] = remNodeCount;
217  }
218 
219  // send info back to all the client nodes
220  Message *msg = new Message;
221  msg->put(NodeCount, NodeCount + N);
222  msg->put(TotalNum);
223  Ippl::Comm->broadcast_others(msg, tag2);
224  }
225  }
226 
227  // update our particle number counts
228  PData.setTotalNum(TotalNum); // set the total atom count
229  PData.setLocalNum(LocalNum); // set the number of local atoms
230 
231  if(caching)
232  this->updateGhostParticles(PData, *this);
233 
234  //dbgmsg << endl << "At end of update:" << endl;
235  //PData.printDebug(dbgmsg);
236 }
237 
238 
239 
240 
241 
243 // print it out
244 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
245 std::ostream& operator<<(std::ostream& out, const ParticleSpatialLayout<T,Dim,Mesh,CachingPolicy>& L)
246 {
247 
248  out << "ParticleSpatialLayout, with particle distribution:\n ";
249  for (unsigned int i=0; i < (unsigned int) Ippl::getNodes(); ++i)
250  out << "Number of particles " << L.getNodeCount(i) << " ";
251  out << "\nSpatialLayout decomposition = " << L.getLayout();
252  return out;
253 }
254 
255 
257 // Print out information for debugging purposes.
258 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
260 {
261 
262  o << "PSpatial: distrib = ";
263  for (int i=0; i < Ippl::getNodes(); ++i)
264  o << NodeCount[i] << " ";
265 }
266 
267 
269 // Repartition onto a new layout, if the layout changes ... this is a
270 // virtual function called by a UserList, as opposed to the RepartitionLayout
271 // function used by the particle load balancing mechanism.
272 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
274 {
275 }
276 
277 
279 // Tell the subclass that the FieldLayoutBase is being deleted, so
280 // don't use it anymore
281 template < class T, unsigned Dim, class Mesh, class CachingPolicy >
283 {
284 
285  // really, nothing to do, since the RegionLayout we use only gets
286  // deleted when we are deleted ourselves.
287  return;
288 }
const unsigned Dim
#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
std::ostream & operator<<(std::ostream &out, const ParticleSpatialLayout< T, Dim, Mesh, CachingPolicy > &L)
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()
virtual void Repartition(UserList *)
virtual void notifyUserOfDelete(UserList *)
void update(IpplParticleBase< ParticleSpatialLayout< T, Dim, Mesh, CachingPolicy > > &p, const ParticleAttrib< char > *canSwap=0)
Definition: Inform.h:42
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84