OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
BoxCornerDomain.cpp
Go to the documentation of this file.
1//
2// Class BoxCornerDomain
3// :FIXME: add brief description
4//
5// Copyright (c) 2008, Yves Ineichen, ETH Zürich,
6// 2013 - 2015, Tülin Kaman, Paul Scherrer Institut, Villigen PSI, Switzerland
7// 2017 - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
8// All rights reserved
9//
10// Implemented as part of the master thesis
11// "A Parallel Multigrid Solver for Beam Dynamics"
12// and the paper
13// "A fast parallel Poisson solver on irregular domains applied to beam dynamics simulations"
14// (https://doi.org/10.1016/j.jcp.2010.02.022)
15//
16// This file is part of OPAL.
17//
18// OPAL is free software: you can redistribute it and/or modify
19// it under the terms of the GNU General Public License as published by
20// the Free Software Foundation, either version 3 of the License, or
21// (at your option) any later version.
22//
23// You should have received a copy of the GNU General Public License
24// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
25//
28
29#include <map>
30#include <string>
31#include <cmath>
32#include <iostream>
33
34//FIXME: ORDER HOW TO TRAVERSE NODES IS FIXED, THIS SHOULD BE MORE GENERIC! (PLACES MARKED)
35
36BoxCornerDomain::BoxCornerDomain(double A, double B, double C,
37 double L1, double L2, IntVector_t nr, Vector_t hr,
38 std::string interpl)
39 : RegularDomain(nr, hr, interpl)
40{
41 setRangeMin(Vector_t(-A, -B, L1));
42 setRangeMax(Vector_t( A, B, L1 + L2));
43 C_m = C;
44
45 throw OpalException("BoxCornerDomain::BoxCornerDomain()",
46 "This domain is currently not supported!");
47}
48
50 //nothing so far
51}
52
53
54// for this geometry we only have to calculate the intersection on
55// all x-y-planes
56// for the moment we center the box corner geometry around the center of the grid
57// hr holds the grid-spacings (boundary ellipse embedded in hr-grid)
58
60
61 //there is nothing to be done if the mesh spacings have not changed
62 // if(hr_m[0] == getHr()[0] && hr_m[1] == getHr()[1] && hr_m[2] == getHr()[2]) {
63 // hasGeometryChanged_m = false;
64 // return;
65 // }
66
67 setHr(hr);
69
70 double bL= getB(getMinZ());
71 double bH= getB(getMaxZ());
72
74 actBMax_m = std::max(bL,bH);
75
76 //reset number of points inside domain
77
78 // clear previous coordinate maps
79 idxMap_m.clear();
80 coordMap_m.clear();
81 //clear previous intersection points
82 IntersectYDir.clear();
83 IntersectXDir.clear();
84
85 // build a index and coordinate map
86 int idx = 0;
87 int x, y, z;
88 for(x = 0; x < nr_m[0]; x++) {
89 for(y = 0; y < nr_m[1]; y++) {
90 for(z = 0; z < nr_m[2]; z++) {
91 if(isInside(x, y, z)) {
92 idxMap_m[toCoordIdx(x, y, z)] = idx;
93 coordMap_m[idx++] = toCoordIdx(x, y, z);
94 }
95 }
96 }
97 }
98
99 //XXX: calculate intersection on the fly
100 /*
101 switch(interpolationMethod_m) {
102
103 case CONSTANT:
104 break;
105 case LINEAR:
106 case QUADRATIC:
107
108 // calculate intersection
109
110 for(int z = 0; z < nr_m[2]; z++) {
111
112 for(int x = 0; x < nr_m[0]; x++) {
113 // the x coordinate does not change in the CornerBox geometry
114 std::pair<int, int> pos(x, z);
115 IntersectXDir.insert(std::pair< std::pair<int, int>, double >(pos, 0.5*getXRangeMax()));
116 IntersectXDir.insert(std::pair< std::pair<int, int>, double >(pos, 0.5*getXRangeMin()));
117 }
118
119 for(int y = 0; y < nr_m[1]; y++) {
120 std::pair<int, int> pos(y, z);
121 double yt = getB(z*hr_m[2]);
122 double yb = 0.5*getYRangeMin();
123 IntersectXDir.insert(std::pair< std::pair<int, int>, double >(pos, yt));
124 IntersectXDir.insert(std::pair< std::pair<int, int>, double >(pos, yb));
125 }
126 }
127 }
128 */
129}
130
132 double &scaleFactor) const
133{
134 scaleFactor = 1.0;
135
136 double cx = x * hr_m[0] - (nr_m[0] - 1) * hr_m[0] / 2.0;
137 double cy = y * hr_m[1] - (nr_m[1] - 1) * hr_m[1] / 2.0;
138
139 //XXX: calculate intersection on the fly
140 /*
141 multimap< pair<int, int>, double >::iterator it;
142 pair< multimap< pair<int, int>, double>::iterator, multimap< pair<int, int>, double>::iterator > ret;
143
144 double dx = 0.0;
145 std::pair<int, int> coordxz(x, z);
146 ret = IntersectXDir.equal_range(coordxz);
147 if(cx < 0)
148 it++;
149 dx = it->second;
150
151 double dy = 0.0;
152 std::pair<int, int> coordyz(y, z);
153 ret = IntersectYDir.equal_range(coordyz);
154 if(cy < 0)
155 it++;
156 dy = it->second;
157 */
158
159 double dw = hr_m[0];
160 double de = hr_m[0];
161 double dn = hr_m[1];
162 double ds = hr_m[1];
163 value.center = 0.0;
164
165 //we are a right boundary point
166 if(!isInside(x + 1, y, z)) {
167 double dx = getXIntersection(cx, z);
168 value.center += 1 / ((dx - cx) * de);
169 value.east = 0.0;
170 } else {
171 value.center += 1 / (de * de);
172 value.east = -1 / (de * de);
173 }
174
175 //we are a left boundary point
176 if(!isInside(x - 1, y, z)) {
177 double dx = getXIntersection(cx, z);
178 value.center += 1 / ((std::abs(dx) - std::abs(cx)) * dw);
179 value.west = 0.0;
180 } else {
181 value.center += 1 / (dw * dw);
182 value.west = -1 / (dw * dw);
183 }
184
185 //we are a upper boundary point
186 if(!isInside(x, y + 1, z)) {
187 double dy = getYIntersection(cy, z);
188 value.center += 1 / ((dy - cy) * dn);
189 value.north = 0.0;
190 } else {
191 value.center += 1 / (dn * dn);
192 value.north = -1 / (dn * dn);
193 }
194
195 //we are a lower boundary point
196 if(!isInside(x, y - 1, z)) {
197 double dy = getYIntersection(cy, z);
198 value.center += 1 / ((std::abs(dy) - std::abs(cy)) * ds);
199 value.south = 0.0;
200 } else {
201 value.center += 1 / (ds * ds);
202 value.south = -1 / (ds * ds);
203 }
204
205 value.front = -1 / (hr_m[2] * hr_m[2]);
206 value.back = -1 / (hr_m[2] * hr_m[2]);
207 value.center += 2 / (hr_m[2] * hr_m[2]);
208
209 // handle boundary condition in z direction
210 if(z == 0 || z == nr_m[2] - 1) {
211
212 // case where we are on the NEUMAN BC in Z-direction
213 // where we distinguish two cases
214 if(z == 0)
215 value.front = 0.0;
216 else
217 value.back = 0.0;
218
219 //hr_m[2]*(nr_m2[2]-1)/2 = radius
220 double d = hr_m[2] * (nr_m[2] - 1) / 2;
221 value.center += 2 / (d * hr_m[2]);
222
223 value.west /= 2.0;
224 value.east /= 2.0;
225 value.north /= 2.0;
226 value.south /= 2.0;
227 value.center /= 2.0;
228 scaleFactor *= 0.5;
229
230 }
231
232}
233
234//FIXME: this probably needs some cleanup/rewriting
236 double &scaleFactor) const
237{
238 double cx = (x - (nr_m[0] - 1) / 2.0) * hr_m[0];
239 double cy = (y - (nr_m[1] - 1) / 2.0) * hr_m[1];
240
241 double dx = getXIntersection(cx, z);
242 double dy = getYIntersection(cy, z);
243
244 //XXX: calculate intersection on the fly
245 /*
246 multimap< pair<int, int>, double >::iterator it;
247 pair< multimap< pair<int, int>, double>::iterator, multimap< pair<int, int>, double>::iterator > ret;
248
249 double dx = 0.0;
250 std::pair<int, int> coordxz(x, z);
251 ret = IntersectXDir.equal_range(coordxz);
252 if(cx < 0)
253 it++;
254 dx = it->second;
255
256 double dy = 0.0;
257 std::pair<int, int> coordyz(y, z);
258 ret = IntersectYDir.equal_range(coordyz);
259 if(cy < 0)
260 it++;
261 dy = it->second;
262 */
263
264 double dw = hr_m[0];
265 double de = hr_m[0];
266 double dn = hr_m[1];
267 double ds = hr_m[1];
268 value.west = 1.0;
269 value.east = 1.0;
270 value.north = 1.0;
271 value.south = 1.0;
272 value.front = 1.0;
273 value.back = 1.0;
274 value.center = 0.0;
275
276 //TODO: = cx+hr_m[0] > dx && cx > 0
277 //if((x-nr_m[0]/2.0+1)*hr_m[0] > dx && cx > 0) {
280 //de = dx-cx;
281 //}
282
283 //if((x-nr_m[0]/2.0-1)*hr_m[0] < dx && cx < 0) {
286 //dw = std::abs(dx)-std::abs(cx);
287 //}
288
289 //if((y-nr_m[1]/2.0+1)*hr_m[1] > dy && cy > 0) {
292 //dn = dy-cy;
293 //}
294
295 //if((y-nr_m[1]/2.0-1)*hr_m[1] < dy && cy < 0) {
298 //ds = std::abs(dy)-std::abs(cy);
299 //}
300
301 //TODO: = cx+hr_m[0] > dx && cx > 0
302 //if((x-nr_m[0]/2.0+1)*hr_m[0] > dx && cx > 0) {
303 //we are a right boundary point
304 if(!isInside(x + 1, y, z)) {
305 de = dx - cx;
306 value.east = 0.0;
307 }
308
309 //if((x-nr_m[0]/2.0-1)*hr_m[0] < dx && cx < 0) {
310 //we are a left boundary point
311 if(!isInside(x - 1, y, z)) {
312 dw = std::abs(dx) - std::abs(cx);
313 value.west = 0.0;
314 }
315
316 //if((y-nr_m[1]/2.0+1)*hr_m[1] > dy && cy > 0) {
317 //we are a upper boundary point
318 if(!isInside(x, y + 1, z)) {
319 dn = dy - cy;
320 value.north = 0.0;
321 }
322
323 //if((y-nr_m[1]/2.0-1)*hr_m[1] < dy && cy < 0) {
324 //we are a lower boundary point
325 if(!isInside(x, y - 1, z)) {
326 ds = std::abs(dy) - std::abs(cy);
327 value.south = 0.0;
328 }
329
330 //2/dw*(dw_de)
331 value.west *= -1.0 / (dw * (dw + de));
332 value.east *= -1.0 / (de * (dw + de));
333 value.north *= -1.0 / (dn * (dn + ds));
334 value.south *= -1.0 / (ds * (dn + ds));
335 value.front = -1 / (hr_m[2] * (hr_m[2] + hr_m[2]));
336 value.back = -1 / (hr_m[2] * (hr_m[2] + hr_m[2]));
337
338 //TODO: problem when de,dw,dn,ds == 0
339 //is NOT a regular BOUND PT
340 value.center += 1 / de * 1 / dw;
341 value.center += 1 / dn * 1 / ds;
342 value.center += 1 / hr_m[2] * 1 / hr_m[2];
343 scaleFactor = 0.5;
344
345
346 //for regular gridpoints no problem with symmetry, just boundary
347 //z direction is right
348 //implement isLastInside(dir)
349 //we have LOCAL x,y coordinates!
350
351 /*
352 if(dw != 0 && !wIsB)
353 W = -1/dw * (dn+ds) * 2*hr_m[2];
354 else
355 W = 0;
356 if(de != 0 && !eIsB)
357 E = -1/de * (dn+ds) * 2*hr_m[2];
358 else
359 E = 0;
360 if(dn != 0 && !nIsB)
361 N = -1/dn * (dw+de) * 2*hr_m[2];
362 else
363 N = 0;
364 if(ds != 0 && !sIsB)
365 S = -1/ds * (dw+de) * 2*hr_m[2];
366 else
367 S = 0;
368 F = -(dw+de)*(dn+ds)/hr_m[2];
369 B = -(dw+de)*(dn+ds)/hr_m[2];
370 */
371
372 //if(dw != 0)
373 //W = -2*hr_m[2]*(dn+ds)/dw;
374 //else
375 //W = 0;
376 //if(de != 0)
377 //E = -2*hr_m[2]*(dn+ds)/de;
378 //else
379 //E = 0;
380 //if(dn != 0)
381 //N = -2*hr_m[2]*(dw+de)/dn;
382 //else
383 //N = 0;
384 //if(ds != 0)
385 //S = -2*hr_m[2]*(dw+de)/ds;
386 //else
387 //S = 0;
388 //F = -(dw+de)*(dn+ds)/hr_m[2];
389 //B = -(dw+de)*(dn+ds)/hr_m[2];
390
393 //scaleFactor = 0.5*(dw+de)*(dn+ds)*(2*hr_m[2]);
394
395 // catch the case where a point lies on the boundary
396 //FIXME: do this more elegant!
397 //double m1 = dw*de;
398 //double m2 = dn*ds;
399 //if(de == 0)
400 //m1 = dw;
401 //if(dw == 0)
402 //m1 = de;
403 //if(dn == 0)
404 //m2 = ds;
405 //if(ds == 0)
406 //m2 = dn;
409 //C = 2/hr_m[2];
410 //if(dw != 0 || de != 0)
411 //C *= (dw+de);
412 //if(dn != 0 || ds != 0)
413 //C *= (dn+ds);
414 //if(dw != 0 || de != 0)
415 //C += (2*hr_m[2])*(dn+ds)*(dw+de)/m1;
416 //if(dn != 0 || ds != 0)
417 //C += (2*hr_m[2])*(dw+de)*(dn+ds)/m2;
418
419 //handle Neumann case
420 //if(z == 0 || z == nr_m[2]-1) {
421
422 //if(z == 0)
423 //F = 0.0;
424 //else
425 //B = 0.0;
426
428 //W = W/2.0;
429 //E = E/2.0;
430 //N = N/2.0;
431 //S = S/2.0;
432 //C /= 2.0;
433
434 //scaleFactor /= 2.0;
435 //}
436
437 // handle boundary condition in z direction
438 if(z == 0 || z == nr_m[2] - 1) {
439
440 // case where we are on the NEUMAN BC in Z-direction
441 // where we distinguish two cases
442 if(z == 0)
443 value.front = 0.0;
444 else
445 value.back = 0.0;
446
447 //value.center += 2/((hr_m[2]*(nr_m[2]-1)/2.0) * hr_m[2]);
448 //hr_m[2]*(nr_m2[2]-1)/2 = radius
449 double d = hr_m[2] * (nr_m[2] - 1) / 2;
450 value.center += 2 / (d * hr_m[2]);
451
452 value.west /= 2.0;
453 value.east /= 2.0;
454 value.north /= 2.0;
455 value.south /= 2.0;
456 value.center /= 2.0;
457 scaleFactor /= 2.0;
458
459 }
460}
const int nr
Definition: ClassicRandom.h:24
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
BoxCornerPointList IntersectYDir
all intersection points with grid lines in Y direction
double C_m
height of the corner
void compute(Vector_t hr, NDIndex< 3 > localId) override
BoxCornerPointList IntersectXDir
all intersection points with grid lines in X direction
void linearInterpolation(int x, int y, int z, StencilValue_t &value, double &scaleFactor) const override
different interpolation methods for boundary points
void quadraticInterpolation(int x, int y, int z, StencilValue_t &value, double &scaleFactor) const override
BoxCornerDomain(double A, double B, double C, double L1, double L2, IntVector_t nr, Vector_t hr, std::string interpl)
double actBMin_m
because the geometry can change in the y direction
double getB(double z) const
as a function of z, determine the height (B) of the geometry
double getXIntersection(double cx, int) const
bool isInside(int x, int y, int z) const override
queries if a given (x,y,z) coordinate lies inside the domain
double getYIntersection(double cy, int z) const
int toCoordIdx(int x, int y, int z) const
conversion from (x,y,z) to index in xyz plane
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 getMaxZ() 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)
double getMinZ() const
void setHr(Vector_t hr)
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6