OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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
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
248void 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
275void 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}
const int nr
Definition: ClassicRandom.h:24
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFOMSG(msg)
Definition: IpplInfo.h:348
bool isInside(int idx, int idy, int idz) const override
queries if a given (x,y,z) coordinate lies inside the domain
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
void compute(Vector_t hr, NDIndex< 3 > localId) override
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
PointList_t intersectLoY_m
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
Inform * gmsg
Definition: Main.cpp:61