OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
BoxParticleCachingPolicy.h
Go to the documentation of this file.
1#ifndef BOX_PARTICLE_CACHING_POLICY
2#define BOX_PARTICLE_CACHING_POLICY
3
4/*
5 *
6 * The Box caching layout ensures that each node has all ghost particles
7 * for each external particle that is inside an extended bounding box
8 *
9 */
10
11
12#include <algorithm>
13#include <map>
14
15#include "Message/Message.h"
16#include "Message/Communicate.h"
17#include "Message/Format.h"
18#include "Message/MsgBuffer.h"
19
20template <class T, unsigned Dim, class Mesh, class CachingPolicy> class ParticleSpatialLayout;
21
22template<class T, unsigned Dim, class Mesh>
24public:
26 {
27 std::fill(boxDimension, boxDimension+Dim, T());
28 }
29
30 void setCacheDimension(int d, T length)
31 {
32 boxDimension[d] = length;
33 }
34
36 {
37 std::fill(boxDimension, boxDimension+Dim, length);
38 }
39 template<class C>
42 )
43 {
44 RegionLayout<T,Dim,Mesh> &RLayout = PLayout.getLayout();
45 NDRegion<T,Dim> globalDomain = RLayout.getDomain();
46
47 typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN = RLayout.begin_iv();
48 typename RegionLayout<T,Dim,Mesh>::iterator_iv localVNend = RLayout.end_iv();
49
50 regions.clear();
51
52
53 //fill in boundary conditions
54 std::fill(periodic, periodic+2*Dim, false);
55
57 {
60
61 for (unsigned d=0; d<2*Dim; ++d)
62 {
63 if(pBConds[d] == periodicBCond)
64 {
65 periodic[d] = true;
66 }
67 }
68 }
69
70
71 for (;localVN!=localVNend;++localVN)
72 {
73 //get local domain
74 NDRegion<T,Dim> ldom = (*localVN).second->getDomain();
75
76 //extrude local domain
77 NDRegion<T,Dim> exdom;
78 for(unsigned int d = 0;d<Dim;++d)
79 {
80 exdom[d] = PRegion<T>(ldom[d].first()- boxDimension[d],
81 ldom[d].last() + boxDimension[d]);
82 }
83
84 Offset_t offset;
85 std::fill(offset.begin(), offset.end(), 0);
86
87 //get all relevant offsets
88 for(unsigned int d = 0;d<Dim;++d)
89 {
90 if(periodic[2*d] && (exdom[d].first() < globalDomain[d].first()))
91 {
92 offset[d] = globalDomain[d].length();
93 }
94 else if(periodic[2*d+1] && (exdom[d].last() > globalDomain[d].last()))
95 {
96 offset[d] = -globalDomain[d].length();
97 }
98 }
99 //cycle through all combinations
100 int onoff[Dim];
101 std::fill(onoff, onoff+Dim, 0);
102 while(true)
103 {
104
105 NDRegion<T,Dim> chckdom;
106 for(unsigned int d = 0;d<Dim;++d)
107 {
108 chckdom[d] = PRegion<T>(ldom[d].first()- boxDimension[d]+onoff[d]*offset[d],
109 ldom[d].last() + boxDimension[d]+onoff[d]*offset[d]);
110 }
111
112 //get touched external domains
113 typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchRange = RLayout.touch_range_rdv(chckdom);
114
115
117
118
119 for(i = touchRange.first; i != touchRange.second; ++i)
120 {
121 int node = (*i).second->getNode();
122 if(node == Ippl::myNode())//don't add local node
123 continue;
124 NDRegion<T,Dim> dom = (*i).second->getDomain();
125 Offset_t tmpoffset;
126 for(unsigned int d = 0;d<Dim;++d)
127 {
128 dom[d] = PRegion<T>(dom[d].first() - onoff[d]*offset[d],
129 dom[d].last() - onoff[d]*offset[d]);
130 tmpoffset[d] = onoff[d]*offset[d];
131 }
132
133 regions[node].push_back(std::make_pair(dom,tmpoffset));
134
135 }
136
137 //generate next combinations. this is basically a binary incrementer
138 unsigned int j = 0;
139 for(;j<Dim;++j)
140 {
141 if(offset[j]==0)
142 continue;//skip irrelevant directions
143 if((onoff[j] = !onoff[j]))
144 break;//flip and continue if there's a "carry"
145 }
146
147 if(j==Dim)
148 break;
149 }
150
151 }
152 }
153
154 template<class C>
158 )
159 {
160
162 typedef typename std::map<unsigned, std::list<std::pair<NDRegion<T,Dim>, Offset_t> > >::iterator m_iterator;
163
164 //dump the old ghost particles
165 PData.ghostDestroy(PData.getGhostNum(), 0);
166
167 //get tag
169
170 //these are needed to free data for nonblocking sends
171 std::vector<MPI_Request> requests;
172 std::vector<MsgBuffer*> buffers;
173
174 //for each possible target node
175 for(m_iterator n = regions.begin();n!=regions.end();++n)
176 {
177 int node = n->first;
178
179 //find particles that need to be sent
180 std::vector<size_t> sendlist;
181 std::vector<Offset_t> offsetlist;
182 for(typename std::list<std::pair<NDRegion<T,Dim>, Offset_t> >::iterator li = n->second.begin();li!=n->second.end();++li)
183 {
184 NDRegion<T, Dim> region = (*li).first;
185
186 for (unsigned int i = 0;i < PData.getLocalNum();++i)
187 {
188 NDRegion<T,Dim> ploc;
189 for (unsigned int d = 0;d < Dim;++d)
190 ploc[d] = PRegion<T>(PData.R[i][d] - boxDimension[d],
191 PData.R[i][d] + boxDimension[d]);
192
193 if(region.touches(ploc))
194 {
195 sendlist.push_back(i);
196 offsetlist.push_back((*li).second);
197 }
198 }
199 }
200
201
202 //and send them
203 if(sendlist.empty())
204 {
205 //don't bother creating an empty buffer just send an empty message
206 requests.push_back(Ippl::Comm->raw_isend(0, 0, node, tag));
207 }
208 else
209 {
210 //pack and send ghost particles
211 MsgBuffer *msgbuf = 0;
212 PData.writeMsgBufferWithOffsets(msgbuf, sendlist,offsetlist);
213 MPI_Request request = Ippl::Comm->raw_isend(msgbuf->getBuffer(), msgbuf->getSize(), node, tag);
214
215 requests.push_back(request);
216 buffers.push_back(msgbuf);
217 }
218
219 }
220
221
222 //receive ghost particles
223 Format *format = PData.getFormat();
224
225 for(unsigned int n = 0;n<regions.size();++n)
226 {
228 char *buffer = 0;
229 int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
230 if(bufsize>0)
231 {
232 MsgBuffer recvbuf(format, buffer, bufsize);
233 PData.readGhostMsgBuffer(&recvbuf, node);
234 }
235 }
236
237 //wait for communication to finish and clean up buffers
238 MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
239 MPI_Waitall(requests.size(), requests_ptr, MPI_STATUSES_IGNORE);
240 for (unsigned int j = 0; j<buffers.size(); ++j)
241 {
242 delete buffers[j]->getFormat();
243 delete buffers[j];
244 }
245
246 delete format;
247 }
248protected:
250private:
251 struct Offset_t
252 {
254 T& operator[](int i) { return data[i]; }
255 T operator[](int i) const { return data[i]; }
256 T* begin() { return data; }
257 T* end() { return data+Dim; }
258 };
259
261 bool periodic[2*Dim];
262 std::map<unsigned, std::list<std::pair<NDRegion<T,Dim>, Offset_t> > > regions;
263};
264
265#endif
const unsigned Dim
#define P_SPATIAL_GHOST_TAG
Definition: Tags.h:83
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
T ParticlePeriodicBCond(const T t, const T minval, const T maxval)
std::string::iterator iterator
Definition: MSLang.h:16
virtual MPI_Request raw_isend(void *, int, int, int)
Definition: Communicate.h:196
virtual int raw_probe_receive(char *&, int &, int &)
Definition: Communicate.h:208
void barrier(void)
Definition: Format.h:27
void * getBuffer()
Definition: MsgBuffer.h:54
int getSize()
Definition: MsgBuffer.h:50
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
std::map< unsigned, std::list< std::pair< NDRegion< T, Dim >, Offset_t > > > regions
void updateCacheInformation(ParticleSpatialLayout< T, Dim, Mesh, C > &PLayout)
void updateGhostParticles(IpplParticleBase< ParticleSpatialLayout< T, Dim, Mesh, C > > &PData, ParticleSpatialLayout< T, Dim, Mesh, C > &)
void setCacheDimension(int d, T length)
ParticleBConds< T, Dim > & getBConds()
bool getUpdateFlag(UpdateFlags f) const
bool touches(const NDRegion< T, Dim > &nr) const
Definition: NDRegion.h:175
iterator_iv begin_iv()
Definition: RegionLayout.h:146
touch_range_dv touch_range_rdv(const NDRegion< T, Dim > &domain)
Definition: RegionLayout.h:159
ac_id_vnodes::iterator iterator_iv
Definition: RegionLayout.h:66
iterator_iv end_iv()
Definition: RegionLayout.h:147
const NDRegion< T, Dim > & getDomain() const
Definition: RegionLayout.h:131
std::pair< touch_iterator_dv, touch_iterator_dv > touch_range_dv
Definition: RegionLayout.h:71
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84