Peano
Loading...
Searching...
No Matches
DiffuseInterface.h
Go to the documentation of this file.
1#pragma once
2
3#include "../../../../ExaHyPE/kernels/GaussLegendreBasis.h"
4#include "../../../../ExaHyPE/kernels/KernelUtils.h"
5
6enum Position { above, at, below };
7
11
12template <class Shortcuts, int basisSize>
13class DiffuseInterface {
14public:
16 Topography* a_topo,
17 DomainInformation* a_domainInfo,
18 SolverInformation* a_solverInfo,
19 double a_interface_factor,
20 double a_max_distance_to_direct_surface
21 ) {
22 topography = a_topo;
23 info = a_domainInfo;
24 isDG = a_solverInfo->isDG();
25
26 max_distance_to_direct_surface = a_max_distance_to_direct_surface;
27
28 dx = info->getDx();
29
30 interface_factor = a_interface_factor;
32
33 // number of cells in one dimension
34 domain_cells = int(std::ceil(info->domainSize[0] / dx));
35
36 integration_nodes.resize(basisSize);
37 for (int node = 0; node < basisSize; node++) {
38 if (isDG) {
39 // todo replace with solver nodes
40 integration_nodes[node] = kernels::legendre::nodes[basisSize - 1][node];
41 } else {
42 integration_nodes[node] = (node + 1) / (basisSize + 1);
43 }
44 }
45 initLimits();
46 };
47
48 ~DiffuseInterface() { delete topography; };
49
50 // position 0: above
51 // 1: at
52 // 2: below topography
53 int findRelativePosition(double& distance, double y_min, double y_max, int i, int j) {
55 distance = topography_limits_min[idx_cells(j, i)] - y_max;
56 if (distance > 0) {
57 return Position::above;
58 }
59
60 distance = y_min - topography_limits_max[idx_cells(j, i)];
61 if (distance > 0) {
62 return Position::below;
63 }
64 distance = 0.0;
65 return Position::at;
66 }
67
68 void getAlphaPatch(const double* const x, double* alpha) {
70 kernels::idx4 idx(basisSize, basisSize, basisSize, Dimensions);
71
72 constexpr int center = basisSize / 2;
73
74 // find cell id on surface of patch
75 int cell_j = static_cast<int>(std::floor((x[idx(center, center, center, 2)] - info->domainOffset[2]) / dx));
76 int cell_i = static_cast<int>(std::floor((x[idx(center, center, center, 0)] - info->domainOffset[0]) / dx));
77
78 double patch_distance = 0;
79 // position 0: above 1: at 2: below topography
80 int position = findRelativePosition(
81 patch_distance, x[idx(0, 0, 0, 1)], x[idx(0, basisSize - 1, 0, 1)], cell_i, cell_j
82 );
83
84 // compute distance of patch to underlaying surface
85 if (patch_distance >= max_distance_to_direct_surface) {
86 if (position == Position::above) {
87 std::fill_n(alpha, basisSize * basisSize * basisSize, 0.0);
88 return;
89 }
90 if (position == Position::below) {
91 std::fill_n(alpha, basisSize * basisSize * basisSize, 1.0);
92 return;
93 }
94 }
95
96 double cell_dx = (x[idx(0, basisSize - 1, 0, 1)] - x[idx(0, 0, 0, 1)]);
97 // add distance from top center to edge as buffer
98 patch_distance += sqrt(3.0 / 2.0) * dx;
99
100 // minmal measuerd distance for each patch node
101 double minDistance[basisSize * basisSize * basisSize];
102 std::fill_n(minDistance, basisSize * basisSize * basisSize, patch_distance);
103 // boolean if the patch is done
104 bool done[basisSize * basisSize * basisSize];
105 std::fill_n(done, basisSize * basisSize * basisSize, false);
106
107 Position positions[basisSize * basisSize * basisSize];
108 getMinDistancePatch(patch_distance, x, minDistance, positions, done);
109 computeAlphaPatch(alpha, minDistance, positions);
110
111 // std::copy_n(minDistance,basisSize*basisSize*basisSize,alpha);
112 }
113
114 void computeAlphaPatch(double* alpha, double* minDistance, Position* positions) {
115 kernels::idx3 idx_alpha(basisSize, basisSize, basisSize);
116 for (int node_z = 0; node_z < basisSize; node_z++) {
117 for (int node_y = 0; node_y < basisSize; node_y++) {
118 for (int node_x = 0; node_x < basisSize; node_x++) {
119 Position position_node = positions[idx_alpha(node_z, node_y, node_x)];
120
121 double r = minDistance[idx_alpha(node_z, node_y, node_x)] / interval_size;
122 if (r < 0.5) {
123 if (position_node == Position ::above)
124 r = -r;
125 alpha[idx_alpha(node_z, node_y, node_x)] = (std::sin(r * M_PI) + 1) * 0.5;
126 } else {
127 alpha[idx_alpha(node_z, node_y, node_x)] = position_node == Position::below ? 1 : 0;
128 }
129#ifdef Asserts
131 alpha[idx_alpha(node_z, node_y, node_x)] >= 0 && alpha[idx_alpha(node_z, node_y, node_x)] <= 1,
132 alpha[idx_alpha(node_z, node_y, node_x)]
133 );
134#endif
135 }
136 }
137 }
138 }
139
140 void spanPatchAroundCenter(
141 std::vector<double>& patch_x, std::vector<double>& patch_z, double center_x, double center_z, double patch_radius
142 ) {
143
144 kernels::idx4 idx(basisSize, basisSize, basisSize, Dimensions);
145 kernels::idx3 idx_node(basisSize, basisSize, basisSize);
146
147 constexpr int center = basisSize / 2;
148
149 // Todo: Is this basis size a valid coice?
150 int num_circles = basisSize;
151 std::vector<double> radius;
152 radius.resize(num_circles);
153
154 int num_args[num_circles];
155 num_args[0] = 1;
156 num_args[1] = basisSize;
157
158 double delta_radius = patch_radius / static_cast<double>(num_circles - 1);
159 for (int i = 0; i < num_circles; i++) {
160 radius[i] = delta_radius * i;
161 }
162
163 int node_counter = 0;
164
165 patch_x.resize(num_args[0]);
166 patch_z.resize(num_args[0]);
167
168 patch_x[node_counter] = center_x;
169 patch_z[node_counter] = center_z;
170
171 node_counter++;
172
173 for (int j = 1; j < num_circles; j++) {
174 num_args[j] = static_cast<int>(std::ceil(radius[j] / radius[1])) * num_args[1];
175 patch_x.resize(patch_x.size() + num_args[j]);
176 patch_z.resize(patch_z.size() + num_args[j]);
177 for (int i = 0; i < num_args[j]; i++) {
178 double arg = 2 * M_PI * i / static_cast<double>(num_args[j]);
179 patch_x[node_counter] = std::cos(arg) * radius[j] + center_x;
180 patch_z[node_counter] = std::sin(arg) * radius[j] + center_z;
181
182 /*truncate on domain boundary*/
183 patch_x[node_counter] = std::min(
184 std::max(patch_x[node_counter], info->domainOffset[0]), info->domainOffset[0] + info->domainSize[0]
185 );
186 patch_z[node_counter] = std::min(
187 std::max(patch_z[node_counter], info->domainOffset[2]), info->domainOffset[2] + info->domainSize[2]
188 );
189 node_counter++;
190 }
191 }
192 }
193
194 void findMinDistanceToNode(
195 double& min_distance,
196 Position& position,
197 const double* const x,
198 std::vector<double>& patch_x,
199 std::vector<double>& patch_y,
200 std::vector<double>& patch_z
201 ) {
202
203 double new_min_distance = std::numeric_limits<double>::max();
204 for (int i = 0; i < patch_x.size(); i++) {
205 double distance = std::sqrt(
206 (patch_x[i] - x[0]) * (patch_x[i] - x[0]) + (patch_y[i] - x[1]) * (patch_y[i] - x[1])
207 + (patch_z[i] - x[2]) * (patch_z[i] - x[2])
208 );
209 if (distance < new_min_distance) {
210 new_min_distance = distance;
211 position = (patch_y[i] - x[1]) > 0 ? Position::above : Position::below;
212 }
213 }
214 min_distance = new_min_distance;
215 }
216
217 void getMinDistancePatch(
218 double patch_distance, const double* const x, double* min_distance, Position* positions, bool* done
219 ) {
220
221 /*span patch around center of the cell*/
222 std::vector<double> patch_x;
223 std::vector<double> patch_z;
224
225 kernels::idx4 idx(basisSize, basisSize, basisSize, Dimensions);
226 kernels::idx3 idx_node(basisSize, basisSize, basisSize);
227
228 double center_x = (x[idx(0, 0, basisSize - 1, 0)] + x[idx(0, 0, 0, 0)]) / 2.0;
229 double center_z = (x[idx(basisSize - 1, 0, 0, 2)] + x[idx(0, 0, 0, 2)]) / 2.0;
230 spanPatchAroundCenter(patch_x, patch_z, center_x, center_z, patch_distance);
231
232 /*evaluate topography on patch*/
233 std::vector<double> patch_y;
234 topography->topography_onSet(patch_x, patch_z, patch_y);
235
236 /*compute distance to surface for each node*/
237
238 for (int node_z = 0; node_z < basisSize; node_z++) {
239 for (int node_y = 0; node_y < basisSize; node_y++) {
240 for (int node_x = 0; node_x < basisSize; node_x++) {
241 double new_min_distance = 0;
242 Position new_position;
243 findMinDistanceToNode(
244 new_min_distance, new_position, x + idx(node_z, node_y, node_x, 0), patch_x, patch_y, patch_z
245 );
246
247 // If new min distance doesn't change we are done
248 if (new_min_distance < min_distance[idx_node(node_z, node_y, node_x)]) {
249 positions[idx_node(node_z, node_y, node_x)] = new_position;
250 min_distance[idx_node(node_z, node_y, node_x)] = new_min_distance;
251 } else {
252 done[idx_node(node_z, node_y, node_x)] = true;
253 }
254 }
255 }
256 }
257
258 bool all_done = true;
259 for (int i = 0; i < basisSize * basisSize * basisSize; i++) {
260 if (!done[i]) {
261 all_done = false;
262 break;
263 }
264 }
265
266 /* if(!isDG){ */
267 /* for(int node_z = 0; node_z < basisSize; node_z++){ */
268 /* for(int node_y = 0; node_y < basisSize; node_y++){ */
269 /* for(int node_x = 0; node_x < basisSize; node_x++){ */
270 /* std::cout << min_distance[idx_node(node_z,node_y,node_x)] << std::endl; */
271 /* } */
272 /* } */
273 /* } */
274 /* std::cout << " "<< std::endl; */
275 /* } */
276
277 if (all_done) { // no closer nodes found -> we are done
278 return;
279 } else {
280 double patch_distance = std::numeric_limits<double>::max();
281
282 for (int node_z = 0; node_z < basisSize; node_z++) {
283 for (int node_y = 0; node_y < basisSize; node_y++) {
284 for (int node_x = 0; node_x < basisSize; node_x++) {
285
286 if (!done[idx_node(node_z, node_y, node_x)]) {
287 double node_distance = 0.0;
288 node_distance = std::sqrt(
289 (x[idx(node_z, node_y, node_x, 0)] - center_x
290 ) * (x[idx(node_z, node_y, node_x, 0)] - center_x)
291 + (x[idx(node_z, node_y, node_x, 2)] - center_z
292 ) * (x[idx(node_z, node_y, node_x, 2)] - center_z)
293 )
294 + min_distance[idx_node(node_z, node_y, node_x)];
295
296 patch_distance = std::min(node_distance, patch_distance);
297 }
298 }
299 }
300 }
301 getMinDistancePatch(patch_distance, x, min_distance, positions, done);
302 return;
303 }
304 }
305
306 double getAlpha(const double* const x) {
308 int cell_j = static_cast<int>(std::floor((x[2] - info->domainOffset[2]) / dx));
309 int cell_i = static_cast<int>(std::floor((x[0] - info->domainOffset[0]) / dx));
310
311 double min_dist_limit = topography_limits_min[idx2(cell_j, cell_i)] - x[1];
312 if (min_dist_limit > max_distance_to_direct_surface) {
313 return 0;
314 }
315
316 double max_dist_limit = x[1] - topography_limits_max[idx2(cell_j, cell_i)];
317 if (max_dist_limit > max_distance_to_direct_surface) {
318 return 1;
319 }
320
321 double min_distance = std::min(std::abs(max_dist_limit), std::abs(min_dist_limit));
322 min_distance = getMinDistance(min_distance, x[0], x[1], x[2]);
323
324 double alpha;
325 if (std::abs(min_distance) < interval_size * 0.5) {
326 double r = min_distance / interval_size;
327 alpha = (std::sin(r * M_PI) + 1) * 0.5;
328 } else {
329 alpha = min_distance < 0 ? 0 : 1;
330 }
331 return alpha;
332 };
333
334 double getMinDistance(double max_distance, double x, double y, double z) {
335
336 std::vector<double> patch_x;
337 std::vector<double> patch_z;
338 std::vector<double> patch_y;
339 std::vector<double> radius;
340
341 int num_circles = 5; // Todo: Is this a valid choice?
342 int num_args[num_circles];
343 num_args[0] = 1;
344 num_args[1] = 10; // Todo: Is this a valid coice?
345
346 radius.resize(num_circles);
347
348 double delta_radius = std::abs(max_distance) / static_cast<double>(num_circles - 1);
349 for (int i = 0; i < num_circles; i++) {
350 radius[i] = delta_radius * i;
351 }
352
353 int node_counter = 0;
354
355 patch_x.resize(1);
356 patch_z.resize(1);
357 patch_x[0] = x;
358 patch_z[0] = z;
359
360 node_counter++;
361
362 for (int j = 1; j < num_circles; j++) {
363 num_args[j] = static_cast<int>(std::ceil(radius[j] / radius[1])) * num_args[1];
364 patch_x.resize(patch_x.size() + num_args[j]);
365 patch_z.resize(patch_z.size() + num_args[j]);
366 for (int i = 0; i < num_args[j]; i++) {
367 double arg = 2 * M_PI * i / static_cast<double>(num_args[j]);
368 patch_x[node_counter] = std::cos(arg) * radius[j] + x;
369 patch_z[node_counter] = std::sin(arg) * radius[j] + z;
370
371 patch_x[node_counter] = std::min(
372 std::max(patch_x[node_counter], info->domainOffset[0]), info->domainOffset[0] + info->domainSize[0]
373 );
374 patch_z[node_counter] = std::min(
375 std::max(patch_z[node_counter], info->domainOffset[2]), info->domainOffset[2] + info->domainSize[2]
376 );
377
378 node_counter++;
379 }
380 }
381
382 topography->topography_onSet(patch_x, patch_z, patch_y);
383
384 double new_max_distance = max_distance;
385 double distance;
386 node_counter = 0;
387 for (int j = 0; j < num_circles; j++) {
388 for (int i = 0; i < num_args[j]; i++) {
389 distance = std::sqrt((patch_y[node_counter] - y) * (patch_y[node_counter] - y) + radius[j] * radius[j]);
390 if (std::abs(new_max_distance) > std::abs(distance)) {
391 new_max_distance = distance;
392 }
393 node_counter++;
394 }
395 }
396
397 if (std::abs(new_max_distance - max_distance) < 1.0e-10) { // no closer nodes found
398 return max_distance;
399 } else {
400 return getMinDistance(new_max_distance, x, y, z);
401 }
402 }
403
404 void initLimits() {
405 std::vector<double> x;
406 std::vector<double> y;
407 std::vector<double> z;
408
411
412 x.resize(basisSize);
413 z.resize(basisSize);
414
416 for (int j = 0; j < domain_cells; j++) {
417 for (int i = 0; i < domain_cells; i++) {
418 for (int node = 0; node < basisSize; node++) {
419 if (isDG) {
420 x[node] = kernels::legendre::nodes[basisSize - 1][node] * dx + i * dx + info->domainOffset[0];
421 z[node] = kernels::legendre::nodes[basisSize - 1][node] * dx + j * dx + info->domainOffset[2];
422 } else {
423 x[node] = (node + 1) / static_cast<double>(basisSize + 1) * dx + i * dx + info->domainOffset[0];
424 z[node] = (node + 1) / static_cast<double>(basisSize + 1) * dx + j * dx + info->domainOffset[2];
425 }
426 }
427
428 topography->topography_onPatch(x, z, y);
429
430 double min = std::numeric_limits<double>::max();
431 double max = -std::numeric_limits<double>::max();
432
433 for (int node = 0; node < basisSize * basisSize; node++) {
434 min = std::min(min, y[node]);
435 max = std::max(max, y[node]);
436 }
437 topography_limits_max[idx2(j, i)] = max;
438 topography_limits_min[idx2(j, i)] = min;
439 }
440 }
441 }
442
443private:
444 Topography* topography;
446
447 bool isDG;
448
449 double dx;
450 double interval_size;
451 double max_distance_to_direct_surface;
452 double interface_factor;
453 int domain_cells;
454
455 std::vector<double> topography_limits_max;
456 std::vector<double> topography_limits_min;
457 std::vector<double> integration_nodes;
458
459 double volume_testfunction;
460};
461
462
#define assertion1(expr, param)
Position
@ at
@ above
@ below
double getAlpha(const double *const x)
std::vector< double > integration_nodes
std::vector< double > topography_limits_min
void getAlphaPatch(const double *const x, double *alpha)
DiffuseInterface(Topography *a_topo, DomainInformation *a_info)
std::vector< double > topography_limits_max
virtual bool isDG()=0
j
Definition euler.py:99
double max(double a, double b, double c)
I need the maximum of three values all the time, to I decided to write a function for this.
Scalar min(const Vector< Size, Scalar > &vector)
Returns the element with minimal value (NOT absolute value).