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 <newton.h>
15#include <observer_pointer.h>
16#include <simd.h>
17
18// #define DEBUG_OUTPUT_LIMITER
19
20namespace ryujin
21{
22 namespace EulerBarotropic
23 {
24 template <int dim,
25 typename Number = double,
26 typename MemorySpace = dealii::MemorySpace::Host>
27 class LimiterView;
28
34 template <typename ScalarNumber = double>
35 class Limiter : public dealii::ParameterAcceptor
36 {
37 public:
42
46 struct Parameters {
47 unsigned int iterations;
49 };
50
52
56
60 Limiter(const HyperbolicSystem &hyperbolic_system,
61 const std::string &subsection = "/Limiter")
62 : ParameterAcceptor(subsection)
63 , parameters_("euler_barotropic_limiter_parameters",
65 , hyperbolic_system_(&hyperbolic_system)
66 {
67 /* reference remains valid due to implicit_transfers_host_resident */
68 auto &parameters = *parameters_.view();
69
70 parameters.iterations = 2;
71 add_parameter("iterations",
72 parameters.iterations,
73 "Number of limiter iterations");
74
75 parameters.relaxation_factor = 1.;
76 add_parameter("relaxation factor",
77 parameters.relaxation_factor,
78 "Factor for scaling the relaxation window with r_i = "
79 "factor * (m_i/|Omega|)^(1.5/d).");
80
81 /* invalidates view on default memory space */
82 ParameterAcceptor::parse_parameters_call_back.connect(
83 [this] { parameters_.view(); });
84 }
85
93 template <int dim,
94 typename Number,
95 typename MemorySpace = dealii::MemorySpace::Host>
96 auto view() const
97 {
99 hyperbolic_system_->template view<dim, Number, MemorySpace>(),
100 *this};
101 }
102
103 private:
105
109
110 Mirrored<Parameters> parameters_;
111
113
117
118 dealii::ObserverPointer<const HyperbolicSystem> hyperbolic_system_;
119
120 template <int, typename, typename>
121 friend class LimiterView;
122
124 };
125
126
135 template <int dim, typename Number, typename MemorySpace>
137 {
138 public:
139 static_assert(
140 std::is_same_v<MemorySpace, dealii::MemorySpace::Host> ||
141 std::is_same_v<MemorySpace, dealii::MemorySpace::Default>,
142 "Unexpected memory space");
143
148
150
152
153 using state_type = typename View::state_type;
154
156
158
160
167 static constexpr unsigned int n_bounds = 2;
168
172 using Bounds = std::array<Number, n_bounds>;
173
178 LimiterView(const View &view, const Limiter<ScalarNumber> &limiter)
179 : view_(view)
180 , parameters_(limiter.parameters_.template view<MemorySpace>())
181 {
182 }
183
187 DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int iterations() const
188 {
189 return parameters_->iterations;
190 }
191
195 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber relaxation_factor() const
196 {
197 return ScalarNumber(parameters_->relaxation_factor);
198 }
199
204 DEAL_II_HOST_DEVICE Bounds
206 const unsigned int i,
207 const state_type &U_i) const;
208
214 DEAL_II_HOST_DEVICE Bounds combine_bounds(
215 const Bounds &bounds_left, const Bounds &bounds_right) const;
216
225 DEAL_II_HOST_DEVICE Bounds fully_relax_bounds(const Bounds &bounds,
226 const Number &hd) const;
227
229
248
252 DEAL_II_HOST_DEVICE void reset(const PrecomputedVectorView &pv,
253 const unsigned int i,
254 const state_type &U_i,
255 const flux_contribution_type &flux_i);
256
261 DEAL_II_HOST_DEVICE void
263 const unsigned int *js,
264 const state_type &U_j,
265 const flux_contribution_type &flux_j,
266 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
267 const state_type &affine_shift);
268
272 DEAL_II_HOST_DEVICE Bounds bounds(const Number hd_i) const;
273
275
279
295 DEAL_II_HOST_DEVICE std::tuple<Number, bool>
296 limit(const Bounds &bounds,
297 const state_type &U,
298 const state_type &P,
299 const Number t_min = Number(0.),
300 const Number t_max = Number(1.)) const;
301
302 private:
304
308
309 const View view_;
310 const Limiter<ScalarNumber>::Parameters *const parameters_;
311
312 state_type U_i_;
314
315 Bounds bounds_;
316
317 Number rho_relaxation_numerator_;
318 Number rho_relaxation_denominator_;
319
321 };
322
323
324 /*
325 * -------------------------------------------------------------------------
326 * Inline definitions
327 * -------------------------------------------------------------------------
328 */
329
330
331 template <int dim, typename Number, typename MemorySpace>
332 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
334 const PrecomputedVectorView & /*pv*/,
335 const unsigned int /*i*/,
336 const state_type &U_i) const -> Bounds
337 {
338 const auto rho_i = view_.density(U_i);
339 return {/*rho_min*/ rho_i, /*rho_max*/ rho_i};
340 }
341
342
343 template <int dim, typename Number, typename MemorySpace>
344 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
346 const Bounds &bounds_left, const Bounds &bounds_right) const -> Bounds
347 {
348 const auto &[rho_min_l, rho_max_l] = bounds_left;
349 const auto &[rho_min_r, rho_max_r] = bounds_right;
350
351 return {std::min(rho_min_l, rho_min_r), std::max(rho_max_l, rho_max_r)};
352 }
353
354
355 template <int dim, typename Number, typename MemorySpace>
356 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
358 const Bounds &bounds, const Number &hd) const -> Bounds
359 {
360 auto relaxed_bounds = bounds;
361 auto &[rho_min_relaxed, rho_max_relaxed] = relaxed_bounds;
362
363 /* Use r = factor * (m_i / |Omega|) ^ (1.5 / d): */
364
365 Number r = std::sqrt(hd); // in 3D: ^ 3/6
366 if constexpr (dim == 2) //
367 r = dealii::Utilities::fixed_power<3>(std::sqrt(r)); // in 2D: ^ 3/4
368 else if constexpr (dim == 1) //
369 r = dealii::Utilities::fixed_power<3>(r); // in 1D: ^ 3/2
370 r *= relaxation_factor();
371
372 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
373 rho_min_relaxed *= std::max(Number(1.) - r, Number(eps));
374 rho_max_relaxed *= (Number(1.) + r);
375
376 return relaxed_bounds;
377 }
378
379
380 template <int dim, typename Number, typename MemorySpace>
381 DEAL_II_HOST_DEVICE_ALWAYS_INLINE void
383 const PrecomputedVectorView & /*pv*/,
384 const unsigned int /*i*/,
385 const state_type &U_i,
386 const flux_contribution_type &flux_i)
387 {
388 U_i_ = U_i;
389 flux_i_ = flux_i;
390
391 /* Bounds: */
392
393 auto &[rho_min, rho_max] = bounds_;
394
395 rho_min = Number(std::numeric_limits<ScalarNumber>::max());
396 rho_max = Number(0.);
397
398 /* Relaxation: */
399
400 rho_relaxation_numerator_ = Number(0.);
401 rho_relaxation_denominator_ = Number(0.);
402 }
403
404
405 template <int dim, typename Number, typename MemorySpace>
406 DEAL_II_HOST_DEVICE_ALWAYS_INLINE void
408 const PrecomputedVectorView & /*pv*/,
409 const unsigned int * /*js*/,
410 const state_type &U_j,
411 const flux_contribution_type &flux_j,
412 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
413 const state_type &affine_shift)
414 {
415 // TODO: Currently we only apply the affine_shift to U_ij_bar (which
416 // then enters all bounds), but we do not modify s_interp and
417 // rho_relaxation. When actually adding a source term to the Euler
418 // equations verify that this does the right thing.
419 Assert(std::max(affine_shift.norm(), Number(0.)) == Number(0.),
420 dealii::ExcNotImplemented());
421
422 /* Bounds: */
423 auto &[rho_min, rho_max] = bounds_;
424
425 const auto rho_i = view_.density(U_i_);
426 const auto rho_j = view_.density(U_j);
427
428 /* bar state shifted by an affine shift: */
429 const auto U_ij_bar =
430 ScalarNumber(0.5) * (U_i_ + U_j) -
431 ScalarNumber(0.5) * contract(add(flux_j, -flux_i_), scaled_c_ij) +
432 affine_shift;
433
434 const auto rho_ij_bar = view_.density(U_ij_bar);
435
436 /* Density bounds: */
437
438 rho_min = std::min(rho_min, rho_ij_bar);
439 rho_max = std::max(rho_max, rho_ij_bar);
440
441 /* Density relaxation: */
442
443 /* Use a uniform weight. */
444 const auto beta_ij = Number(1.);
445 rho_relaxation_numerator_ += beta_ij * (rho_i + rho_j);
446 rho_relaxation_denominator_ += std::abs(beta_ij);
447 }
448
449
450 template <int dim, typename Number, typename MemorySpace>
451 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
453 -> Bounds
454 {
455 const auto &[rho_min, rho_max] = bounds_;
456
457 auto relaxed_bounds = fully_relax_bounds(bounds_, hd_i);
458 auto &[rho_min_relaxed, rho_max_relaxed] = relaxed_bounds;
459
460 /* Apply a stricter window: */
461
462 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
463
464 const auto rho_relaxation =
465 ScalarNumber(2. * relaxation_factor()) *
466 std::abs(rho_relaxation_numerator_) /
467 (std::abs(rho_relaxation_denominator_) + Number(eps));
468
469 rho_min_relaxed = std::max(rho_min_relaxed, rho_min - rho_relaxation);
470 rho_max_relaxed = std::min(rho_max_relaxed, rho_max + rho_relaxation);
471
472 return relaxed_bounds;
473 }
474
475
476 template <int dim, typename Number, typename MemorySpace>
477 DEAL_II_HOST_DEVICE_ALWAYS_INLINE std::tuple<Number, bool>
479 const Bounds &bounds,
480 const state_type &U,
481 const state_type &P,
482 const Number t_min /* = Number(0.) */,
483 const Number t_max /* = Number(1.) */) const
484 {
485 bool success = true;
486 Number t_r = t_max;
487
488 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
489 const auto large = view_.vacuum_state_relaxation_large();
490 const ScalarNumber relax = ScalarNumber(1. + large * eps);
491
492 /*
493 * Limit the density rho.
494 */
495
496 {
497 const auto &rho_U = view_.density(U);
498 const auto &rho_P = view_.density(P);
499
500 const auto &rho_min = std::get<0>(bounds);
501 const auto &rho_max = std::get<1>(bounds);
502
503 /*
504 * Verify that rho_U is within bounds. This property might be
505 * violated for relative CFL numbers larger than 1.
506 */
507 const auto test_min = view_.filter_vacuum_density(
508 std::max(Number(0.), rho_U - relax * rho_max));
509 const auto test_max = view_.filter_vacuum_density(
510 std::max(Number(0.), rho_min - relax * rho_U));
511 if (!(test_min == Number(0.) && test_max == Number(0.))) {
512#ifdef DEBUG_OUTPUT
513 std::cout << std::fixed << std::setprecision(16);
514 std::cout << "Bounds violation: low-order density (critical)!"
515 << "\n\t\trho min: " << rho_min
516 << "\n\t\trho min (delta): "
517 << negative_part(rho_U - rho_min)
518 << "\n\t\trho: " << rho_U
519 << "\n\t\trho max (delta): "
520 << positive_part(rho_U - rho_max)
521 << "\n\t\trho max: " << rho_max << "\n"
522 << std::endl;
523#endif
524 success = false;
525 }
526
527 const Number denominator =
528 ScalarNumber(1.) / (std::abs(rho_P) + eps * rho_max);
529
530 t_r = ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
531 rho_max,
532 rho_U + t_r * rho_P,
533 /*
534 * rho_P is positive.
535 *
536 * Note: Do not take an absolute value here. If we are out of
537 * bounds we have to ensure that t_r is set to t_min.
538 */
539 (rho_max - rho_U) * denominator,
540 t_r);
541
542 t_r = ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
543 rho_U + t_r * rho_P,
544 rho_min,
545 /*
546 * rho_P is negative.
547 *
548 * Note: Do not take an absolute value here. If we are out of
549 * bounds we have to ensure that t_r is set to t_min.
550 */
551 (rho_U - rho_min) * denominator,
552 t_r);
553
554 /*
555 * Ensure that t_min <= t <= t_max. This might not be the case if
556 * rho_U is outside the interval [rho_min, rho_max]. Furthermore,
557 * the quotient we take above is prone to numerical cancellation in
558 * particular in the second pass of the limiter when rho_P might be
559 * small.
560 */
561 t_r = std::min(t_r, t_max);
562 t_r = std::max(t_r, t_min);
563
564#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
565 /*
566 * Verify that the new state is within bounds:
567 */
568 const auto rho_new = view_.density(U + t_r * P);
569 const auto test_new_min = view_.filter_vacuum_density(
570 std::max(Number(0.), rho_new - relax * rho_max));
571 const auto test_new_max = view_.filter_vacuum_density(
572 std::max(Number(0.), rho_min - relax * rho_new));
573 if (!(test_new_min == Number(0.) && test_new_max == Number(0.))) {
574#ifdef DEBUG_OUTPUT
575 std::cout << std::fixed << std::setprecision(16);
576 std::cout << "Bounds violation: high-order density!"
577 << "\n\t\trho min: " << rho_min
578 << "\n\t\trho min (delta): "
579 << negative_part(rho_new - rho_min)
580 << "\n\t\trho: " << rho_new
581 << "\n\t\trho max (delta): "
582 << positive_part(rho_new - rho_max)
583 << "\n\t\trho max: " << rho_max << "\n"
584 << std::endl;
585#endif
586 success = false;
587 }
588#endif
589 }
590
591 return {t_r, success};
592 }
593 } // namespace EulerBarotropic
594} // namespace ryujin
VectorView< n_precomputed_values > PrecomputedVectorView
dealii::Tensor< 1, problem_dimension, Number > state_type
typename get_value_type< Number >::type ScalarNumber
typename View::ScalarNumber ScalarNumber
Definition limiter.h:151
static constexpr unsigned int n_bounds
Definition limiter.h:167
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:478
DEAL_II_HOST_DEVICE Bounds fully_relax_bounds(const Bounds &bounds, const Number &hd) const
Definition limiter.h:357
typename View::PrecomputedVectorView PrecomputedVectorView
Definition limiter.h:157
typename View::flux_contribution_type flux_contribution_type
Definition limiter.h:155
typename View::state_type state_type
Definition limiter.h:153
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber relaxation_factor() const
Definition limiter.h:195
HyperbolicSystemView< dim, Number, MemorySpace > View
Definition limiter.h:149
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:407
DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int iterations() const
Definition limiter.h:187
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:333
DEAL_II_HOST_DEVICE Bounds bounds(const Number hd_i) const
Definition limiter.h:452
LimiterView(const View &view, const Limiter< ScalarNumber > &limiter)
Definition limiter.h:178
std::array< Number, n_bounds > Bounds
Definition limiter.h:172
DEAL_II_HOST_DEVICE Bounds combine_bounds(const Bounds &bounds_left, const Bounds &bounds_right) const
Definition limiter.h:345
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:382
Limiter(const HyperbolicSystem &hyperbolic_system, const std::string &subsection="/Limiter")
Definition limiter.h:60
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