ryujin 2.5.0 revision c64172211cf21344cb9b9b0f3a1266aa6400d392
Loading...
Searching...
No Matches
limiter.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2023 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include <ryujin/base/compile_time_options.h>
9#include <ryujin/base/gpu.h>
11#include <ryujin/base/simd.h>
14
15namespace ryujin
16{
17 namespace ScalarConservation
18 {
19 template <int dim,
20 typename Number = double,
21 typename MemorySpace = dealii::MemorySpace::Host>
22 class LimiterView;
23
29 template <typename ScalarNumber = double>
30 class Limiter : public dealii::ParameterAcceptor
31 {
32 public:
37
41 struct Parameters {
42 unsigned int iterations;
44 };
45
47
51
55 Limiter(const HyperbolicSystem &hyperbolic_system,
56 const std::string &subsection = "/Limiter")
57 : ParameterAcceptor(subsection)
58 , parameters_("scalar_conservation_limiter_parameters",
60 , hyperbolic_system_(&hyperbolic_system)
61 {
62 /* reference remains valid due to implicit_transfers_host_resident */
63 auto &parameters = *parameters_.view();
64
65 parameters.iterations = 2;
66 add_parameter("iterations",
67 parameters.iterations,
68 "Number of limiter iterations");
69
70 parameters.relaxation_factor = 1.;
71 add_parameter("relaxation factor",
72 parameters.relaxation_factor,
73 "Factor for scaling the relaxation window with r_i = "
74 "factor * (m_i/|Omega|)^(1.5/d).");
75
76 /* invalidates view on default memory space */
77 ParameterAcceptor::parse_parameters_call_back.connect(
78 [this] { parameters_.view(); });
79 }
80
88 template <int dim,
89 typename Number,
90 typename MemorySpace = dealii::MemorySpace::Host>
91 auto view() const
92 {
94 hyperbolic_system_->template view<dim, Number, MemorySpace>(),
95 *this};
96 }
97
98 private:
100
104
105 Mirrored<Parameters> parameters_;
106
108
112
113 dealii::ObserverPointer<const HyperbolicSystem> hyperbolic_system_;
114
115 template <int, typename, typename>
116 friend class LimiterView;
117
119 };
120
121
130 template <int dim, typename Number, typename MemorySpace>
132 {
133 public:
134 static_assert(
135 std::is_same_v<MemorySpace, dealii::MemorySpace::Host> ||
136 std::is_same_v<MemorySpace, dealii::MemorySpace::Default>,
137 "Unexpected memory space");
138
143
145
147
148 using state_type = typename View::state_type;
149
151
153
155
159
163 static constexpr unsigned int n_bounds = 2;
164
168 using Bounds = std::array<Number, n_bounds>;
169
174 LimiterView(const View &view, const Limiter<ScalarNumber> &limiter)
175 : view_(view)
176 , parameters_(limiter.parameters_.template view<MemorySpace>())
177 {
178 }
179
183 DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int iterations() const
184 {
185 return parameters_->iterations;
186 }
187
191 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber relaxation_factor() const
192 {
193 return ScalarNumber(parameters_->relaxation_factor);
194 }
195
200 DEAL_II_HOST_DEVICE Bounds
202 const unsigned int i,
203 const state_type &U_i) const;
204
210 DEAL_II_HOST_DEVICE Bounds combine_bounds(
211 const Bounds &bounds_left, const Bounds &bounds_right) const;
212
218 DEAL_II_HOST_DEVICE Bounds fully_relax_bounds(const Bounds &bounds,
219 const Number &hd) const;
220
222
241
245 DEAL_II_HOST_DEVICE void reset(const PrecomputedVectorView &pv,
246 const unsigned int i,
247 const state_type &U_i,
248 const flux_contribution_type &flux_i);
249
254 DEAL_II_HOST_DEVICE void
256 const unsigned int *js,
257 const state_type &U_j,
258 const flux_contribution_type &flux_j,
259 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
260 const state_type &affine_shift);
261
265 DEAL_II_HOST_DEVICE Bounds bounds(const Number hd_i) const;
266
268
272
279 DEAL_II_HOST_DEVICE std::tuple<Number, bool>
280 limit(const Bounds &bounds,
281 const state_type &U,
282 const state_type &P,
283 const Number t_min = Number(0.),
284 const Number t_max = Number(1.)) const;
285
286 private:
288
292
293 const View view_;
294 const Limiter<ScalarNumber>::Parameters *const parameters_;
295
296 state_type U_i_;
298
299 Bounds bounds_;
300
301 Number u_relaxation_numerator_;
302 Number u_relaxation_denominator_;
304 };
305
306
307 /*
308 * -------------------------------------------------------------------------
309 * Inline definitions
310 * -------------------------------------------------------------------------
311 */
312
313
314 template <int dim, typename Number, typename MemorySpace>
315 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
317 const PrecomputedVectorView & /*pv*/,
318 const unsigned int /*i*/,
319 const state_type &U_i) const -> Bounds
320 {
321 const auto u_i = view_.state(U_i);
322 return {/*u_min*/ u_i, /*u_max*/ u_i};
323 }
324
325
326 template <int dim, typename Number, typename MemorySpace>
327 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
329 const Bounds &bounds_left, const Bounds &bounds_right) const -> Bounds
330 {
331 const auto &[u_min_l, u_max_l] = bounds_left;
332 const auto &[u_min_r, u_max_r] = bounds_right;
333
334 return {std::min(u_min_l, u_min_r), std::max(u_max_l, u_max_r)};
335 }
336
337
338 template <int dim, typename Number, typename MemorySpace>
339 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
341 const Bounds &bounds, const Number &hd) const -> Bounds
342 {
343 auto relaxed_bounds = bounds;
344 auto &[u_min, u_max] = relaxed_bounds;
345
346 /* Use r = factor * (m_i / |Omega|) ^ (1.5 / d): */
347
348 Number r = std::sqrt(hd); // in 3D: ^ 3/6
349 if constexpr (dim == 2) //
350 r = ryujin::fixed_power<3>(std::sqrt(r)); // in 2D: ^ 3/4
351 else if constexpr (dim == 1) //
352 r = ryujin::fixed_power<3>(r); // in 1D: ^ 3/2
353 r *= relaxation_factor();
354
355 u_min = std::min((Number(1.) - r) * u_min, (Number(1.) + r) * u_min);
356 u_max = std::max((Number(1.) + r) * u_max, (Number(1.) - r) * u_max);
357
358 return relaxed_bounds;
359 }
360
361
362 template <int dim, typename Number, typename MemorySpace>
363 DEAL_II_HOST_DEVICE_ALWAYS_INLINE void
365 const PrecomputedVectorView & /*pv*/,
366 const unsigned int /*i*/,
367 const state_type &U_i,
368 const flux_contribution_type &flux_i)
369 {
370 U_i_ = U_i;
371 flux_i_ = flux_i;
372
373 /* Bounds: */
374
375 auto &[u_min, u_max] = bounds_;
376
377 u_min = Number(std::numeric_limits<ScalarNumber>::max());
378 u_max = Number(std::numeric_limits<ScalarNumber>::lowest());
379
380 /* Relaxation: */
381
382 u_relaxation_numerator_ = Number(0.);
383 u_relaxation_denominator_ = Number(0.);
384 }
385
386
387 template <int dim, typename Number, typename MemorySpace>
388 DEAL_II_HOST_DEVICE_ALWAYS_INLINE void
390 const PrecomputedVectorView & /*pv*/,
391 const unsigned int * /*js*/,
392 const state_type &U_j,
393 const flux_contribution_type &flux_j,
394 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
395 const state_type &affine_shift)
396 {
397 /* Bounds: */
398 auto &[u_min, u_max] = bounds_;
399
400 const auto u_i = view_.state(U_i_);
401 const auto u_j = view_.state(U_j);
402
403 const auto U_ij_bar =
404 ScalarNumber(0.5) * (U_i_ + U_j) -
405 ScalarNumber(0.5) * contract(add(flux_j, -flux_i_), scaled_c_ij) +
406 affine_shift;
407
408 const auto u_ij_bar = view_.state(U_ij_bar);
409
410 /* Bounds: */
411
412 u_min = std::min(u_min, u_ij_bar);
413 u_max = std::max(u_max, u_ij_bar);
414
415 /* Relaxation: */
416
417 /* Use a uniform weight. */
418 const auto beta_ij = Number(1.);
419 u_relaxation_numerator_ += beta_ij * (u_i + u_j);
420 u_relaxation_denominator_ += std::abs(beta_ij);
421 }
422
423
424 template <int dim, typename Number, typename MemorySpace>
425 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
427 -> Bounds
428 {
429 const auto &[u_min, u_max] = bounds_;
430
431 auto relaxed_bounds = fully_relax_bounds(bounds_, hd_i);
432 auto &[u_min_relaxed, u_max_relaxed] = relaxed_bounds;
433
434 /* Apply a stricter window: */
435
436 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
437
438 const Number u_relaxation =
439 ScalarNumber(2. * relaxation_factor()) *
440 std::abs(u_relaxation_numerator_) /
441 (std::abs(u_relaxation_denominator_) + Number(eps));
442
443 u_min_relaxed = std::max(u_min_relaxed, u_min - u_relaxation);
444 u_max_relaxed = std::min(u_max_relaxed, u_max + u_relaxation);
445
446 return relaxed_bounds;
447 }
448
449
450 template <int dim, typename Number, typename MemorySpace>
451 DEAL_II_HOST_DEVICE_ALWAYS_INLINE std::tuple<Number, bool>
453 const Bounds &bounds,
454 const state_type &U,
455 const state_type &P,
456 const Number t_min /* = Number(0.) */,
457 const Number t_max /* = Number(1.) */) const
458 {
459 bool success = true;
460 Number t_r = t_max;
461
462 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
463 const ScalarNumber relax = ScalarNumber(1. + 10000. * eps);
464
465 const auto &u_U = view_.state(U);
466 const auto &u_P = view_.state(P);
467
468 const auto &u_min = std::get<0>(bounds);
469 const auto &u_max = std::get<1>(bounds);
470
471 /*
472 * Verify that u_U is within bounds. This property might be
473 * violated for relative CFL numbers larger than 1.
474 *
475 * u_min, u_U, u_max might be negative, thus relax in both directions.
476 */
477 const auto test_max = std::max(
478 Number(0.), std::min(u_U - relax * u_max, relax * u_U - u_max));
479 const auto test_min = std::max(
480 Number(0.), std::min(u_min - relax * u_U, relax * u_min - u_U));
481 if (!(test_max == Number(0.) && test_min == Number(0.))) {
482#ifdef DEBUG_OUTPUT
483 std::cout << std::fixed << std::setprecision(16);
484 std::cout << "Bounds violation: low-order state (critical)!"
485 << "\n\t\tu min: " << u_min
486 << "\n\t\tu min (delta): " << negative_part(u_U - u_min)
487 << "\n\t\tu: " << u_U
488 << "\n\t\tu max (delta): " << positive_part(u_U - u_max)
489 << "\n\t\tu max: " << u_max << "\n"
490 << std::endl;
491#endif
492 success = false;
493 }
494
495 const auto regularization =
496 Number(100. * std::numeric_limits<ScalarNumber>::min());
497
498 const Number denominator =
499 ScalarNumber(1.) /
500 std::max(regularization, std::abs(u_P) + eps * u_max);
501
502 t_r = ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
503 u_max,
504 u_U + t_r * u_P,
505 /*
506 * u_P is positive.
507 *
508 * Note: Do not take an absolute value here. If we are out of
509 * bounds we have to ensure that t_r is set to t_min.
510 */
511 (u_max - u_U) * denominator,
512 t_r);
513
514 t_r = ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
515 u_U + t_r * u_P,
516 u_min,
517 /*
518 * u_P is negative.
519 *
520 * Note: Do not take an absolute value here. If we are out of
521 * bounds we have to ensure that t_r is set to t_min.
522 */
523 (u_U - u_min) * denominator,
524 t_r);
525
526 /*
527 * Ensure that t_min <= t <= t_max. This might not be the case if
528 * u_U is outside the interval [u_min, u_max]. Furthermore,
529 * the quotient we take above is prone to numerical cancellation in
530 * particular in the second pass of the limiter when u_P might be
531 * small.
532 */
533 t_r = std::min(t_r, t_max);
534 t_r = std::max(t_r, t_min);
535
536#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
537 /*
538 * Verify that the new state is within bounds:
539 *
540 * u_min, u_U, u_max might be negative, thus relax in both directions.
541 */
542 const auto u_new = view_.state(U + t_r * P);
543 const auto test_new_max = std::max(
544 Number(0.), std::min(u_new - relax * u_max, relax * u_new - u_max));
545 const auto test_new_min = std::max(
546 Number(0.), std::min(u_min - relax * u_new, relax * u_min - u_new));
547 if (!(test_new_max == Number(0.) && test_new_min == Number(0.))) {
548#ifdef DEBUG_OUTPUT
549 std::cout << std::fixed << std::setprecision(16);
550 std::cout << "Bounds violation: high-order state!"
551 << "\n\t\tu min: " << u_min
552 << "\n\t\tu min (delta): " << negative_part(u_new - u_min)
553 << "\n\t\tu: " << u_new
554 << "\n\t\tu max (delta): " << positive_part(u_new - u_max)
555 << "\n\t\tu max: " << u_max << "\n"
556 << std::endl;
557#endif
558 success = false;
559 }
560#endif
561
562 return {t_r, success};
563 }
564 } // namespace ScalarConservation
565} // namespace ryujin
dealii::Tensor< 1, problem_dimension, Number > state_type
typename get_value_type< Number >::type ScalarNumber
VectorView< n_precomputed_values > PrecomputedVectorView
typename View::PrecomputedVectorView PrecomputedVectorView
Definition limiter.h:152
DEAL_II_HOST_DEVICE void accumulate(const PrecomputedVectorView &pv, const unsigned int *js, const state_type &U_j, const flux_contribution_type &flux_j, const dealii::Tensor< 1, dim, Number > &scaled_c_ij, const state_type &affine_shift)
Definition limiter.h:389
DEAL_II_HOST_DEVICE Bounds bounds(const Number hd_i) const
Definition limiter.h:426
typename View::state_type state_type
Definition limiter.h:148
DEAL_II_HOST_DEVICE Bounds fully_relax_bounds(const Bounds &bounds, const Number &hd) const
Definition limiter.h:340
typename View::ScalarNumber ScalarNumber
Definition limiter.h:146
DEAL_II_HOST_DEVICE Bounds projection_bounds_from_state(const PrecomputedVectorView &pv, const unsigned int i, const state_type &U_i) const
Definition limiter.h:316
static constexpr unsigned int n_bounds
Definition limiter.h:163
std::array< Number, n_bounds > Bounds
Definition limiter.h:168
DEAL_II_HOST_DEVICE Bounds combine_bounds(const Bounds &bounds_left, const Bounds &bounds_right) const
Definition limiter.h:328
typename View::flux_contribution_type flux_contribution_type
Definition limiter.h:150
DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int iterations() const
Definition limiter.h:183
DEAL_II_HOST_DEVICE void reset(const PrecomputedVectorView &pv, const unsigned int i, const state_type &U_i, const flux_contribution_type &flux_i)
Definition limiter.h:364
HyperbolicSystemView< dim, Number, MemorySpace > View
Definition limiter.h:144
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber relaxation_factor() const
Definition limiter.h:191
LimiterView(const View &view, const Limiter< ScalarNumber > &limiter)
Definition limiter.h:174
DEAL_II_HOST_DEVICE std::tuple< Number, bool > limit(const Bounds &bounds, const state_type &U, const state_type &P, const Number t_min=Number(0.), const Number t_max=Number(1.)) const
Definition limiter.h:452
Limiter(const HyperbolicSystem &hyperbolic_system, const std::string &subsection="/Limiter")
Definition limiter.h:55
TransferPolicy
Definition gpu.h:88
DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number positive_part(const Number number)
Definition simd.h:134
DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number negative_part(const Number number)
Definition simd.h:146
DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor< 1, problem_dim, T > contract(const FT &flux_ij, const TT &c_ij)
DEAL_II_HOST_DEVICE_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)