OPAL (Object Oriented Parallel Accelerator Library)  2024.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 
36 BoxCornerDomain::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);
68  hasGeometryChanged_m = true;
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 
131 void BoxCornerDomain::linearInterpolation(int x, int y, int z, StencilValue_t& value,
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 }
double C_m
height of the corner
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
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
void setRangeMax(const Vector_t &max)
IntVector_t nr_m
number of mesh points in each direction
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
BoxCornerDomain(double A, double B, double C, double L1, double L2, IntVector_t nr, Vector_t hr, std::string interpl)
std::map< int, int > idxMap_m
mapping (x,y,z) -&gt; idx
double getMinZ() const
double getMaxZ() const
double getB(double z) const
as a function of z, determine the height (B) of the geometry
BoxCornerPointList IntersectXDir
all intersection points with grid lines in X direction
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
int toCoordIdx(int x, int y, int z) const
conversion from (x,y,z) to index in xyz plane
void linearInterpolation(int x, int y, int z, StencilValue_t &value, double &scaleFactor) const override
different interpolation methods for boundary points
BoxCornerPointList IntersectYDir
all intersection points with grid lines in Y direction
double getYRangeMin() const
The base class for all OPAL exceptions.
Definition: OpalException.h:28
double actBMin_m
because the geometry can change in the y direction
void compute(Vector_t hr, NDIndex< 3 > localId) override
Vector_t hr_m
mesh-spacings in each direction
std::map< int, int > coordMap_m
mapping idx -&gt; (x,y,z)
void setRangeMin(const Vector_t &min)
void quadraticInterpolation(int x, int y, int z, StencilValue_t &value, double &scaleFactor) const override
const int nr
Definition: ClassicRandom.h:24
bool hasGeometryChanged_m
flag indicating if geometry has changed for the current time-step
double getYIntersection(double cy, int z) const
void setHr(Vector_t hr)