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