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