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