3#include "../../../../ExaHyPE/kernels/GaussLegendreBasis.h"
4#include "../../../../ExaHyPE/kernels/KernelUtils.h"
12template <
class Shortcuts,
int basisSize>
19 double a_interface_factor,
20 double a_max_distance_to_direct_surface
26 max_distance_to_direct_surface = a_max_distance_to_direct_surface;
37 for (
int node = 0; node < basisSize; node++) {
53 int findRelativePosition(
double& distance,
double y_min,
double y_max,
int i,
int j) {
70 kernels::idx4 idx(basisSize, basisSize, basisSize, Dimensions);
72 constexpr int center = basisSize / 2;
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));
78 double patch_distance = 0;
80 int position = findRelativePosition(
81 patch_distance, x[idx(0, 0, 0, 1)], x[idx(0, basisSize - 1, 0, 1)], cell_i, cell_j
85 if (patch_distance >= max_distance_to_direct_surface) {
87 std::fill_n(alpha, basisSize * basisSize * basisSize, 0.0);
91 std::fill_n(alpha, basisSize * basisSize * basisSize, 1.0);
96 double cell_dx = (
x[idx(0, basisSize - 1, 0, 1)] -
x[idx(0, 0, 0, 1)]);
98 patch_distance += sqrt(3.0 / 2.0) *
dx;
101 double minDistance[basisSize * basisSize * basisSize];
102 std::fill_n(minDistance, basisSize * basisSize * basisSize, patch_distance);
104 bool done[basisSize * basisSize * basisSize];
105 std::fill_n(done, basisSize * basisSize * basisSize,
false);
107 Position positions[basisSize * basisSize * basisSize];
108 getMinDistancePatch(patch_distance, x, minDistance, positions, done);
109 computeAlphaPatch(alpha, minDistance, positions);
114 void computeAlphaPatch(
double* alpha,
double* minDistance,
Position* positions) {
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)];
121 double r = minDistance[idx_alpha(node_z, node_y, node_x)] /
interval_size;
123 if (position_node == Position ::above)
125 alpha[idx_alpha(node_z, node_y, node_x)] = (std::sin(r * M_PI) + 1) * 0.5;
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)]
140 void spanPatchAroundCenter(
141 std::vector<double>& patch_x, std::vector<double>& patch_z,
double center_x,
double center_z,
double patch_radius
144 kernels::idx4 idx(basisSize, basisSize, basisSize, Dimensions);
147 constexpr int center = basisSize / 2;
150 int num_circles = basisSize;
151 std::vector<double> radius;
152 radius.resize(num_circles);
154 int num_args[num_circles];
156 num_args[1] = basisSize;
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;
163 int node_counter = 0;
165 patch_x.resize(num_args[0]);
166 patch_z.resize(num_args[0]);
168 patch_x[node_counter] = center_x;
169 patch_z[node_counter] = center_z;
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;
183 patch_x[node_counter] = std::min(
186 patch_z[node_counter] = std::min(
194 void findMinDistanceToNode(
195 double& min_distance,
197 const double*
const x,
198 std::vector<double>& patch_x,
199 std::vector<double>& patch_y,
200 std::vector<double>& patch_z
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])
209 if (distance < new_min_distance) {
210 new_min_distance = distance;
214 min_distance = new_min_distance;
217 void getMinDistancePatch(
218 double patch_distance,
const double*
const x,
double* min_distance,
Position* positions,
bool* done
222 std::vector<double> patch_x;
223 std::vector<double> patch_z;
225 kernels::idx4 idx(basisSize, basisSize, basisSize, Dimensions);
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);
233 std::vector<double> patch_y;
234 topography->topography_onSet(patch_x, patch_z, patch_y);
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;
243 findMinDistanceToNode(
244 new_min_distance, new_position, x + idx(node_z, node_y, node_x, 0), patch_x, patch_y, patch_z
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;
252 done[idx_node(node_z, node_y, node_x)] =
true;
258 bool all_done =
true;
259 for (
int i = 0;
i < basisSize * basisSize * basisSize;
i++) {
280 double patch_distance = std::numeric_limits<double>::max();
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++) {
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)
294 + min_distance[idx_node(node_z, node_y, node_x)];
296 patch_distance = std::min(node_distance, patch_distance);
301 getMinDistancePatch(patch_distance, x, min_distance, positions, done);
306 double getAlpha(
const double*
const x) {
312 if (min_dist_limit > max_distance_to_direct_surface) {
317 if (max_dist_limit > max_distance_to_direct_surface) {
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]);
327 alpha = (std::sin(r * M_PI) + 1) * 0.5;
329 alpha = min_distance < 0 ? 0 : 1;
334 double getMinDistance(
double max_distance,
double x,
double y,
double z) {
336 std::vector<double> patch_x;
337 std::vector<double> patch_z;
338 std::vector<double> patch_y;
339 std::vector<double> radius;
342 int num_args[num_circles];
346 radius.resize(num_circles);
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;
353 int node_counter = 0;
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;
371 patch_x[node_counter] = std::min(
374 patch_z[node_counter] = std::min(
382 topography->topography_onSet(patch_x, patch_z, patch_y);
384 double new_max_distance = max_distance;
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;
397 if (std::abs(new_max_distance - max_distance) < 1.0e-10) {
400 return getMinDistance(new_max_distance, x, y, z);
405 std::vector<double>
x;
406 std::vector<double>
y;
407 std::vector<double>
z;
418 for (
int node = 0; node < basisSize; node++) {
430 double min = std::numeric_limits<double>::max();
431 double max = -std::numeric_limits<double>::max();
433 for (
int node = 0; node < basisSize * basisSize; node++) {
434 min = std::min(min, y[node]);
435 max = std::max(max, y[node]);
451 double max_distance_to_direct_surface;
#define assertion1(expr, param)
double volume_testfunction
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
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).