OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
HashPairBuilderPeriodicParallel_globCHaining.h
Go to the documentation of this file.
1 #ifndef HASH_PAIR_BUILDER_PERIODIC_PARALLEL_H
2 #define HASH_PAIR_BUILDER_PERIODIC_PARALLEL_H
3 
4 #include <algorithm>
5 #include <limits>
6 #include <cmath>
7 #include <set>
8 
9 template<class PBase>
11 {
12 public:
13  enum { Dim = PBase::Dim };
14  typedef typename PBase::Position_t Position_t;
15 
17 
18  template<class Pred, class OP>
19  void for_each(const Pred& pred, const OP &op,Vektor<double,3> extend_l, Vektor<double,3> extend_r )
20  {
21  const std::size_t END = std::numeric_limits<std::size_t>::max();
22  std::size_t size = particles.getLocalNum()+particles.getGhostNum();
23 
24  Inform dmsg("debug_msg:");
25  std::cout << "We use parallel hash pair builder ****************************" << std::endl;
26 
27  //compute which dimensions are really serial process neighbors itself in this direction
28  Vektor<bool,3> parallel_dims(0,0,0);
29 
30  NDIndex<3> globDomain = particles.getFieldLayout().getDomain();
31  NDIndex<3> locDomain = particles.getFieldLayout().getLocalNDIndex();
32 
33  parallel_dims[0] = !(globDomain[0]==locDomain[0]);
34  parallel_dims[1] = !(globDomain[1]==locDomain[1]);
35  parallel_dims[2] = !(globDomain[2]==locDomain[2]);
36 
37  Vektor<double,3> period;
38  period=extend_r-extend_l;
39 
40  //make sure that the chaining mesh covers the whole domain and has a gridwidth > r_cut
41  buckets_per_dim[0]=floor(period[0]/pred.getRange(0));
42  buckets_per_dim[1]=floor(period[1]/pred.getRange(1));
43  buckets_per_dim[2]=floor(period[2]/pred.getRange(2));
44 
45  for (unsigned dim = 0; dim<3; ++dim)
46  h_chaining[dim] = period[dim]/buckets_per_dim[dim];
47 
48  //extend the chaining mesh by one layer of chaining cells in each dimension
49  rmin_m = extend_l-h_chaining;
50  rmax_m = extend_r+h_chaining;
51  buckets_per_dim+=2;
52 
53  dmsg << " period = " << period << endl;
54  dmsg << "buckets per dim = " << buckets_per_dim << endl;
55  dmsg << "h_chaining = " << h_chaining << endl;
56 
57  std::size_t Nbucket = buckets_per_dim[0]*buckets_per_dim[1]*buckets_per_dim[2];
58 
59  std::size_t *buckets = new size_t[Nbucket]; //index of first particle in this bucket
60  std::size_t *next = new size_t[size]; //index of next particle in this bucket. END indicates last particle of bucket
61  std::fill(buckets, buckets+Nbucket, END);
62  std::fill(next, next+size, END);
63 
64  //in 3D we interact with 14 neighboring cells (including self cell interaction)
65  unsigned neigh = 14;
66 
67  int offset[14][3] = {{ 1, 1, 1}, { 0, 1, 1}, {-1, 1, 1},
68  { 1, 0, 1}, { 0, 0, 1}, {-1, 0, 1},
69  { 1,-1, 1}, { 0,-1, 1}, {-1,-1, 1},
70  { 1, 1, 0}, { 0, 1, 0}, {-1, 1, 0},
71  { 1, 0, 0}, { 0, 0, 0}};
72 
73  //assign all particles to a bucket
74  for(std::size_t i = 0;i<size;++i)
75  {
76  unsigned bucket_id = get_bucket_id(i,pred);
77  next[i] = buckets[bucket_id];
78  buckets[bucket_id] = i;
79  }
80 
81  double part_count = 0;
82  //loop over all buckets
83  for (int bx=0+int(!parallel_dims[0]); bx<buckets_per_dim[0]-int(!parallel_dims[0]); ++bx) {
84  for (int by=0+int(!parallel_dims[1]); by<buckets_per_dim[1]-int(!parallel_dims[1]); ++by) {
85  for (int bz=0+int(!parallel_dims[2]); bz<buckets_per_dim[2]-int(!parallel_dims[2]); ++bz) {
86  unsigned bucket_id_self = bz*buckets_per_dim[1]*buckets_per_dim[0]+by*buckets_per_dim[0]+bx;
87  //compute index of neighboring bucket to interact with
88  for (unsigned n=0; n<neigh;++n){
89  int bx_neigh, by_neigh, bz_neigh;
90  Vektor<double,3> shift(0,0,0);
91 
92  bx_neigh = bx+offset[n][0];
93  //if we are serial in x-dimension we have no cached ghost particles. The local positions get periodically shifted
94  if (!parallel_dims[0]) {
95  if (bx_neigh == 0) {
96  //bucket in -x direction exceed domain boundary
97  bx_neigh+=(buckets_per_dim[0]-2);//consider last bucket in +x instead
98  shift[0] = -period[0];//shift particles in negative x direction by domain size
99  }
100  else if (bx_neigh == (buckets_per_dim[0]-1)) {
101  //bucket in +x direction exceeds domain boundary
102  bx_neigh -= (buckets_per_dim[0]-2);//consider first bucket in +x instead
103  shift[0] = period[0];//shift particles in positive x direction by domain size
104  }
105  }
106  //do the same for y and z direction:
107  by_neigh = by+offset[n][1];
108  if (!parallel_dims[1]) {
109  if (by_neigh == 0) {
110  by_neigh+=(buckets_per_dim[1]-2);
111  shift[1] = -period[0];
112  }
113  else if (by_neigh == (buckets_per_dim[1]-1)) {
114  by_neigh -=(buckets_per_dim[1]-2);
115  shift[1] = period[1];
116  }
117  }
118 
119  bz_neigh = bz+offset[n][2];
120  if (!parallel_dims[2]) {
121  if (bz_neigh == 0) {
122  bz_neigh+=(buckets_per_dim[2]-2);
123  shift[2] = -period[2];
124  }
125  else if (bz_neigh == (buckets_per_dim[2]-1)) {
126  bz_neigh -=(buckets_per_dim[2]-2);
127  shift[2] = period[2];
128  }
129  }
130 
131  if (bx_neigh >= 0 && bx_neigh<buckets_per_dim[0] &&
132  by_neigh >= 0 && by_neigh<buckets_per_dim[1] &&
133  bz_neigh >= 0 && bz_neigh<buckets_per_dim[2]) {
134 
135  unsigned bucket_id_neigh =
136  bz_neigh*buckets_per_dim[1]*buckets_per_dim[0]+by_neigh*buckets_per_dim[0]+bx_neigh;
137 
138  //i is index of particle considered in active cahining cell, j is index of neighbor particle considered
139  std::size_t i = buckets[bucket_id_self];
140  std::size_t j;
141 
142  //loop over all particles in self cell
143  //self offset avoids double counting in self cell
144  int self_offset = 0;
145  part_count = 0;
146  while (i != END) {
147  part_count++;
148  j = buckets[bucket_id_neigh];
149  //increase offset by number of processed particles in self cell
150  for (int o=0;o<self_offset;o++){
151  j = next[j];
152  }
153  //loop over all particles in neighbor cell
154  while(j != END) {
155  if(pred(particles.R[i], particles.R[j]+shift)) {
156  if (i!=j)
157  op(i, j, particles, shift);
158  }
159  j = next[j];
160  }
161  i = next[i];
162  //adjust self_offset
163  if (bucket_id_self==bucket_id_neigh)
164  self_offset++;
165  else
166  self_offset=0;
167  }
168  }
169  }
170 
171  }
172  }
173  }
174 
175  delete[] buckets;
176  delete[] next;
177  }
178 private:
179 
180  //returns the bucket id of particle i
181  template<class Pred>
182  int get_bucket_id(int i, const Pred& pred)
183  {
184  Vektor<int,3> loc;
185  for (unsigned d=0; d<3; ++d)
186  loc[d] = (particles.R[i][d]-rmin_m[d])/h_chaining[d];
187  int bucket_id = loc[2]*buckets_per_dim[1]*buckets_per_dim[0]+loc[1]*buckets_per_dim[0]+loc[0];
188  //std::cout << "bucket id of particle " << i << "with coords " << particles.R[i] << " = [" << loc[0] << "," << loc[1] << "," << loc[2] << "] => bucket id = " << bucket_id << std::endl;
189  //std::cout << particles.R[i][0] << "," << particles.R[i][1] << "," << particles.R[i][2] << "," << bucket_id << std::endl;
190 
191  return bucket_id;
192  }
193 
194  PBase &particles;
199 };
200 
201 
202 #endif
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
Position_t
Definition: Types.h:28
void for_each(const Pred &pred, const OP &op, Vektor< double, 3 > extend_l, Vektor< double, 3 > extend_r)
const unsigned Dim
Definition: Inform.h:41
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:816
Inform & endl(Inform &inf)
Definition: Inform.cpp:42