OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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
38template<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
50template<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.
64template<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
301template<class T, unsigned Dim>
302inline
303std::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
312template<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