Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
SlopeLimitedGradientUtilities.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
19
20#include "shamcomm/logs.hpp"
21#include "shammath/riemann.hpp"
25#include <type_traits>
26
27namespace {
29 using Direction = shammodels::basegodunov::modules::Direction;
30
31 template<class T>
32 inline T slope_function_van_leer_f_form(T sL, T sR) {
33 T st = sL + sR;
34
35 auto vanleer = [](T f) {
36 return 4. * f * (1. - f);
37 };
38
39 auto slopelim = [&](T f) {
40 if constexpr (std::is_same_v<T, f64_3>) {
41 f.x() = (f.x() >= 0 && f.x() <= 1) ? f.x() : 0;
42 f.y() = (f.y() >= 0 && f.y() <= 1) ? f.y() : 0;
43 f.z() = (f.z() >= 0 && f.z() <= 1) ? f.z() : 0;
44 } else {
45 f = (f >= 0 && f <= 1) ? f : 0;
46 }
47 return vanleer(f);
48 };
49
50 return slopelim(sL / st) * st * 0.5;
51 }
52
53 template<class T>
54 inline T slope_function_van_leer_symetric(T sL, T sR) {
55
56 if constexpr (std::is_same_v<T, f64_3>) {
57 return {
58 shammath::van_leer_slope_symetric(sL[0], sR[0]),
59 shammath::van_leer_slope_symetric(sL[1], sR[1]),
60 shammath::van_leer_slope_symetric(sL[2], sR[2])};
61 } else {
62 return shammath::van_leer_slope_symetric(sL, sR);
63 }
64 }
65
66 template<class T>
67 inline T slope_function_van_leer_standard(T sL, T sR) {
68
69 if constexpr (std::is_same_v<T, f64_3>) {
70 return {
71 shammath::van_leer_slope(sL[0], sR[0]),
72 shammath::van_leer_slope(sL[1], sR[1]),
73 shammath::van_leer_slope(sL[2], sR[2])};
74 } else {
75 return shammath::van_leer_slope(sL, sR);
76 }
77 }
78
79 template<class T>
80 inline T slope_function_minmod(T sL, T sR) {
81
82 if constexpr (std::is_same_v<T, f64_3>) {
83 return {
84 shammath::minmod(sL[0], sR[0]),
85 shammath::minmod(sL[1], sR[1]),
86 shammath::minmod(sL[2], sR[2])};
87 } else {
88 return shammath::minmod(sL, sR);
89 }
90 }
91
93
94 template<class T, SlopeMode mode>
95 inline T slope_function(T sL, T sR) {
96 if constexpr (mode == SlopeMode::None) {
97 return sham::VectorProperties<T>::get_zero();
98 }
99
100 if constexpr (mode == SlopeMode::VanLeer_f) {
101 return slope_function_van_leer_f_form(sL, sR);
102 }
103
104 if constexpr (mode == SlopeMode::VanLeer_std) {
105 return slope_function_van_leer_standard(sL, sR);
106 }
107
108 if constexpr (mode == SlopeMode::VanLeer_sym) {
109 return slope_function_van_leer_symetric(sL, sR);
110 }
111
112 if constexpr (mode == SlopeMode::Minmod) {
113 return slope_function_minmod(sL, sR);
114 }
115 }
116
135 template<class Tfield, class Tvec, SlopeMode mode, class ACCField>
136 inline std::array<Tfield, 3> get_3d_grad(
137 const f64 *cell_sizes,
138 const u32 block_size,
139 const u32 cell_global_id,
140 const AMRGraphLinkiterator &graph_iter_xp,
141 const AMRGraphLinkiterator &graph_iter_xm,
142 const AMRGraphLinkiterator &graph_iter_yp,
143 const AMRGraphLinkiterator &graph_iter_ym,
144 const AMRGraphLinkiterator &graph_iter_zp,
145 const AMRGraphLinkiterator &graph_iter_zm,
146 ACCField &&field_access) {
147
148 auto cur_cell_block_id = cell_global_id / block_size;
149
150 auto get_gradient_dir = [&](auto &graph_links, Direction dir) -> Tfield {
151 Tfield acc = shambase::VectorProperties<Tfield>::get_zero();
152 auto cell_center_dist = cell_sizes[cur_cell_block_id];
153
154 u32 cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
155 auto neigh_block_id = id_b / block_size;
156 auto fac = 1.;
157 if (cell_sizes[neigh_block_id] > cell_sizes[cur_cell_block_id]) {
158 fac = (3. / 2.);
159 }
160 // This logic suppose that the last (4-th) cell at interface have same size with the
161 // other three cells. This is also consitent with 2:1 refinement.
162 // TODO: extended to anisotropic mesh
163 if (cell_sizes[neigh_block_id] < cell_sizes[cur_cell_block_id]) {
164 fac = (3. / 4.);
165 }
166 const auto inv_dist = 1. / (fac * cell_center_dist);
167
168 int sign = 1 - 2 * (dir % 2);
169 acc += sign * inv_dist * (field_access(id_b) - field_access(cell_global_id));
170 });
171 return (cnt > 0) ? acc / cnt : shambase::VectorProperties<Tfield>::get_zero();
172 };
173
174 return {
175 slope_function<Tfield, mode>(
176 get_gradient_dir(graph_iter_xm, Direction::xm),
177 get_gradient_dir(graph_iter_xp, Direction::xp)),
178 slope_function<Tfield, mode>(
179 get_gradient_dir(graph_iter_ym, Direction::ym),
180 get_gradient_dir(graph_iter_yp, Direction::yp)),
181 slope_function<Tfield, mode>(
182 get_gradient_dir(graph_iter_zm, Direction::zm),
183 get_gradient_dir(graph_iter_zp, Direction::zp))};
184 }
185
209 template<class Tvec, SlopeMode mode, class ACCField1, class ACCField2, class ACCField3>
210 inline std::array<shammath::ConsState<Tvec>, 3> get_3d_grad_cons(
211 const f64 *cell_sizes,
212 const u32 block_size,
213 const u32 cell_global_id,
214 const AMRGraphLinkiterator &graph_iter_xp,
215 const AMRGraphLinkiterator &graph_iter_xm,
216 const AMRGraphLinkiterator &graph_iter_yp,
217 const AMRGraphLinkiterator &graph_iter_ym,
218 const AMRGraphLinkiterator &graph_iter_zp,
219 const AMRGraphLinkiterator &graph_iter_zm,
220 ACCField1 &&field_access_rho,
221 ACCField2 &&field_access_rho_vel,
222 ACCField3 &&field_access_rhoe) {
223
224 using Tscal = shambase::VecComponent<Tvec>;
225 auto cur_cell_block_id = cell_global_id / block_size;
226
227 auto get_gradient_dir = [&](auto &graph_links, Direction dir) -> shammath::ConsState<Tvec> {
228 Tscal acc_rho = shambase::VectorProperties<Tscal>::get_zero();
229 Tscal acc_rhoe = shambase::VectorProperties<Tscal>::get_zero();
230 Tvec acc_rho_vel = shambase::VectorProperties<Tvec>::get_zero();
231 auto cell_center_dist = cell_sizes[cur_cell_block_id];
232
233 auto cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
234 auto neigh_block_id = id_b / block_size;
235 auto fac = 1.;
236 if (cell_sizes[neigh_block_id] > cell_sizes[cur_cell_block_id]) {
237 fac = (3. / 2.);
238 }
239 // This logic suppose that the last (4-th) cell at interface have same size with the
240 // other three cells. This is also consitent with 2:1 refinement.
241 // TODO: extended to anisotropic mesh
242 if (cell_sizes[neigh_block_id] < cell_sizes[cur_cell_block_id]) {
243 fac = (3. / 4.);
244 }
245 const auto inv_dist = 1. / (fac * cell_center_dist);
246
247 int sign = 1 - 2 * (dir % 2);
248 acc_rho += sign * inv_dist
249 * (field_access_rho(id_b) - field_access_rho(cell_global_id));
250 acc_rhoe += sign * inv_dist
251 * (field_access_rhoe(id_b) - field_access_rhoe(cell_global_id));
252 acc_rho_vel
253 += sign * inv_dist
254 * (field_access_rho_vel(id_b) - field_access_rho_vel(cell_global_id));
255 });
256
258 = {shambase::VectorProperties<Tscal>::get_zero(),
259 shambase::VectorProperties<Tscal>::get_zero(),
260
261 {shambase::VectorProperties<Tscal>::get_zero(),
262 shambase::VectorProperties<Tscal>::get_zero(),
263 shambase::VectorProperties<Tscal>::get_zero()}};
264 if (cnt > 0) {
265 res = {acc_rho, acc_rhoe, acc_rho_vel};
266 res *= 1. / cnt;
267 }
268 return res;
269 };
270
271 auto get_avg_neigh = [&](auto &graph_links) -> shammath::ConsState<Tvec> {
272 Tscal acc_rho = shambase::VectorProperties<Tscal>::get_zero();
273 Tscal acc_rhoe = shambase::VectorProperties<Tscal>::get_zero();
274 Tvec acc_rho_vel = shambase::VectorProperties<Tvec>::get_zero();
275 u32 cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
276 acc_rho += field_access_rho(id_b);
277 acc_rho_vel += field_access_rho_vel(id_b);
278 acc_rhoe += field_access_rhoe(id_b);
279 });
280
282 = {shambase::VectorProperties<Tscal>::get_zero(),
283 shambase::VectorProperties<Tscal>::get_zero(),
284
285 {shambase::VectorProperties<Tscal>::get_zero(),
286 shambase::VectorProperties<Tscal>::get_zero(),
287 shambase::VectorProperties<Tscal>::get_zero()}};
288 if (cnt > 0) {
289 res = {acc_rho, acc_rhoe, acc_rho_vel};
290 res *= 1. / cnt;
291 }
292 return res;
293 };
294
295 shammath::ConsState<Tvec> delta_xp = get_gradient_dir(graph_iter_xp, Direction::xp);
296 shammath::ConsState<Tvec> delta_xm = get_gradient_dir(graph_iter_xm, Direction::xm);
297 shammath::ConsState<Tvec> delta_yp = get_gradient_dir(graph_iter_yp, Direction::yp);
298 shammath::ConsState<Tvec> delta_ym = get_gradient_dir(graph_iter_ym, Direction::ym);
299 shammath::ConsState<Tvec> delta_zp = get_gradient_dir(graph_iter_zp, Direction::zp);
300 shammath::ConsState<Tvec> delta_zm = get_gradient_dir(graph_iter_zm, Direction::zm);
301
302 shammath::ConsState<Tvec> lim_slope_x
303 = {slope_function<Tscal, mode>(delta_xm.rho, delta_xp.rho),
304 slope_function<Tscal, mode>(delta_xm.rhoe, delta_xp.rhoe),
305 slope_function<Tvec, mode>(delta_xm.rhovel, delta_xp.rhovel)};
306
307 shammath::ConsState<Tvec> lim_slope_y
308 = {slope_function<Tscal, mode>(delta_ym.rho, delta_yp.rho),
309 slope_function<Tscal, mode>(delta_ym.rhoe, delta_yp.rhoe),
310 slope_function<Tvec, mode>(delta_ym.rhovel, delta_yp.rhovel)};
311
312 shammath::ConsState<Tvec> lim_slope_z
313 = {slope_function<Tscal, mode>(delta_zm.rho, delta_zp.rho),
314 slope_function<Tscal, mode>(delta_zm.rhoe, delta_zp.rhoe),
315 slope_function<Tvec, mode>(delta_zm.rhovel, delta_zp.rhovel)};
316
317 return {lim_slope_x, lim_slope_y, lim_slope_z};
318 }
319
323 template<class T, class Tvec, class ACCField>
324 inline T get_pseudo_grad(
325 const u32 cell_global_id,
326 const AMRGraphLinkiterator &graph_iter_xp,
327 const AMRGraphLinkiterator &graph_iter_xm,
328 const AMRGraphLinkiterator &graph_iter_yp,
329 const AMRGraphLinkiterator &graph_iter_ym,
330 const AMRGraphLinkiterator &graph_iter_zp,
331 const AMRGraphLinkiterator &graph_iter_zm,
332 ACCField &&field_access)
333
334 {
335
336 using namespace sham;
337 using namespace sham::details;
338
339 auto get_avg_neigh = [&](auto &graph_links, u32 dir) -> T {
340 T acc = shambase::VectorProperties<T>::get_zero();
341 u32 cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
342 acc += field_access(id_b);
343 });
344
345 return (cnt > 0) ? acc / cnt : shambase::VectorProperties<T>::get_zero();
346 };
347
348 auto epsilon = shambase::get_epsilon<T>();
349 T u_cur = field_access(cell_global_id);
350 T u_xp = get_avg_neigh(graph_iter_xp, 0);
351 T u_xm = get_avg_neigh(graph_iter_xm, 1);
352 T u_yp = get_avg_neigh(graph_iter_yp, 2);
353 T u_ym = get_avg_neigh(graph_iter_ym, 3);
354 T u_zp = get_avg_neigh(graph_iter_zp, 4);
355 T u_zm = get_avg_neigh(graph_iter_zm, 5);
356
357 // RAMSES LIKE
358
359 T x_scal = 2
360 * g_sycl_max(
361 g_sycl_abs((u_cur - u_xm) / (epsilon + u_cur + u_xm)),
362 g_sycl_abs((u_cur - u_xp) / (epsilon + u_cur + u_xp)));
363
364 T y_scal = 2
365 * g_sycl_max(
366 g_sycl_abs((u_cur - u_ym) / (epsilon + u_cur + u_ym)),
367 g_sycl_abs((u_cur - u_yp) / (epsilon + u_cur + u_yp)));
368 T z_scal = 2
369 * g_sycl_max(
370 g_sycl_abs((u_cur - u_zm) / (epsilon + u_cur + u_zm)),
371 g_sycl_abs((u_cur - u_zp) / (epsilon + u_cur + u_zp)));
372
373 T res = g_sycl_max(x_scal, g_sycl_max(y_scal, z_scal));
374 return res;
375 }
376
379 template<class T, class ACCField>
380 inline T baryonic_normalized_slope_criterion(
381 const u32 cell_global_id,
382 const AMRGraphLinkiterator &graph_iter_xp,
383 const AMRGraphLinkiterator &graph_iter_xm,
384 const AMRGraphLinkiterator &graph_iter_yp,
385 const AMRGraphLinkiterator &graph_iter_ym,
386 const AMRGraphLinkiterator &graph_iter_zp,
387 const AMRGraphLinkiterator &graph_iter_zm,
388 ACCField &&field_access)
389
390 {
391
392 using namespace sham;
393 using namespace sham::details;
394
395 auto get_avg_neigh = [&](auto &graph_links, u32 dir) -> T {
396 T acc = shambase::VectorProperties<T>::get_zero();
397 u32 cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
398 acc += field_access(id_b);
399 });
400
401 return (cnt > 0) ? acc / cnt : shambase::VectorProperties<T>::get_zero();
402 };
403
404 auto epsilon = shambase::get_epsilon<T>();
405 T u_cur = field_access(cell_global_id);
406 T u_xp = get_avg_neigh(graph_iter_xp, 0);
407 T u_xm = get_avg_neigh(graph_iter_xm, 1);
408 T u_yp = get_avg_neigh(graph_iter_yp, 2);
409 T u_ym = get_avg_neigh(graph_iter_ym, 3);
410 T u_zp = get_avg_neigh(graph_iter_zp, 4);
411 T u_zm = get_avg_neigh(graph_iter_zm, 5);
412
413 T norm_slope_x = g_sycl_abs((u_xm - u_xp) / (2 * u_cur + epsilon));
414 T norm_slope_y = g_sycl_abs((u_ym - u_yp) / (2 * u_cur + epsilon));
415 T norm_slope_z = g_sycl_abs((u_zm - u_zp) / (2 * u_cur + epsilon));
416
417 T res = g_sycl_max(norm_slope_x, g_sycl_max(norm_slope_y, norm_slope_z));
418
419 return res;
420 }
421
422 /***
423 * Lohner second order criterion
424 */
425 template<class T, class Tvec, class ACCField>
426 inline T modif_second_derivative(
427 const u32 cell_global_id,
428 const AMRGraphLinkiterator &graph_iter_xp,
429 const AMRGraphLinkiterator &graph_iter_xm,
430 const AMRGraphLinkiterator &graph_iter_yp,
431 const AMRGraphLinkiterator &graph_iter_ym,
432 const AMRGraphLinkiterator &graph_iter_zp,
433 const AMRGraphLinkiterator &graph_iter_zm,
434 ACCField &&field_access) {
435 using namespace sham;
436 using namespace sham::details;
437
438 auto get_avg_neigh = [&](auto &graph_links) -> T {
439 T acc = shambase::VectorProperties<T>::get_zero();
440 u32 cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
441 acc += field_access(id_b);
442 });
443 return (cnt > 0) ? acc / cnt : shambase::VectorProperties<T>::get_zero();
444 };
445
446 auto eps_ref = 0.01;
447 auto epsilon = shambase::get_epsilon<T>();
448 T u_cur = field_access(cell_global_id);
449 T u_xp = get_avg_neigh(graph_iter_xp);
450 T u_xm = get_avg_neigh(graph_iter_xm);
451 T u_yp = get_avg_neigh(graph_iter_yp);
452 T u_ym = get_avg_neigh(graph_iter_ym);
453 T u_zp = get_avg_neigh(graph_iter_zp);
454 T u_zm = get_avg_neigh(graph_iter_zm);
455
456 T delta_u_xp = u_xp - u_cur;
457 T delta_u_xm = u_xm - u_cur;
458 T delta_u_yp = u_yp - u_cur;
459 T delta_u_ym = u_ym - u_cur;
460 T delta_u_zp = u_zp - u_cur;
461 T delta_u_zm = u_zm - u_cur;
462
463 T scalar_x = g_sycl_abs(u_xp) + g_sycl_abs(u_xm) + 2 * g_sycl_abs(u_cur);
464 T scalar_y = g_sycl_abs(u_yp) + g_sycl_abs(u_ym) + 2 * g_sycl_abs(u_cur);
465 T scalar_z = g_sycl_abs(u_zp) + g_sycl_abs(u_zm) + 2 * g_sycl_abs(u_cur);
466
467 T res_x
468 = g_sycl_abs(delta_u_xm + delta_u_xp)
469 / (g_sycl_abs(delta_u_xm) + g_sycl_abs(delta_u_xp) + eps_ref * scalar_x + epsilon);
470 T res_y
471 = g_sycl_abs(delta_u_ym + delta_u_yp)
472 / (g_sycl_abs(delta_u_ym) + g_sycl_abs(delta_u_yp) + eps_ref * scalar_y + epsilon);
473 T res_z
474 = g_sycl_abs(delta_u_zm + delta_u_zp)
475 / (g_sycl_abs(delta_u_zm) + g_sycl_abs(delta_u_zp) + eps_ref * scalar_z + epsilon);
476
477 return (res_x + res_y + res_z);
478 }
479
483 template<class Tvec, class ACCField>
484 inline shambase::VecComponent<Tvec> normalized_shear(
485 const u32 cell_global_id,
486 const f32 sound_speed,
487 const Tvec delta_cells,
488 const AMRGraphLinkiterator &graph_iter_xp,
489 const AMRGraphLinkiterator &graph_iter_xm,
490 const AMRGraphLinkiterator &graph_iter_yp,
491 const AMRGraphLinkiterator &graph_iter_ym,
492 const AMRGraphLinkiterator &graph_iter_zp,
493 const AMRGraphLinkiterator &graph_iter_zm,
494 ACCField &&field_access)
495
496 {
497
498 using namespace sham;
499 using namespace sham::details;
500
501 auto get_avg_neigh = [&](auto &graph_links, u32 dir) -> Tvec {
502 Tvec acc = shambase::VectorProperties<Tvec>::get_zero();
503 u32 cnt = graph_links.for_each_object_link_cnt(cell_global_id, [&](u32 id_b) {
504 acc += field_access(id_b);
505 });
506
507 return (cnt > 0) ? acc / cnt : shambase::VectorProperties<Tvec>::get_zero();
508 };
509
510 Tvec u_xp = get_avg_neigh(graph_iter_xp, 0);
511 Tvec u_xm = get_avg_neigh(graph_iter_xm, 1);
512 Tvec u_yp = get_avg_neigh(graph_iter_yp, 2);
513 Tvec u_ym = get_avg_neigh(graph_iter_ym, 3);
514 Tvec u_zp = get_avg_neigh(graph_iter_zp, 4);
515 Tvec u_zm = get_avg_neigh(graph_iter_zm, 5);
516
517 auto vgy = 0.25 * (u_xp[1] - u_xm[1]) * (u_xp[1] - u_xm[1]);
518 auto vgx = 0.25 * (u_yp[0] - u_ym[0]) * (u_yp[0] - u_ym[0]);
519
520 return vgy + vgx;
521
525 // auto dv_xdir = 0.5 * sycl::abs(u_xp - u_xm);
526 // auto dv_ydir = 0.5 * sycl::abs(u_yp - u_ym);
527 // auto dv_zdir = 0.5 * sycl::abs(u_zp - u_zm) ;
528 // auto shear_1 = (dv_ydir[0] + dv_xdir[1])*(dv_ydir[0] + dv_xdir[1]);
529 // auto shear_2 = (dv_ydir[2] + dv_zdir[1]) * (dv_ydir[2] + dv_zdir[1]);
530 // auto shear_3 = (dv_zdir[0] + dv_xdir[2]) * (dv_zdir[0] + dv_xdir[2]);
531 // return (shear_1 + shear_2 + shear_3) * (delta_cells.x() * delta_cells.x())/(sound_speed
532 // * sound_speed);
533 }
534
535} // namespace
double f64
Alias for double.
float f32
Alias for float.
std::uint32_t u32
32 bit unsigned integer
namespace for backends this one is named only sham since shambackends is too long to write
T van_leer_slope(T f, T g)
Van leer slope limiter.
SlopeMode
Slope limiter modes.
Umbrella header pulling in the gas states and all gas Riemann solvers (Rusanov, HLL,...
Math header to compute slope limiters.