OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
ParticleUniformLayout.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
28 #include "Utility/IpplInfo.h"
29 #include "Message/Communicate.h"
30 #include "Message/Message.h"
31 
32 #include <cstddef>
33 
34 
36 // constructor
37 // create storage for per-node data
38 template<class T, unsigned Dim>
40 
41  int N = Ippl::getNodes();
42  LocalSize = new int[N];
43  Change = new int[N];
44  MsgCount = new int[N];
45 }
46 
47 
49 // destructor
50 template<class T, unsigned Dim>
52 
53  delete [] LocalSize;
54  delete [] Change;
55  delete [] MsgCount;
56 }
57 
58 
60 // Update the location and indices of all atoms in the given IpplParticleBase
61 // object. This handles swapping particles among processors if
62 // needed, and handles create and destroy requests. When complete,
63 // all nodes have correct layout information.
64 template<class T, unsigned Dim>
67  const ParticleAttrib<char>* canSwap) {
68 
69  int i, j; // loop variables
70  int N = Ippl::getNodes();
71  int myN = Ippl::myNode();
72  size_t TotalNum = PData.getTotalNum();
73  size_t LocalNum = PData.getLocalNum();
74  size_t DestroyNum = PData.getDestroyNum();
75  float Weight = 1.0 / (float)N; // the fraction of the total particles
76  // to go on each node
77  // create Inform object for printing
78  //Inform dbgmsg("UniformLayout", INFORM_ALL_NODES);
79  //dbgmsg << "At start on node " << myN << ": local=" << LocalNum;
80  //dbgmsg << ", total=" << TotalNum << ", destroy=" << DestroyNum << endl;
81 
82  // if we just have one node, this is simple: just create and destroy
83  // particles we need to.
84  if (N == 1) {
85  // delete unsightly particles
86  PData.performDestroy();
87 
88  // adjust local num
89  LocalNum -= DestroyNum;
90 
91  // update particle counts
92  PData.setTotalNum(LocalNum);
93  PData.setLocalNum(LocalNum);
94 
95  return;
96  }
97 
98  // data and tags for send/receive's
102  int node, sendnum, recnum;
103  int nodedata[3];
104  Message *msg = 0;
105 
106  // perform tasks on client nodes
107  if (myN != 0) {
108  // step 1: forward our current size and delete requests
109  // to master node
110  nodedata[0] = LocalNum;
111  nodedata[1] = DestroyNum;
112  msg = new Message;
113  msg->put(nodedata, nodedata + 2);
114  //dbgmsg << "Sending to parent: LocalNum=" << nodedata[0];
115  //dbgmsg << ", DestroyNum=" << nodedata[1] << endl;
116  Ippl::Comm->send(msg, 0, tag1);
117 
118  } else { // do update tasks particular to node 0
119 
120  //
121  // step 1: get info on requests from client nodes
122  //
123 
124  // fill in data on the size, etc. of node 0
125  LocalSize[0] = LocalNum - DestroyNum;
126  TotalNum = LocalSize[0];
127  //dbgmsg << "Master initially has TotalNum = " << TotalNum << endl;
128 
129  // receive messages from other nodes describing what they have
130  int notrecvd = N - 1; // do not need to receive from node 0
131  while (notrecvd > 0) {
132  // receive a message from another node. After recv, node == sender.
134  msg = Ippl::Comm->receive_block(node, tag1);
135  msg->get(nodedata);
136  delete msg;
137 
138  // fill in data on the size, etc. of other nodes
139  LocalSize[node] = nodedata[0] - nodedata[1];
140  TotalNum += LocalSize[node];
141  //dbgmsg << "Master received local[" << node << "] = " << LocalSize[node];
142  //dbgmsg << ", new TotalNum = " << TotalNum << endl;
143  notrecvd--;
144  }
145 
146  // now calculate how many particles go on each node
147  if (getUpdateFlag(ParticleLayout<T,Dim>::SWAP)) {
148  int accounted = 0;
149  for (i = 0; i < N; i++) {
150  Change[i] = (int)((float)TotalNum * Weight);
151  accounted += Change[i];
152  }
153  accounted -= TotalNum;
154  if (accounted < 0) {
155  while (accounted != 0) {
156  Change[(-accounted) % N]++;
157  accounted++;
158  }
159  } else {
160  int whichnode = 0;
161  while (accounted != 0) {
162  if (Change[whichnode] > 0) {
163  Change[whichnode]--;
164  accounted--;
165  }
166  whichnode = (whichnode + 1) % N;
167  }
168  }
169  for (i = 0; i < N; i++) {
170  Change[i] = Change[i] - LocalSize[i];
171  MsgCount[i] = Change[i];
172  }
173  } else {
174  for (i = 0; i < N; i++) {
175  Change[i] = MsgCount[i] = 0;
176  }
177  }
178 
179  // send out instructions to all nodes, while calculating what goes where
180  for (i = 0; i < N; i++) {
181  // put header info into the message
182  nodedata[0] = TotalNum; // new total number of particles
183  if (Change[i] <= 0) { // if the change is < 0, send out particles
184  nodedata[1] = -Change[i]; // number of particles to send
185  nodedata[2] = 0; // number of particles to receive
186  }
187  else { // if the change is > 0, receive particles
188  nodedata[1] = 0; // number of particles to send
189  nodedata[2] = Change[i]; // number of particles to receive
190  }
191  msg = new Message;
192  msg->put(nodedata, nodedata + 3);
193 
194  // if we must send out particles to other nodes
195  // put info on where to send into the message
196  if (Change[i] <= 0) {
197  for (j = 0; j < N && MsgCount[i] < 0; j++) {
198  if (j != i && MsgCount[j] > 0) {
199  nodedata[0] = j;
200  if ((-MsgCount[i]) > MsgCount[j])
201  nodedata[1] = MsgCount[j];
202  else
203  nodedata[1] = -MsgCount[i];
204  MsgCount[i] += nodedata[1];
205  MsgCount[j] -= nodedata[1];
206  msg->put(nodedata, nodedata + 2);
207  }
208  }
209  }
210 
211  Ippl::Comm->send(msg, i, tag2);
212  }
213  }
214 
215  // step 2: retrieve instructions on what to create, and what to send/rec
217  // dbgmsg << "Receiving instructions ..." << endl;
218  msg = Ippl::Comm->receive_block(node, tag2);
219  msg->get(nodedata);
220  TotalNum = nodedata[0]; // new total number of particles
221  sendnum = nodedata[1]; // how many particles to send out
222  recnum = nodedata[2]; // how many particles to receive
223  //dbgmsg << "Received new TotalNum=" << TotalNum << ", sendnum=" << sendnum;
224  //dbgmsg << ", recnum=" << recnum << endl;
225 
226  // step 3: delete unwanted particles, update local num
227  PData.performDestroy();
228  LocalNum -= DestroyNum;
229 
230  // step 4: send out particles which need to be sent. In this case,
231  // we just respond to the instructions from the master node, and
232  // take particles from the end of our list
233  if (canSwap==0) {
234  while (sendnum > 0) {
235  // get number of particles to send, and where
236  msg->get(nodedata); // node, number of particles
237  LocalNum -= nodedata[1];
238  sendnum -= nodedata[1];
239 
240  //dbgmsg << "Sending " << nodedata[1] << " particles to node ";
241  //dbgmsg << nodedata[0] << endl;
242 
243  // put the particles in a new message
244  Message *sendmsg = new Message;
245  PData.putMessage(*sendmsg, nodedata[1], LocalNum);
246  Ippl::Comm->send(sendmsg, nodedata[0], tag3);
247 
248  // After putting particles in the message, we can delete them.
249  PData.destroy(nodedata[1], LocalNum, true);
250  }
251  }
252  else {
253  while (sendnum > 0) {
254  // get number of particles to send, and where
255  msg->get(nodedata); // node, number of particles
256 
257  // put the particles in a new message
258  Message *sendmsg = new Message;
259  int delpart = LocalNum-1;
260  for (int ip=0; ip<nodedata[1]; ip++) {
261  while ( !(bool((*canSwap)[delpart])) ) { --delpart; }
262  PData.putMessage(*sendmsg, 1, delpart);
263  // After putting particles in the message, we can delete them.
264  PData.destroy(1, delpart, true);
265  }
266  LocalNum -= nodedata[1];
267  sendnum -= nodedata[1];
268 
269  //dbgmsg << "Sending " << nodedata[1] << " particles to node ";
270  //dbgmsg << nodedata[0] << endl;
271 
272  Ippl::Comm->send(sendmsg, nodedata[0], tag3);
273  }
274  }
275 
276  // we no longer need the message from node 0 telling us what to do
277  delete msg;
278 
279  // step 5: receive particles, add them to our list
280  while (recnum > 0) {
281  // receive next message with particle data for us
283  // dbgmsg<< "Receiving particles (" << recnum << " yet to arrive)" << endl;
284  msg = Ippl::Comm->receive_block(node, tag3);
285  int recvamt = PData.getMessage(*msg);
286  delete msg;
287 
288  //dbgmsg << "Received " << recvamt << " particles" << endl;
289  LocalNum += recvamt;
290  recnum -= recvamt;
291  }
292 
293  // finally, update our particle number counts
294  PData.setTotalNum(TotalNum); // set the total atom count
295  PData.setLocalNum(LocalNum); // set the number of local atoms
296 }
297 
298 
300 // print it out
301 template<class T, unsigned Dim>
302 inline
303 std::ostream& operator<<(std::ostream& out, const ParticleUniformLayout<T,Dim>& /*L*/) {
304 
305  out << "ParticleUniformLayout" << std::endl;
306  return out;
307 }
308 
309 
311 // print out debugging information
312 template<class T, unsigned Dim>
314 
315  o << "ParticleUniformLayout";
316 }
317 
318 
319 /***************************************************************************
320  * $RCSfile: addheaderfooter,v $ $Author: adelmann $
321  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:17 $
322  * IPPL_VERSION_ID: $Id: addheaderfooter,v 1.1.1.1 2003/01/23 07:40:17 adelmann Exp $
323  ***************************************************************************/
324 
#define P_WEIGHTED_RETURN_TAG
Definition: Tags.h:78
#define P_WEIGHTED_LAYOUT_TAG
Definition: Tags.h:77
#define P_WEIGHTED_TRANSFER_TAG
Definition: Tags.h:79
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
std::ostream & operator<<(std::ostream &out, const ParticleUniformLayout< T, Dim > &)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
bool send(Message *, int node, int tag, 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
void update(IpplParticleBase< ParticleUniformLayout< T, Dim > > &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