OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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
21template <unsigned Dim> class FieldLayout;
22class UserList;
23
25// constructor, from a FieldLayout
26template < 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
36template < 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
47template < 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.
58template < class T, unsigned Dim, class Mesh, class CachingPolicy >
60{
61 setup(); // perform necessary setup
62}
63
64
66// perform common constructor tasks
67template < 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];
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}
96
98// destructor
99template < 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.
120template <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.
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
244template < class T, unsigned Dim, class Mesh, class CachingPolicy >
245std::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.
258template < 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.
272template < 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
281template < 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
virtual void Repartition(UserList *)
RegionLayout< T, Dim, Mesh > & getLayout()
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