OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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 }
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
BoxCornerPointList IntersectXDir
all intersection points with grid lines in X direction
void compute(Vector_t hr, NDIndex< 3 > localId)
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)
bool isInside(int x, int y, int z) const
queries if a given (x,y,z) coordinate lies inside the domain
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
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