OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
ArbitraryDomain.cpp
Go to the documentation of this file.
1 //
2 // Class ArbitraryDomain
3 // Interface to iterative solver and boundary geometry
4 // for space charge calculation
5 //
6 // Copyright (c) 2008, Yves Ineichen, ETH Zürich,
7 // 2013 - 2015, Tülin Kaman, Paul Scherrer Institut, Villigen PSI, Switzerland
8 // 2016, Daniel Winklehner, Massachusetts Institute of Technology
9 // 2017 - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
10 // All rights reserved
11 //
12 // Implemented as part of the master thesis
13 // "A Parallel Multigrid Solver for Beam Dynamics"
14 // and the paper
15 // "A fast parallel Poisson solver on irregular domains applied to beam dynamics simulations"
16 // (https://doi.org/10.1016/j.jcp.2010.02.022)
17 //
18 // This file is part of OPAL.
19 //
20 // OPAL is free software: you can redistribute it and/or modify
21 // it under the terms of the GNU General Public License as published by
22 // the Free Software Foundation, either version 3 of the License, or
23 // (at your option) any later version.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
27 //
28 
29 //#define DEBUG_INTERSECT_RAY_BOUNDARY
30 
33 
34 #include <cmath>
35 #include <iostream>
36 #include <tuple>
38 #include "Index/NDIndex.h"
39 
42  Vector_t hr,
43  std::string interpl)
44  : IrregularDomain(nr, hr, interpl)
45 {
46  bgeom_m = bgeom;
47 
48  setRangeMin(bgeom->getmincoords());
49  setRangeMax(bgeom->getmaxcoords());
50 
51  bool have_inside_pt = bgeom->getInsidePoint(globalInsideP0_m);
52  if (have_inside_pt == false) {
53  throw OpalException(
54  "ArbitraryDomain::ArbitraryDomain()",
55  "No point inside geometry found/set!");
56  }
57 
58  throw OpalException("ArbitraryDomain::ArbitraryDomain()",
59  "This domain is currently not available.");
60 }
61 
63  //nothing so far
64 }
65 
67 
68  INFOMSG(level2 << "* Starting the Boundary Intersection Tests..." << endl);
69 
70  setHr(hr);
71 
72  int zGhostOffsetLeft = (localId[2].first()== 0) ? 0 : 1;
73  int zGhostOffsetRight = (localId[2].last() == nr_m[2] - 1) ? 0 : 1;
74  int yGhostOffsetLeft = (localId[1].first()== 0) ? 0 : 1;
75  int yGhostOffsetRight = (localId[1].last() == nr_m[1] - 1) ? 0 : 1;
76  int xGhostOffsetLeft = (localId[0].first()== 0) ? 0 : 1;
77  int xGhostOffsetRight = (localId[0].last() == nr_m[0] - 1) ? 0 : 1;
78 
79  hasGeometryChanged_m = true;
80 
81  intersectLoX_m.clear();
82  intersectHiX_m.clear();
83  intersectLoY_m.clear();
84  intersectHiY_m.clear();
85  intersectLoZ_m.clear();
86  intersectHiZ_m.clear();
87 
88  // Calculate intersection
89  Vector_t P, dir, I;
91 
92  // We cannot assume that the geometry is symmetric about the xy, xz, and yz planes!
93  // In my spiral inflector simulation, this is not the case for z direction for
94  // example (-0.13 to +0.025). -DW
95  for (int idz = localId[2].first()-zGhostOffsetLeft; idz <= localId[2].last()+zGhostOffsetRight; idz++) {
96 
97  P[2] = getZRangeMin() + (idz + 0.5) * hr[2];
98 
99  for (int idy = localId[1].first()-yGhostOffsetLeft; idy <= localId[1].last()+yGhostOffsetRight; idy++) {
100 
101  P[1] = getYRangeMin() + (idy + 0.5) * hr[1];
102 
103  for (int idx = localId[0].first()-xGhostOffsetLeft; idx <= localId[0].last()+xGhostOffsetRight; idx++) {
104 
105  P[0] = getXRangeMin() + (idx + 0.5) * hr[0];
106 
107  if (bgeom_m->fastIsInside(P0, P) % 2 == 0) {
108 
109  // Fill the map with true or false values for very fast isInside tests
110  // during the rest of the fieldsolve.
111  isInsideMap_m[toCoordIdx(idx, idy, idz)] = true;
112 
113  // Replace the old reference point with the new point (which we know is
114  // inside because we just tested for it. This makes the algorithm faster
115  // because fastIsInside() creates a number of segments that depends on the
116  // distance between P and P0. Using the previous P as the new P0
117  // assures the smallest possible distance in most cases. -DW
118  P0 = P;
119 
120  std::tuple<int, int, int> pos(idx, idy, idz);
121 
122  dir = Vector_t(0, 0, 1);
123 
124  if (bgeom_m->intersectRayBoundary(P, dir, I)) {
125  intersectHiZ_m.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[2]));
126  } else {
127 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
128  *gmsg << "zdir=+1 " << dir << " x,y,z= " << idx << "," << idy
129  << "," << idz << " P=" << P <<" I=" << I << endl;
130 #endif
131  }
132 
133  if (bgeom_m->intersectRayBoundary(P, -dir, I)) {
134  intersectLoZ_m.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[2]));
135  } else {
136 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
137  *gmsg << "zdir=-1 " << -dir << " x,y,z= " << idx << "," << idy
138  << "," << idz << " P=" << P <<" I=" << I << endl;
139 #endif
140  }
141 
142  dir = Vector_t(0, 1, 0);
143 
144  if (bgeom_m->intersectRayBoundary(P, dir, I)) {
145  intersectHiY_m.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[1]));
146  } else {
147 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
148  *gmsg << "ydir=+1 " << dir << " x,y,z= " << idx << "," << idy
149  << "," << idz << " P=" << P <<" I=" << I << endl;
150 #endif
151  }
152 
153  if (bgeom_m->intersectRayBoundary(P, -dir, I)) {
154  intersectLoY_m.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[1]));
155  } else {
156 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
157  *gmsg << "ydir=-1" << -dir << " x,y,z= " << idx << "," << idy
158  << "," << idz << " P=" << P <<" I=" << I << endl;
159 #endif
160  }
161 
162  dir = Vector_t(1, 0, 0);
163 
164  if (bgeom_m->intersectRayBoundary(P, dir, I)) {
165  intersectHiX_m.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[0]));
166  } else {
167 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
168  *gmsg << "xdir=+1 " << dir << " x,y,z= " << idx << "," << idy
169  << "," << idz << " P=" << P <<" I=" << I << endl;
170 #endif
171  }
172 
173  if (bgeom_m->intersectRayBoundary(P, -dir, I)){
174  intersectLoX_m.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[0]));
175  } else {
176 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
177  *gmsg << "xdir=-1 " << -dir << " x,y,z= " << idx << "," << idy
178  << "," << idz << " P=" << P <<" I=" << I << endl;
179 #endif
180  }
181  } else {
182  isInsideMap_m[toCoordIdx(idx, idy, idz)] = false;
183 #ifdef DEBUG_INTERSECT_RAY_BOUNDARY
184  *gmsg << "OUTSIDE" << " x,y,z= " << idx << "," << idy
185  << "," << idz << " P=" << P <<" I=" << I << endl;
186 #endif
187  }
188  }
189  }
190  }
191 
192  INFOMSG(level2 << "* Finding number of ghost nodes to the left..." << endl);
193 
194  //number of ghost nodes to the left
195  int numGhostNodesLeft = 0;
196  if(localId[2].first() != 0) {
197  for(int idx = 0; idx < nr_m[0]; idx++) {
198  for(int idy = 0; idy < nr_m[1]; idy++) {
199  if(isInside(idx, idy, localId[2].first() - zGhostOffsetLeft))
200  numGhostNodesLeft++;
201  }
202  }
203  }
204 
205  INFOMSG(level2 << "* Finding number of xy points in each plane along z..." << endl);
206 
207  //xy points in z plane
208  int numtotal = 0;
209  numXY_m.clear();
210  for(int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
211  int numxy = 0;
212  for(int idx = 0; idx < nr_m[0]; idx++) {
213  for(int idy = 0; idy < nr_m[1]; idy++) {
214  if(isInside(idx, idy, idz))
215  numxy++;
216  }
217  }
218  numXY_m[idz-localId[2].first()] = numxy;
219  numtotal += numxy;
220  }
221 
222  int startIdx = 0;
223  MPI_Scan(&numtotal, &startIdx, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
224  startIdx -= numtotal;
225 
226  // Build up index and coord map
227  idxMap_m.clear();
228  coordMap_m.clear();
229  int index = startIdx - numGhostNodesLeft;
230 
231  INFOMSG(level2 << "* Building up index and coordinate map..." << endl);
232 
233  for(int idz = localId[2].first() - zGhostOffsetLeft; idz <= localId[2].last() + zGhostOffsetRight; idz++) {
234  for(int idy = 0; idy < nr_m[1]; idy++) {
235  for(int idx = 0; idx < nr_m[0]; idx++) {
236  if(isInside(idx, idy, idz)) {
237  idxMap_m[toCoordIdx(idx, idy, idz)] = index;
238  coordMap_m[index] = toCoordIdx(idx, idy, idz);
239  index++;
240  }
241  }
242  }
243  }
244 
245  INFOMSG(level2 << "* Done." << endl);
246 }
247 
248 void ArbitraryDomain::constantInterpolation(int idx, int idy, int idz,
249  StencilValue_t& value, double& /*scaleFactor*/) const
250 {
251  value.west = -1/(hr_m[0]*hr_m[0]);
252  value.east = -1/(hr_m[0]*hr_m[0]);
253  value.north = -1/(hr_m[1]*hr_m[1]);
254  value.south = -1/(hr_m[1]*hr_m[1]);
255  value.front = -1/(hr_m[2]*hr_m[2]);
256  value.back = -1/(hr_m[2]*hr_m[2]);
257  value.center = 2/(hr_m[0]*hr_m[0]) + 2/(hr_m[1]*hr_m[1]) + 2/(hr_m[2]*hr_m[2]);
258 
259  if(!isInside(idx-1,idy,idz))
260  value.west = 0.0;
261  if(!isInside(idx+1,idy,idz))
262  value.east = 0.0;
263 
264  if(!isInside(idx,idy+1,idz))
265  value.north = 0.0;
266  if(!isInside(idx,idy-1,idz))
267  value.south = 0.0;
268 
269  if(!isInside(idx,idy,idz-1))
270  value.front = 0.0;
271  if(!isInside(idx,idy,idz+1))
272  value.back = 0.0;
273 }
274 
275 void ArbitraryDomain::linearInterpolation(int idx, int idy, int idz,
276  StencilValue_t& value, double &scaleFactor) const
277 {
278  scaleFactor = 1;
279 
280  double cx = (idx - (nr_m[0]-1)/2.0)*hr_m[0];
281  double cy = (idy - (nr_m[1]-1)/2.0)*hr_m[1];
282  double cz = (idz - (nr_m[2]-1)/2.0)*hr_m[2];
283 
284  double dx_w=hr_m[0];
285  double dx_e=hr_m[0];
286  double dy_n=hr_m[1];
287  double dy_s=hr_m[1];
288  double dz_f=hr_m[2];
289  double dz_b=hr_m[2];
290  value.center = 0.0;
291 
292  std::tuple<int, int, int> coordxyz(idx, idy, idz);
293 
294  if (idx == nr_m[0]-1)
295  dx_e = std::abs(intersectHiX_m.find(coordxyz)->second - cx);
296  if (idx == 0)
297  dx_w = std::abs(intersectLoX_m.find(coordxyz)->second - cx);
298  if (idy == nr_m[1]-1)
299  dy_n = std::abs(intersectHiY_m.find(coordxyz)->second - cy);
300  if (idy == 0)
301  dy_s = std::abs(intersectLoY_m.find(coordxyz)->second - cy);
302  if (idz == nr_m[2]-1)
303  dz_b = std::abs(intersectHiZ_m.find(coordxyz)->second - cz);
304  if (idz == 0)
305  dz_f = std::abs(intersectLoZ_m.find(coordxyz)->second - cz);
306 
307  if(dx_w != 0)
308  value.west = -(dz_f + dz_b) * (dy_n + dy_s) / dx_w;
309  else
310  value.west = 0;
311  if(dx_e != 0)
312  value.east = -(dz_f + dz_b) * (dy_n + dy_s) / dx_e;
313  else
314  value.east = 0;
315  if(dy_n != 0)
316  value.north = -(dz_f + dz_b) * (dx_w + dx_e) / dy_n;
317  else
318  value.north = 0;
319  if(dy_s != 0)
320  value.south = -(dz_f + dz_b) * (dx_w + dx_e) / dy_s;
321  else
322  value.south = 0;
323  if(dz_f != 0)
324  value.front = -(dx_w + dx_e) * (dy_n + dy_s) / dz_f;
325  else
326  value.front = 0;
327  if(dz_b != 0)
328  value.back = -(dx_w + dx_e) * (dy_n + dy_s) / dz_b;
329  else
330  value.back = 0;
331 
332  //RHS scaleFactor for current 3D index
333  //0.5* comes from discretiztaion
334  //scaleFactor = 0.5*(dw+de)*(dn+ds)*(df+db);
335  scaleFactor = 0.5;
336  if(dx_w + dx_e != 0)
337  scaleFactor *= (dx_w + dx_e);
338  if(dy_n + dy_s != 0)
339  scaleFactor *= (dy_n + dy_s);
340  if(dz_f + dz_b != 0)
341  scaleFactor *= (dz_f + dz_b);
342 
343  //catch the case where a point lies on the boundary
344  double m1 = dx_w * dx_e;
345  double m2 = dy_n * dy_s;
346  if(dx_e == 0)
347  m1 = dx_w;
348  if(dx_w == 0)
349  m1 = dx_e;
350  if(dy_n == 0)
351  m2 = dy_s;
352  if(dy_s == 0)
353  m2 = dy_n;
354 
355  value.center = 2 / hr_m[2];
356  if(dx_w != 0 || dx_e != 0)
357  value.center *= (dx_w + dx_e);
358  if(dy_n != 0 || dy_s != 0)
359  value.center *= (dy_n + dy_s);
360  if(dx_w != 0 || dx_e != 0)
361  value.center += (dz_f + dz_b) * (dy_n + dy_s) * (dx_w + dx_e) / m1;
362  if(dy_n != 0 || dy_s != 0)
363  value.center += (dz_f + dz_b) * (dx_w + dx_e) * (dy_n + dy_s) / m2;
364 }
Inform * gmsg
Definition: Main.cpp:62
const int nr
Definition: ClassicRandom.h:24
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
#define INFOMSG(msg)
Definition: IpplInfo.h:348
PointList_t intersectHiY_m
all intersection points with gridlines in Y direction
std::map< int, bool > isInsideMap_m
void linearInterpolation(int idx, int idy, int idz, StencilValue_t &value, double &scaleFactor) const override
PointList_t intersectLoZ_m
BoundaryGeometry * bgeom_m
Vector_t globalInsideP0_m
int toCoordIdx(int idx, int idy, int idz) const
PointList_t intersectHiZ_m
all intersection points with gridlines in Z direction
std::map< int, int > numXY_m
PointList_t intersectHiX_m
all intersection points with gridlines in X direction
PointList_t intersectLoX_m
ArbitraryDomain(BoundaryGeometry *bgeom, IntVector_t nr, Vector_t hr, std::string interpl)
void constantInterpolation(int idx, int idy, int idz, StencilValue_t &value, double &scaleFactor) const override
different interpolation methods for boundary points
void compute(Vector_t hr, NDIndex< 3 > localId)
PointList_t intersectLoY_m
bool isInside(int idx, int idy, int idz) const
queries if a given (x,y,z) coordinate lies inside the domain
IntVector_t nr_m
number of mesh points in each direction
std::map< int, int > coordMap_m
mapping idx -> (x,y,z)
void setRangeMin(const Vector_t &min)
bool hasGeometryChanged_m
flag indicating if geometry has changed for the current time-step
double getZRangeMin() const
double getXRangeMin() const
std::map< int, int > idxMap_m
mapping (x,y,z) -> idx
double getYRangeMin() const
Vector_t hr_m
mesh-spacings in each direction
void setRangeMax(const Vector_t &max)
void setHr(Vector_t hr)
int fastIsInside(const Vector_t &reference_pt, const Vector_t &P)
int intersectRayBoundary(const Vector_t &P, const Vector_t &v, Vector_t &I)
Vector_t getmincoords()
Vector_t getmaxcoords()
bool getInsidePoint(Vector_t &pt)
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6