10#include "../feedback/feedback.h"
11#include "../global/global.h"
12#include "../utils/basic_structs.h"
13#include "../utils/math_utilities.h"
15enum struct StencilEvalKind {
16 enclosed_stencil_vol_frac,
17 enclosed_cell_vol_frac,
41 const Real edge_offset = n_ghost + min_stencil_offset;
55 inline static constexpr int max_enclosed_neighbors = 1;
63 template <
typename Function>
70 int leftmost_indx_x = int(pos_indU[0] - 0.5);
71 int leftmost_indx_y = int(pos_indU[1] - 0.5);
72 int leftmost_indx_z = int(pos_indU[2] - 0.5);
78 Real delta_x = pos_indU[0] - (leftmost_indx_x + 0.5);
79 Real delta_y = pos_indU[1] - (leftmost_indx_y + 0.5);
80 Real delta_z = pos_indU[2] - (leftmost_indx_z + 0.5);
89#define to_idx3D(i, j, k) ((leftmost_indx_x + (i)) + nx_g * ((leftmost_indx_y + (j)) + ny_g * (leftmost_indx_z + (k))))
91 f((1 - delta_x) * (1 - delta_y) * (1 - delta_z), to_idx3D(0, 0, 0));
92 f((1 - delta_x) * (1 - delta_y) * delta_z, to_idx3D(0, 0, 1));
93 f((1 - delta_x) * delta_y * (1 - delta_z), to_idx3D(0, 1, 0));
94 f((1 - delta_x) * delta_y * delta_z, to_idx3D(0, 1, 1));
95 f(delta_x * (1 - delta_y) * (1 - delta_z), to_idx3D(1, 0, 0));
96 f(delta_x * (1 - delta_y) * delta_z, to_idx3D(1, 0, 1));
97 f(delta_x * delta_y * (1 - delta_z), to_idx3D(1, 1, 0));
98 f(delta_x * delta_y * delta_z, to_idx3D(1, 1, 1));
104 template <
typename Function>
108 CIC::for_each(pos_indU, nx_g, ny_g, f);
119 template <
typename UnaryFunction>
124 CIC::for_each(pos_indU, ng_x, ng_y, [f](
double stencil_enclosed_frac,
int idx3D) {
125 if (stencil_enclosed_frac > 0) f(idx3D);
138 const Real min_stencil_offset = 0.5;
139 return nearest_noGhostOverlap_pos_(min_stencil_offset, pos_indU, ng_x, ng_y, ng_z, n_ghost);
147template <
typename Function, StencilEvalKind flavor>
152 int leftmost_indx_x = int(pos_indU[0]) - 1;
153 int leftmost_indx_y = int(pos_indU[1]) - 1;
154 int leftmost_indx_z = int(pos_indU[2]) - 1;
157 Real offset_x = pos_indU[0] - int(pos_indU[0]);
158 Real offset_y = pos_indU[1] - int(pos_indU[1]);
159 Real offset_z = pos_indU[2] - int(pos_indU[2]);
161 for (
int i = 0; i < 3; i++) {
162 for (
int j = 0; j < 3; j++) {
163 for (
int k = 0; k < 3; k++) {
164 const int ind3D = (leftmost_indx_x + i) + nx_g * ((leftmost_indx_y + j) + ny_g * (leftmost_indx_z + k));
171 Real x_len = (i < 2) + (i - 1) * offset_x;
172 Real y_len = (j < 2) + (j - 1) * offset_y;
173 Real z_len = (k < 2) + (k - 1) * offset_z;
176 Real volEnclosed = x_len * y_len * z_len;
178 if constexpr (flavor == StencilEvalKind::enclosed_stencil_vol_frac) {
181 f(0.25 * volEnclosed, ind3D);
182 }
else if constexpr (flavor == StencilEvalKind::enclosed_cell_vol_frac) {
183 f(volEnclosed, ind3D);
184 }
else if constexpr (flavor == StencilEvalKind::for_each_overlap_zone) {
185 if (volEnclosed > 0) f(ind3D);
205static inline __device__ Real Frac(
int i, Real dx) {
return (-0.5 * i * i - 0.5 * i + 1 + i * dx) * 0.5; }
207static inline __device__ Real D_Frac(
int i, Real dx)
216 return (dx > 0.5) * i * (1 - 2 * dx) + ((i + 1) * dx + 0.5 * (i - 1)) - 3 * (i - 1) * (i + 1) * (0.5 - dx);
226 inline static constexpr int max_enclosed_neighbors = 1;
234 template <
typename Function>
237 for_each_cic27_<Function, StencilEvalKind::enclosed_stencil_vol_frac>(pos_indU, nx_g, ny_g,
238 std::forward<Function>(f));
249 template <
typename Function>
253 for_each_cic27_<Function, StencilEvalKind::enclosed_cell_vol_frac>(pos_indU, nx_g, ny_g, std::forward<Function>(f));
264 template <
typename Function>
267 const Real pos_x_indU = pos_indU[0];
268 const Real pos_y_indU = pos_indU[1];
269 const Real pos_z_indU = pos_indU[2];
271 int indx_x = (int)floor(pos_x_indU);
272 int indx_y = (int)floor(pos_y_indU);
273 int indx_z = (int)floor(pos_z_indU);
275 Real delta_x = pos_x_indU - indx_x;
276 Real delta_y = pos_y_indU - indx_y;
277 Real delta_z = pos_z_indU - indx_z;
283 for (
int i = -1; i < 2; i++) {
284 for (
int j = -1; j < 2; j++) {
285 for (
int k = -1; k < 2; k++) {
286 Real x_frac = D_Frac(i, delta_x) * Frac(j, delta_y) * Frac(k, delta_z);
287 Real y_frac = Frac(i, delta_x) * D_Frac(j, delta_y) * Frac(k, delta_z);
288 Real z_frac = Frac(i, delta_x) * Frac(j, delta_y) * D_Frac(k, delta_z);
290 mag += sqrt(x_frac * x_frac + y_frac * y_frac + z_frac * z_frac);
295 Real inv_mag = 1.0 / mag;
297 for (
int i = -1; i < 2; i++) {
298 for (
int j = -1; j < 2; j++) {
299 for (
int k = -1; k < 2; k++) {
301 int indx = (indx_x + i) + (indx_y + j) * nx_g + (indx_z + k) * nx_g * ny_g;
303 Real x_frac = D_Frac(i, delta_x) * Frac(j, delta_y) * Frac(k, delta_z);
304 Real y_frac = Frac(i, delta_x) * D_Frac(j, delta_y) * Frac(k, delta_z);
305 Real z_frac = Frac(i, delta_x) * Frac(j, delta_y) * D_Frac(k, delta_z);
306 Real scalar_weight = sqrt(x_frac * x_frac + y_frac * y_frac + z_frac * z_frac) * inv_mag;
309 f(scalar_weight, momentum_weights, indx);
324 template <
typename UnaryFunction>
328 for_each_cic27_<UnaryFunction, StencilEvalKind::for_each_overlap_zone>(pos_indU, nx_g, ny_g,
329 std::forward<UnaryFunction>(f));
341 const Real min_stencil_offset = 1.0;
342 return nearest_noGhostOverlap_pos_(min_stencil_offset, pos_indU, ng_x, ng_y, ng_z, n_ghost);
356 __forceinline__ __device__
bool encloses_point(
double pos_x_indU,
double pos_y_indU,
double pos_z_indU)
const
362 return (delta_x * delta_x + delta_y * delta_y + delta_z * delta_z) <
raidus2_indU;
372 template <
int Log2DivsionsPerAx>
373 __device__
bool Encloses_Any_Supersample(
int cell_idx_x,
int cell_idx_y,
int cell_idx_z)
const
380 const int num_subdivisions_per_ax = (Log2DivsionsPerAx == 2) ? 4 : std::pow(2, Log2DivsionsPerAx);
381 const double subgrid_width = (Log2DivsionsPerAx == 2) ? 0.25 : 1.0 / num_subdivisions_per_ax;
382 const double leftmost_subgrid_offset = (Log2DivsionsPerAx == 2) ? 0.125 : 0.5 * subgrid_width;
386 const double rightmost_subgrid_offset = leftmost_subgrid_offset + ((num_subdivisions_per_ax - 1) * subgrid_width);
390 double dx_left =
center_indU[0] - (cell_idx_x + leftmost_subgrid_offset);
391 double dx_right =
center_indU[0] - (cell_idx_x + rightmost_subgrid_offset);
392 double dy_left =
center_indU[1] - (cell_idx_y + leftmost_subgrid_offset);
393 double dy_right =
center_indU[1] - (cell_idx_y + rightmost_subgrid_offset);
394 double dz_left =
center_indU[2] - (cell_idx_z + leftmost_subgrid_offset);
395 double dz_right =
center_indU[2] - (cell_idx_z + rightmost_subgrid_offset);
397 double min_squared_dist =
398 (fmin(dx_left * dx_left, dx_right * dx_right) + fmin(dy_left * dy_left, dy_right * dy_right) +
399 fmin(dz_left * dz_left, dz_right * dz_right));
417 template <
int Log2DivsionsPerAx>
418 __device__
unsigned int Count_Super_Samples(
int cell_idx_x,
int cell_idx_y,
int cell_idx_z)
const
420 static_assert((0 <= Log2DivsionsPerAx) and ((Log2DivsionsPerAx * 3) <= (8 *
sizeof(
unsigned int))),
421 "Log2DivsionsPerAx must be a non-negative integer AND 2^(Log2DivsionsPerAx*3), the total "
422 "number of super-samples in a given cell, must be representable by an unsigned int");
429 const int num_subdivisions_per_ax = (Log2DivsionsPerAx == 2) ? 4 : std::pow(2, Log2DivsionsPerAx);
430 const double subgrid_width = (Log2DivsionsPerAx == 2) ? 0.25 : 1.0 / num_subdivisions_per_ax;
431 const double leftmost_subgrid_offset = (Log2DivsionsPerAx == 2) ? 0.125 : 0.5 * subgrid_width;
433 unsigned int count = 0;
434 for (
int ix = 0; ix < num_subdivisions_per_ax; ix++) {
435 for (
int iy = 0; iy < num_subdivisions_per_ax; iy++) {
436 for (
int iz = 0; iz < num_subdivisions_per_ax; iz++) {
439 double x = cell_idx_x + (leftmost_subgrid_offset + ix * subgrid_width);
440 double y = cell_idx_y + (leftmost_subgrid_offset + iy * subgrid_width);
441 double z = cell_idx_z + (leftmost_subgrid_offset + iz * subgrid_width);
443 count += encloses_point(x, y, z);
491 template <
int Log2DivsionsPerAx>
495 static_assert((0 <= Log2DivsionsPerAx) and ((Log2DivsionsPerAx * 3) <= (8 *
sizeof(
unsigned int))),
496 "Log2DivsionsPerAx must be a non-negative integer AND 2^(Log2DivsionsPerAx*3), the total "
497 "number of super-samples in a given cell, must be representable by an unsigned int");
504 const int num_subdivisions_per_ax = (Log2DivsionsPerAx == 2) ? 4 : std::pow(2, Log2DivsionsPerAx);
505 const double subgrid_width = (Log2DivsionsPerAx == 2) ? 0.25 : 1.0 / num_subdivisions_per_ax;
506 const double leftmost_subgrid_offset = (Log2DivsionsPerAx == 2) ? 0.125 : 0.5 * subgrid_width;
510 for (
int ix = 0; ix < num_subdivisions_per_ax; ix++) {
511 for (
int iy = 0; iy < num_subdivisions_per_ax; iy++) {
512 for (
int iz = 0; iz < num_subdivisions_per_ax; iz++) {
517 const double orig_frame_x = cell_idx_x + (leftmost_subgrid_offset + ix * subgrid_width);
518 const double orig_frame_y = cell_idx_y + (leftmost_subgrid_offset + iy * subgrid_width);
519 const double orig_frame_z = cell_idx_z + (leftmost_subgrid_offset + iz * subgrid_width);
521 const bool subcell_enclosed_by_sphere = encloses_point(orig_frame_x, orig_frame_y, orig_frame_z);
525 const double x = orig_frame_x - ref_pos_IndU[0];
526 const double y = orig_frame_y - ref_pos_IndU[1];
527 const double z = orig_frame_z - ref_pos_IndU[2];
529 const bool coincides_with_origin = ((x == 0.0) && (y == 0.0) && (z == 0.0));
533 const double inv_r_mag = 1.0 / (coincides_with_origin + sqrt((x * x) + (y * y) + (z * z)));
535 out[0] += subcell_enclosed_by_sphere * x * inv_r_mag;
536 out[1] += subcell_enclosed_by_sphere * y * inv_r_mag;
537 out[2] += subcell_enclosed_by_sphere * z * inv_r_mag;
550template <
typename Function, StencilEvalKind flavor,
int CellsPerDiameter,
int Log2DivsionsPerAx_PerCell>
554 const SphereObj sphere{ {pos_indU[0], pos_indU[1], pos_indU[2]},
558 const Real l_offset = ((CellsPerDiameter % 2) == 0) ? CellsPerDiameter / 2 : 0.5 * CellsPerDiameter;
561 const int leftmost_indx_x = int(pos_indU[0] - l_offset);
562 const int leftmost_indx_y = int(pos_indU[1] - l_offset);
563 const int leftmost_indx_z = int(pos_indU[2] - l_offset);
576 [[maybe_unused]]
unsigned long total_count = 0;
577 [[maybe_unused]] uint_least16_t cached_counts[3][3][3];
580 if constexpr (flavor == StencilEvalKind::enclosed_stencil_vol_frac) {
581 for (
int i = 0; i < 3; i++) {
582 for (
int j = 0; j < 3; j++) {
583 for (
int k = 0; k < 3; k++) {
584 unsigned int count = sphere.Count_Super_Samples<Log2DivsionsPerAx_PerCell>(
585 leftmost_indx_x + i, leftmost_indx_y + j, leftmost_indx_z + k);
586 cached_counts[i][j][k] = std::uint_least16_t(count);
587 total_count += count;
598 for (
int i = 0; i < 3; i++) {
599 for (
int j = 0; j < 3; j++) {
600 for (
int k = 0; k < 3; k++) {
601 const int indx_x = leftmost_indx_x + i;
602 const int indx_y = leftmost_indx_y + j;
603 const int indx_z = leftmost_indx_z + k;
604 const int ind3D = indx_x + nx_g * (indx_y + ny_g * indx_z);
609 if constexpr (flavor == StencilEvalKind::enclosed_stencil_vol_frac) {
613 f(
double(cached_counts[i][j][k]) / total_count, ind3D);
615 }
else if constexpr (flavor == StencilEvalKind::enclosed_cell_vol_frac) {
622 double inverse_max_counts_per_cell = 1.0 / double(std::pow(2, Log2DivsionsPerAx_PerCell * 3));
625 unsigned int count = sphere.Count_Super_Samples<Log2DivsionsPerAx_PerCell>(indx_x, indx_y, indx_z);
626 f(count * inverse_max_counts_per_cell, ind3D);
628 }
else if constexpr (flavor == StencilEvalKind::for_each_overlap_zone) {
629 bool is_enclosed = sphere.Encloses_Any_Supersample<Log2DivsionsPerAx_PerCell>(indx_x, indx_y, indx_z);
630 if (is_enclosed) f(ind3D);
646template <
int Log2DivsionsPerAx_PerCell = 2>
648 static_assert((Log2DivsionsPerAx_PerCell >= 0) and (Log2DivsionsPerAx_PerCell <= 5),
649 "Log2DivsionsPerAx_PerCell must be a non-negative integer. It also can't exceed 5 "
650 "so that 2^(Log2DivsionsPerAx_PerCell*3) can be represented by uint16_t");
658 inline static constexpr int max_enclosed_neighbors = 1;
666 template <
typename Function>
669 for_each_sphere_<Function, StencilEvalKind::enclosed_stencil_vol_frac, 2, Log2DivsionsPerAx_PerCell>(
670 pos_indU, nx_g, ny_g, std::forward<Function>(f));
689 template <
typename Function>
693 const int leftmost_indx_x = int(pos_indU[0] - 1);
694 const int leftmost_indx_y = int(pos_indU[1] - 1);
695 const int leftmost_indx_z = int(pos_indU[2] - 1);
698 const SphereObj sphere{{pos_indU[0], pos_indU[1], pos_indU[2]}, 1 * 1};
705 uint_least16_t cached_counts[3][3][3];
707 unsigned long total_count = 0;
708 Real vector_norm = 0.0;
709 for (
int i = 0; i < 3; i++) {
710 for (
int j = 0; j < 3; j++) {
711 for (
int k = 0; k < 3; k++) {
712 unsigned int cur_count = sphere.Count_Super_Samples<Log2DivsionsPerAx_PerCell>(
713 leftmost_indx_x + i, leftmost_indx_y + j, leftmost_indx_z + k);
714 total_count += cur_count;
715 cached_counts[i][j][k] = std::uint_least16_t(cur_count);
718 sphere.Super_Sampled_RadialUnitVec_VolIntegral<Log2DivsionsPerAx_PerCell>(
719 leftmost_indx_x + i, leftmost_indx_y + j, leftmost_indx_z + k, pos_indU);
720 vector_norm += norm3d(integrated_vec[0], integrated_vec[1], integrated_vec[2]);
726 const Real vec_factor = 1.0 / vector_norm;
733 for (
int i = 0; i < 3; i++) {
734 for (
int j = 0; j < 3; j++) {
735 for (
int k = 0; k < 3; k++) {
736 const int ind3D = (leftmost_indx_x + i) + nx_g * ((leftmost_indx_y + j) + ny_g * (leftmost_indx_z + k));
743 sphere.Super_Sampled_RadialUnitVec_VolIntegral<Log2DivsionsPerAx_PerCell>(
744 leftmost_indx_x + i, leftmost_indx_y + j, leftmost_indx_z + k, pos_indU);
746 f(
double(cached_counts[i][j][k]) / total_count,
761 template <
typename Function>
765 for_each_sphere_<Function, StencilEvalKind::enclosed_cell_vol_frac, 2, Log2DivsionsPerAx_PerCell>(
766 pos_indU, nx_g, ny_g, std::forward<Function>(f));
775 template <
typename UnaryFunction>
779 for_each_sphere_<UnaryFunction, StencilEvalKind::for_each_overlap_zone, 2, Log2DivsionsPerAx_PerCell>(
780 pos_indU, nx_g, ny_g, std::forward<UnaryFunction>(f));
794 constexpr Real min_stencil_offset = 1.0;
795 return nearest_noGhostOverlap_pos_(min_stencil_offset, pos_indU, ng_x, ng_y, ng_z, n_ghost);
804template <
int CellsPerRadius = 3>
806 static_assert(CellsPerRadius > 0);
814 inline static constexpr int max_enclosed_neighbors = CellsPerRadius;
816 template <
typename Function>
820 int leftmost_indx_x = int(pos_indU[0]) - CellsPerRadius;
821 int leftmost_indx_y = int(pos_indU[1]) - CellsPerRadius;
822 int leftmost_indx_z = int(pos_indU[2]) - CellsPerRadius;
825 const SphereObj sphere{{pos_indU[0], pos_indU[1], pos_indU[2]}, CellsPerRadius * CellsPerRadius};
828 const int stop = (2 * CellsPerRadius) + 1;
829 for (
int i = 0; i < stop; i++) {
830 for (
int j = 0; j < stop; j++) {
831 for (
int k = 0; k < stop; k++) {
833 sphere.encloses_point(leftmost_indx_x + i + 0.5, leftmost_indx_y + j + 0.5, leftmost_indx_z + k + 0.5);
838 double enclosed_stencil_frac = 1.0 / total_count;
843 for (
int i = 0; i < stop; i++) {
844 for (
int j = 0; j < stop; j++) {
845 for (
int k = 0; k < stop; k++) {
847 sphere.encloses_point(leftmost_indx_x + i + 0.5, leftmost_indx_y + j + 0.5, leftmost_indx_z + k + 0.5);
850 const int ind3D = (leftmost_indx_x + i) + nx_g * ((leftmost_indx_y + j) + ny_g * (leftmost_indx_z + k));
851 f(enclosed_stencil_frac, ind3D);
866 template <
typename Function>
871 int leftmost_indx_x = int(pos_indU[0]) - CellsPerRadius;
872 int leftmost_indx_y = int(pos_indU[1]) - CellsPerRadius;
873 int leftmost_indx_z = int(pos_indU[2]) - CellsPerRadius;
875 const SphereObj sphere{{pos_indU[0], pos_indU[1], pos_indU[2]}, CellsPerRadius * CellsPerRadius};
877 const int stop = (2 * CellsPerRadius) + 1;
878 for (
int i = 0; i < stop; i++) {
879 for (
int j = 0; j < stop; j++) {
880 for (
int k = 0; k < stop; k++) {
882 sphere.encloses_point(leftmost_indx_x + i + 0.5, leftmost_indx_y + j + 0.5, leftmost_indx_z + k + 0.5);
883 double enclosed_cell_vol = (is_enclosed) ? 1.0 : 0.0;
884 const int ind3D = (leftmost_indx_x + i) + nx_g * ((leftmost_indx_y + j) + ny_g * (leftmost_indx_z + k));
885 f(enclosed_cell_vol, ind3D);
891 template <
typename UnaryFunction>
896 int leftmost_indx_x = int(pos_indU[0]) - CellsPerRadius;
897 int leftmost_indx_y = int(pos_indU[1]) - CellsPerRadius;
898 int leftmost_indx_z = int(pos_indU[2]) - CellsPerRadius;
900 const SphereObj sphere{ {pos_indU[0], pos_indU[1], pos_indU[2]},
901 CellsPerRadius * CellsPerRadius};
903 const int stop = (2 * CellsPerRadius) + 1;
904 for (
int i = 0; i < stop; i++) {
905 for (
int j = 0; j < stop; j++) {
906 for (
int k = 0; k < stop; k++) {
907 const int indx_x = leftmost_indx_x + i;
908 const int indx_y = leftmost_indx_y + j;
909 const int indx_z = leftmost_indx_z + k;
910 const int ind3D = indx_x + ng_x * (indx_y + ng_y * indx_z);
912 sphere.encloses_point(leftmost_indx_x + i + 0.5, leftmost_indx_y + j + 0.5, leftmost_indx_z + k + 0.5);
913 if (is_enclosed) f(ind3D);
930 constexpr Real min_stencil_offset = CellsPerRadius;
931 return nearest_noGhostOverlap_pos_(min_stencil_offset, pos_indU, ng_x, ng_y, ng_z, n_ghost);
__device__ __host__ T clamp(T val, T lo, T hi)
When val lies within the inclusive range [lo, hi], returns val. Otherwise, return the closest value i...
Definition math_utilities.h:144
static __device__ void for_each_overlap_zone(hydro_utilities::VectorXYZ< Real > pos_indU, int ng_x, int ng_y, UnaryFunction f)
Definition stencil.h:120
int raidus2_indU
Definition stencil.h:351
double center_indU[3]
Definition stencil.h:349
A data only struct that acts as a simple 3 element vector.
Definition basic_structs.h:32