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) 2020 - 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 EulerAEOS
23 {
24 template <int dim,
25 typename Number = double,
26 typename MemorySpace = dealii::MemorySpace::Host>
27 class LimiterView;
28
61 template <typename ScalarNumber = double>
62 class Limiter : public dealii::ParameterAcceptor
63 {
64 public:
69
73 struct Parameters {
74 unsigned int iterations;
78 };
79
81
85
89 Limiter(const HyperbolicSystem &hyperbolic_system,
90 const std::string &subsection = "/Limiter")
91 : ParameterAcceptor(subsection)
92 , parameters_("euler_aeos_limiter_parameters",
94 , hyperbolic_system_(&hyperbolic_system)
95 {
96 /* reference remains valid due to implicit_transfers_host_resident */
97 auto &parameters = *parameters_.view();
98
99 parameters.iterations = 2;
100 add_parameter("iterations",
101 parameters.iterations,
102 "Number of limiter iterations");
103
104 if constexpr (std::is_same<ScalarNumber, double>::value)
105 parameters.newton_tolerance = 1.e-10;
106 else
107 parameters.newton_tolerance = 1.e-4;
108 add_parameter("newton tolerance",
109 parameters.newton_tolerance,
110 "Tolerance for the quadratic newton stopping criterion");
111
112 parameters.newton_max_iterations = 2;
113 add_parameter("newton max iterations",
114 parameters.newton_max_iterations,
115 "Maximal number of quadratic newton iterations performed "
116 "during limiting");
117
118 parameters.relaxation_factor = 1.;
119 add_parameter("relaxation factor",
120 parameters.relaxation_factor,
121 "Factor for scaling the relaxation window with r_i = "
122 "factor * (m_i/|Omega|)^(1.5/d).");
123
124 /* invalidates view on default memory space */
125 ParameterAcceptor::parse_parameters_call_back.connect(
126 [this] { parameters_.view(); });
127 }
128
136 template <int dim,
137 typename Number,
138 typename MemorySpace = dealii::MemorySpace::Host>
139 auto view() const
140 {
142 hyperbolic_system_->template view<dim, Number, MemorySpace>(),
143 *this};
144 }
145
146 private:
148
152
153 Mirrored<Parameters> parameters_;
154
156
160
161 dealii::ObserverPointer<const HyperbolicSystem> hyperbolic_system_;
162
163 template <int, typename, typename>
164 friend class LimiterView;
165
167 };
168
169
178 template <int dim, typename Number, typename MemorySpace>
180 {
181 public:
182 static_assert(
183 std::is_same_v<MemorySpace, dealii::MemorySpace::Host> ||
184 std::is_same_v<MemorySpace, dealii::MemorySpace::Default>,
185 "Unexpected memory space");
186
191
193
195
196 using state_type = typename View::state_type;
197
199
201
203
205
212 static constexpr unsigned int n_bounds = 4;
213
217 using Bounds = std::array<Number, n_bounds>;
218
223 LimiterView(const View &view, const Limiter<ScalarNumber> &limiter)
224 : view_(view)
225 , parameters_(limiter.parameters_.template view<MemorySpace>())
226 {
227 }
228
232 DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int iterations() const
233 {
234 return parameters_->iterations;
235 }
236
240 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber newton_tolerance() const
241 {
242 return ScalarNumber(parameters_->newton_tolerance);
243 }
244
248 DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int
250 {
251 return parameters_->newton_max_iterations;
252 }
253
257 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber relaxation_factor() const
258 {
259 return ScalarNumber(parameters_->relaxation_factor);
260 }
261
266 DEAL_II_HOST_DEVICE Bounds
268 const unsigned int i,
269 const state_type &U_i) const;
270
276 DEAL_II_HOST_DEVICE Bounds combine_bounds(
277 const Bounds &bounds_left, const Bounds &bounds_right) const;
278
287 DEAL_II_HOST_DEVICE Bounds fully_relax_bounds(const Bounds &bounds,
288 const Number &hd) const;
289
291
310
314 DEAL_II_HOST_DEVICE void reset(const PrecomputedVectorView &pv,
315 const unsigned int i,
316 const state_type &U_i,
317 const flux_contribution_type &flux_i);
318
323 DEAL_II_HOST_DEVICE void
325 const unsigned int *js,
326 const state_type &U_j,
327 const flux_contribution_type &flux_j,
328 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
329 const state_type &affine_shift);
330
334 DEAL_II_HOST_DEVICE Bounds bounds(const Number hd_i) const;
335
337
341
357 DEAL_II_HOST_DEVICE std::tuple<Number, bool>
358 limit(const Bounds &bounds,
359 const state_type &U,
360 const state_type &P,
361 const Number t_min = Number(0.),
362 const Number t_max = Number(1.)) const;
363
364 private:
366
370
371 const View view_;
372 const Limiter<ScalarNumber>::Parameters *const parameters_;
373
374 state_type U_i_;
376
377 Bounds bounds_;
378
379 Number rho_relaxation_numerator_;
380 Number rho_relaxation_denominator_;
381 Number s_interp_max_;
382
384 };
385
386
387 /*
388 * -------------------------------------------------------------------------
389 * Inline definitions
390 * -------------------------------------------------------------------------
391 */
392
393
394 template <int dim, typename Number, typename MemorySpace>
395 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
397 const PrecomputedVectorView &pv,
398 const unsigned int i,
399 const state_type &U_i) const -> Bounds
400 {
401 const auto rho_i = view_.density(U_i);
402 const auto &[p_i, gamma_min_i, s_i, eta_i] =
403 pv.template read_tensor<Number, precomputed_type>(i);
404
405 return {/*rho_min*/ rho_i,
406 /*rho_max*/ rho_i,
407 /*s_min*/ s_i,
408 /*gamma_min*/ gamma_min_i};
409 }
410
411
412 template <int dim, typename Number, typename MemorySpace>
413 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
415 const Bounds &bounds_left, const Bounds &bounds_right) const -> Bounds
416 {
417 const auto &[rho_min_l, rho_max_l, s_min_l, gamma_min_l] = bounds_left;
418 const auto &[rho_min_r, rho_max_r, s_min_r, gamma_min_r] = bounds_right;
419
420 return {std::min(rho_min_l, rho_min_r),
421 std::max(rho_max_l, rho_max_r),
422 std::min(s_min_l, s_min_r),
423 std::min(gamma_min_l, gamma_min_r)};
424 }
425
426
427 template <int dim, typename Number, typename MemorySpace>
428 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
430 const Bounds &bounds, const Number &hd) const -> Bounds
431 {
432 const auto &[rho_min, rho_max, s_min, gamma_min] = bounds;
433
434 auto relaxed_bounds = bounds;
435 auto &[rho_min_relaxed, rho_max_relaxed, s_min_relaxed, g_m_relaxed] =
436 relaxed_bounds;
437
438 /* Use r = factor * (m_i / |Omega|) ^ (1.5 / d): */
439
440 Number r = std::sqrt(hd); // in 3D: ^ 3/6
441 if constexpr (dim == 2) //
442 r = dealii::Utilities::fixed_power<3>(std::sqrt(r)); // in 2D: ^ 3/4
443 else if constexpr (dim == 1) //
444 r = dealii::Utilities::fixed_power<3>(r); // in 1D: ^ 3/2
445 r *= relaxation_factor();
446
447 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
448 rho_min_relaxed *= std::max(Number(1.) - r, Number(eps));
449 rho_max_relaxed *= (Number(1.) + r);
450 s_min_relaxed *= std::max(Number(1.) - r, Number(eps));
451
452 /*
453 * If we have a maximum compressibility constant, b, the maximum
454 * bound for rho changes. See @cite ryujin-2023-4 for how to define
455 * rho_max.
456 */
457
458 const auto numerator = (gamma_min + Number(1.)) * rho_max;
459 const auto covolume_b = view_.eos_covolume_constant();
460 const auto denominator =
461 gamma_min - Number(1.) + ScalarNumber(2.) * covolume_b * rho_max;
462 const auto rho_compressibility_bound = numerator / denominator;
463
464 rho_max_relaxed = std::min(rho_compressibility_bound, rho_max_relaxed);
465
466 return relaxed_bounds;
467 }
468
469
470 template <int dim, typename Number, typename MemorySpace>
471 DEAL_II_HOST_DEVICE_ALWAYS_INLINE void
473 const PrecomputedVectorView &pv,
474 const unsigned int i,
475 const state_type &U_i,
476 const flux_contribution_type &flux_i)
477 {
478 U_i_ = U_i;
479 flux_i_ = flux_i;
480
481 /* Bounds: */
482
483 auto &[rho_min, rho_max, s_min, gamma_min] = bounds_;
484
485 rho_min = Number(std::numeric_limits<ScalarNumber>::max());
486 rho_max = Number(0.);
487 s_min = Number(std::numeric_limits<ScalarNumber>::max());
488
489 const auto &[p_i, gamma_min_i, s_i, eta_i] =
490 pv.template read_tensor<Number, precomputed_type>(i);
491
492 gamma_min = gamma_min_i;
493
494 /* Relaxation: */
495
496 rho_relaxation_numerator_ = Number(0.);
497 rho_relaxation_denominator_ = Number(0.);
498 s_interp_max_ = Number(0.);
499 }
500
501
502 template <int dim, typename Number, typename MemorySpace>
503 DEAL_II_HOST_DEVICE_ALWAYS_INLINE void
505 const PrecomputedVectorView &pv,
506 const unsigned int *js,
507 const state_type &U_j,
508 const flux_contribution_type &flux_j,
509 const dealii::Tensor<1, dim, Number> &scaled_c_ij,
510 const state_type &affine_shift)
511 {
512 // TODO: Currently we only apply the affine_shift to U_ij_bar (which
513 // then enters all bounds), but we do not modify s_interp and
514 // rho_relaxation. When actually adding a source term to the Euler
515 // equations verify that this does the right thing.
516 Assert(std::max(affine_shift.norm(), Number(0.)) == Number(0.),
517 dealii::ExcNotImplemented());
518
519 /* Bounds: */
520 auto &[rho_min, rho_max, s_min, gamma_min] = bounds_;
521
522 const auto rho_i = view_.density(U_i_);
523 const auto rho_j = view_.density(U_j);
524
525 /* bar state shifted by an affine shift: */
526 const auto U_ij_bar =
527 ScalarNumber(0.5) * (U_i_ + U_j) -
528 ScalarNumber(0.5) * contract(add(flux_j, -flux_i_), scaled_c_ij) +
529 affine_shift;
530
531 const auto rho_ij_bar = view_.density(U_ij_bar);
532
533 /* Density bounds: */
534
535 rho_min = std::min(rho_min, rho_ij_bar);
536 rho_max = std::max(rho_max, rho_ij_bar);
537
538 /* Density relaxation: */
539
540 /* Use a uniform weight. */
541 const auto beta_ij = Number(1.);
542 rho_relaxation_numerator_ += beta_ij * (rho_i + rho_j);
543 rho_relaxation_denominator_ += std::abs(beta_ij);
544
545 /* Surrogate entropy bounds and relaxation: */
546
547 if (view_.compute_strict_bounds()) {
548 /*
549 * Compute strict bounds precisely as outlined in @cite ryujin-2023-4
550 *
551 * This means, we compute
552 * - the surrogate entropy at dof j with the gamma_min of index i,
553 * - the surrogate entropy of the bar state U_ij_bar
554 * - an interpolated surrogate entropy at (U_i + U_j) / 2 for
555 * bounds relaxation:
556 */
557
558 const auto s_j = view_.surrogate_specific_entropy(U_j, gamma_min);
559
560 const auto s_ij_bar =
561 view_.surrogate_specific_entropy(U_ij_bar, gamma_min);
562
563 const Number s_interp = view_.surrogate_specific_entropy(
564 (U_i_ + U_j) * ScalarNumber(.5), gamma_min);
565
566 s_min = std::min(s_min, s_j);
567 s_min = std::min(s_min, s_ij_bar);
568 s_interp_max_ = std::max(s_interp_max_, s_interp);
569
570 } else {
571 /*
572 * Compute a cheaper bound solely relying on the diagonal s_j
573 * (computed with gamma_min_j) and the surrogate entropy s_ij_bar
574 * of the bar state. We use the s_ij_bar for computing the bounds
575 * relaxation as well.
576 */
577 const auto [p_j, gamma_min_j, s_j, eta_j] =
578 pv.template read_tensor<Number, precomputed_type>(js);
579
580 const auto s_ij_bar =
581 view_.surrogate_specific_entropy(U_ij_bar, gamma_min);
582
583 s_min = std::min(s_min, s_j);
584 s_min = std::min(s_min, s_ij_bar);
585 s_interp_max_ = std::max(s_interp_max_, s_ij_bar);
586 }
587 }
588
589
590 template <int dim, typename Number, typename MemorySpace>
591 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
593 -> Bounds
594 {
595 const auto &[rho_min, rho_max, s_min, gamma_min] = bounds_;
596
597 auto relaxed_bounds = fully_relax_bounds(bounds_, hd_i);
598 auto &[rho_min_relaxed, rho_max_relaxed, s_min_relaxed, g_m_relaxed] =
599 relaxed_bounds;
600
601 /* Apply a stricter window: */
602
603 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
604
605 const auto rho_relaxation =
606 ScalarNumber(2. * relaxation_factor()) *
607 std::abs(rho_relaxation_numerator_) /
608 (std::abs(rho_relaxation_denominator_) + Number(eps));
609
610 const auto entropy_relaxation =
611 relaxation_factor() * (s_interp_max_ - s_min);
612
613 rho_min_relaxed = std::max(rho_min_relaxed, rho_min - rho_relaxation);
614 rho_max_relaxed = std::min(rho_max_relaxed, rho_max + rho_relaxation);
615 s_min_relaxed = std::max(s_min_relaxed, s_min - entropy_relaxation);
616
617 return relaxed_bounds;
618 }
619
620
621 template <int dim, typename Number, typename MemorySpace>
622 DEAL_II_HOST_DEVICE_ALWAYS_INLINE std::tuple<Number, bool>
624 const Bounds &bounds,
625 const state_type &U,
626 const state_type &P,
627 const Number t_min /* = Number(0.) */,
628 const Number t_max /* = Number(1.) */) const
629 {
630 bool success = true;
631 Number t_r = t_max;
632
633 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
634 const auto small = view_.vacuum_state_relaxation_small();
635 const auto large = view_.vacuum_state_relaxation_large();
636 const ScalarNumber relax_small = ScalarNumber(1. + small * eps);
637 const ScalarNumber relax = ScalarNumber(1. + large * eps);
638
639 /*
640 * First limit the density rho.
641 *
642 * See [Guermond, Nazarov, Popov, Thomas] (4.8):
643 */
644
645 {
646 const auto &rho_U = view_.density(U);
647 const auto &rho_P = view_.density(P);
648
649 const auto &rho_min = std::get<0>(bounds);
650 const auto &rho_max = std::get<1>(bounds);
651
652 /*
653 * Verify that rho_U is within bounds. This property might be
654 * violated for relative CFL numbers larger than 1.
655 */
656 const auto test_min = view_.filter_vacuum_density(
657 std::max(Number(0.), rho_U - relax * rho_max));
658 const auto test_max = view_.filter_vacuum_density(
659 std::max(Number(0.), rho_min - relax * rho_U));
660 if (!(test_min == Number(0.) && test_max == Number(0.))) {
661#ifdef DEBUG_OUTPUT
662 std::cout << std::fixed << std::setprecision(16);
663 std::cout << "Bounds violation: low-order density (critical)!"
664 << "\n\t\trho min: " << rho_min
665 << "\n\t\trho min (delta): "
666 << negative_part(rho_U - rho_min)
667 << "\n\t\trho: " << rho_U
668 << "\n\t\trho max (delta): "
669 << positive_part(rho_U - rho_max)
670 << "\n\t\trho max: " << rho_max << "\n"
671 << std::endl;
672#endif
673 success = false;
674 }
675
676 const Number denominator =
677 ScalarNumber(1.) / (std::abs(rho_P) + eps * rho_max);
678
679 t_r = ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
680 rho_max,
681 rho_U + t_r * rho_P,
682 /*
683 * rho_P is positive.
684 *
685 * Note: Do not take an absolute value here. If we are out of
686 * bounds we have to ensure that t_r is set to t_min.
687 */
688 (rho_max - rho_U) * denominator,
689 t_r);
690
691 t_r = ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
692 rho_U + t_r * rho_P,
693 rho_min,
694 /*
695 * rho_P is negative.
696 *
697 * Note: Do not take an absolute value here. If we are out of
698 * bounds we have to ensure that t_r is set to t_min.
699 */
700 (rho_U - rho_min) * denominator,
701 t_r);
702
703 /*
704 * Ensure that t_min <= t <= t_max. This might not be the case if
705 * rho_U is outside the interval [rho_min, rho_max]. Furthermore,
706 * the quotient we take above is prone to numerical cancellation in
707 * particular in the second pass of the limiter when rho_P might be
708 * small.
709 */
710 t_r = std::min(t_r, t_max);
711 t_r = std::max(t_r, t_min);
712
713#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
714 /*
715 * Verify that the new state is within bounds:
716 */
717 const auto rho_new = view_.density(U + t_r * P);
718 const auto test_new_min = view_.filter_vacuum_density(
719 std::max(Number(0.), rho_new - relax * rho_max));
720 const auto test_new_max = view_.filter_vacuum_density(
721 std::max(Number(0.), rho_min - relax * rho_new));
722 if (!(test_new_min == Number(0.) && test_new_max == Number(0.))) {
723#ifdef DEBUG_OUTPUT
724 std::cout << std::fixed << std::setprecision(16);
725 std::cout << "Bounds violation: high-order density!"
726 << "\n\t\trho min: " << rho_min
727 << "\n\t\trho min (delta): "
728 << negative_part(rho_new - rho_min)
729 << "\n\t\trho: " << rho_new
730 << "\n\t\trho max (delta): "
731 << positive_part(rho_new - rho_max)
732 << "\n\t\trho max: " << rho_max << "\n"
733 << std::endl;
734#endif
735 success = false;
736 }
737#endif
738 }
739
740 /*
741 * Then limit the specific entropy:
742 *
743 * See [Guermond, Nazarov, Popov, Thomas],
744 * Section 4.6 + Section 5.1
745 * and @cite clayton2023robust Section 6:
746 */
747
748 Number t_l = t_min; // good state
749
750 const auto &gamma = std::get<3>(bounds) /* = gamma_min*/;
751 const Number gm1 = gamma - Number(1.);
752
753 const auto b = Number(view_.eos_covolume_constant());
754 const auto pinf = Number(view_.eos_interpolation_pinfty());
755 const auto q = Number(view_.eos_interpolation_q());
756
757 {
758 /*
759 * Prepare a quadratic Newton method:
760 *
761 * Given initial limiter values t_l and t_r with psi(t_l) > 0 and
762 * psi(t_r) < 0 we try to find t^\ast with psi(t^\ast) \approx 0.
763 *
764 * Here, psi is a 3-convex function obtained by scaling the specific
765 * entropy s:
766 *
767 * psi = \rho ^ {\gamma + 1} s
768 *
769 * (s in turn was defined as s =\varepsilon \rho ^{-\gamma}, where
770 * \varepsilon = (\rho e - pinf * (1 - b rho)) is the shifted
771 * internal energy.)
772 */
773
774 const auto &s_min = std::get<2>(bounds);
775
776#ifdef DEBUG_OUTPUT_LIMITER
777 std::cout << std::endl;
778 std::cout << std::fixed << std::setprecision(16);
779 std::cout << "t_l: (start) " << t_l << std::endl;
780 std::cout << "t_r: (start) " << t_r << std::endl;
781#endif
782
783 for (unsigned int n = 0; n < newton_max_iterations(); ++n) {
784
785 const auto U_r = U + t_r * P;
786 const auto rho_r = view_.density(U_r);
787 const auto rho_r_gamma = ryujin::pow(rho_r, gamma);
788 const auto covolume_r = Number(1.) - b * rho_r;
789
790 const auto rho_e_r = view_.internal_energy(U_r);
791 const auto shift_r = rho_e_r - rho_r * q - pinf * covolume_r;
792
793 auto psi_r =
794 relax_small * rho_r * shift_r -
795 s_min * rho_r * rho_r_gamma * ryujin::pow(covolume_r, -gm1);
796
797#ifndef DEBUG_EXPENSIVE_BOUNDS_CHECK
798 /*
799 * If psi_r > 0 the right state is fine, force returning t_r by
800 * setting t_l = t_r:
801 */
803 dealii::SIMDComparison::greater_than>(
804 psi_r, Number(0.), t_r, t_l);
805
806 /*
807 * If we have set t_l = t_r everywhere then all states state U_r
808 * with t_r obey the specific entropy inequality and we can
809 * break.
810 *
811 * This is a very important optimization: Only for 1 in (25 to
812 * 50) cases do we actually need to limit on the specific entropy
813 * because one of the right states failed. So we can skip
814 * constructing the left state U_l, which is expensive.
815 *
816 * This implies unfortunately that we might not accurately report
817 * whether the low_order update U itself obeyed bounds because
818 * U_r = U + t_r * P pushed us back into bounds. We thus skip
819 * this shortcut if `DEBUG_EXPENSIVE_BOUNDS_CHECK` is set.
820 */
821 if (t_l == t_r) {
822#ifdef DEBUG_OUTPUT_LIMITER
823 std::cout << "shortcut: t_l == t_r" << std::endl;
824 std::cout << "psi_l: " << psi_l << std::endl;
825 std::cout << "psi_r: " << psi_r << std::endl;
826 std::cout << "t_l: ( " << n << " ) " << t_l << std::endl;
827 std::cout << "t_r: ( " << n << " ) " << t_r << std::endl;
828#endif
829 break;
830 }
831#endif
832
833 const auto U_l = U + t_l * P;
834 const auto rho_l = view_.density(U_l);
835 const auto rho_l_gamma = ryujin::pow(rho_l, gamma);
836 const auto covolume_l = Number(1.) - b * rho_l;
837 const auto rho_e_l = view_.internal_energy(U_l);
838 const auto shift_l = rho_e_l - rho_l * q - pinf * covolume_l;
839
840 auto psi_l =
841 relax_small * rho_l * shift_l -
842 s_min * rho_l * rho_l_gamma * ryujin::pow(covolume_l, -gm1);
843
844 /*
845 * Verify that the left state is within bounds. This property might
846 * be violated for relative CFL numbers larger than 1.
847 */
848 const auto lower_bound = (ScalarNumber(1.) - relax) * s_min * rho_l *
849 rho_l_gamma * ryujin::pow(covolume_l, -gm1);
850 if (n == 0 &&
851 !(std::min(Number(0.), psi_l - lower_bound) == Number(0.))) {
852#ifdef DEBUG_OUTPUT
853 std::cout << std::fixed << std::setprecision(16);
854 std::cout
855 << "Bounds violation: low-order specific entropy (critical)!\n";
856 std::cout << "\t\tPsi left: 0 <= " << psi_l << "\n" << std::endl;
857#endif
858 success = false;
859 }
860
861#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
862 /*
863 * If psi_r > 0 the right state is fine, force returning t_r by
864 * setting t_l = t_r:
865 */
867 dealii::SIMDComparison::greater_than>(
868 psi_r, Number(0.), t_r, t_l);
869#endif
870
871 /*
872 * Break if the window between t_l and t_r is within the prescribed
873 * tolerance:
874 */
875 const Number tolerance(newton_tolerance());
876 if (std::max(Number(0.), t_r - t_l - tolerance) == Number(0.)) {
877#ifdef DEBUG_OUTPUT_LIMITER
878 std::cout << "break: t_l and t_r within tolerance" << std::endl;
879 std::cout << "psi_l: " << psi_l << std::endl;
880 std::cout << "psi_r: " << psi_r << std::endl;
881 std::cout << "t_l: ( " << n << " ) " << t_l << std::endl;
882 std::cout << "t_r: ( " << n << " ) " << t_r << std::endl;
883#endif
884 break;
885 }
886
887 /* We got unlucky and have to perform a Newton step: */
888
889 const auto drho = view_.density(P);
890 const auto drho_e_l = view_.internal_energy_derivative(U_l) * P;
891 const auto drho_e_r = view_.internal_energy_derivative(U_r) * P;
892
893 const auto q_pinf_term_l =
894 ScalarNumber(2.) * rho_l * q +
895 pinf * (Number(1.) - ScalarNumber(2.) * b * rho_l);
896 const auto q_pinf_term_r =
897 ScalarNumber(2.) * rho_r * q +
898 pinf * (Number(1.) - ScalarNumber(2.) * b * rho_r);
899
900 const auto extra_term_l = s_min *
901 ryujin::pow(rho_l / covolume_l, gamma) *
902 (covolume_l + gamma - b * rho_l);
903 const auto extra_term_r = s_min *
904 ryujin::pow(rho_r / covolume_r, gamma) *
905 (covolume_r + gamma - b * rho_r);
906
907 const auto dpsi_l = rho_l * drho_e_l +
908 (rho_e_l - q_pinf_term_l - extra_term_l) * drho;
909 const auto dpsi_r = rho_r * drho_e_r +
910 (rho_e_r - q_pinf_term_r - extra_term_r) * drho;
911
913 t_l, t_r, psi_l, psi_r, dpsi_l, dpsi_r, Number(-1.));
914
915#ifdef DEBUG_OUTPUT_LIMITER
916 std::cout << "psi_l: " << psi_l << std::endl;
917 std::cout << "psi_r: " << psi_r << std::endl;
918 std::cout << "dpsi_l: " << dpsi_l << std::endl;
919 std::cout << "dpsi_r: " << dpsi_r << std::endl;
920 std::cout << "t_l: ( " << n << " ) " << t_l << std::endl;
921 std::cout << "t_r: ( " << n << " ) " << t_r << std::endl;
922#endif
923 }
924
925#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
926 /*
927 * Verify that the new state is within bounds:
928 */
929 {
930 const auto U_new = U + t_l * P;
931
932 const auto rho_new = view_.density(U_new);
933 const auto covolume_new = Number(1.) - b * rho_new;
934
935 const auto rho_new_gamma = ryujin::pow(rho_new, gamma);
936 const auto rho_e_new = view_.internal_energy(U_new);
937
938 const auto shift_new = rho_e_new - rho_new * q - pinf * covolume_new;
939
940 const auto psi_new =
941 relax_small * rho_new * shift_new -
942 s_min * rho_new * rho_new_gamma * ryujin::pow(covolume_new, -gm1);
943
944 const auto lower_bound = (ScalarNumber(1.) - relax) * s_min *
945 rho_new * rho_new_gamma *
946 ryujin::pow(covolume_new, -gm1);
947
948 const bool e_valid = std::min(Number(0.), shift_new) == Number(0.);
949 const bool psi_valid =
950 std::min(Number(0.), psi_new - lower_bound) == Number(0.);
951
952 if (!e_valid || !psi_valid) {
953#ifdef DEBUG_OUTPUT
954 std::cout << std::fixed << std::setprecision(16);
955 std::cout << "Bounds violation: high-order specific entropy!\n";
956 std::cout << "\t\trho e: 0 <= " << rho_e_new << "\n";
957 std::cout << "\t\tPsi: 0 <= " << psi_new << "\n" << std::endl;
958#endif
959 success = false;
960 }
961 }
962#endif
963 }
964
965 return {t_l, success};
966 }
967 } // namespace EulerAEOS
968} // namespace ryujin
dealii::Tensor< 1, problem_dimension, Number > state_type
typename get_value_type< Number >::type ScalarNumber
VectorView< n_precomputed_values > PrecomputedVectorView
std::array< Number, n_precomputed_values > precomputed_type
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:472
typename View::PrecomputedVectorView PrecomputedVectorView
Definition limiter.h:202
DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int newton_max_iterations() const
Definition limiter.h:249
typename View::precomputed_type precomputed_type
Definition limiter.h:200
std::array< Number, n_bounds > Bounds
Definition limiter.h:217
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber relaxation_factor() const
Definition limiter.h:257
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:623
HyperbolicSystemView< dim, Number, MemorySpace > View
Definition limiter.h:192
typename View::state_type state_type
Definition limiter.h:196
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber newton_tolerance() const
Definition limiter.h:240
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:504
DEAL_II_HOST_DEVICE_ALWAYS_INLINE unsigned int iterations() const
Definition limiter.h:232
DEAL_II_HOST_DEVICE Bounds bounds(const Number hd_i) const
Definition limiter.h:592
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:396
typename View::flux_contribution_type flux_contribution_type
Definition limiter.h:198
DEAL_II_HOST_DEVICE Bounds combine_bounds(const Bounds &bounds_left, const Bounds &bounds_right) const
Definition limiter.h:414
LimiterView(const View &view, const Limiter< ScalarNumber > &limiter)
Definition limiter.h:223
static constexpr unsigned int n_bounds
Definition limiter.h:212
DEAL_II_HOST_DEVICE Bounds fully_relax_bounds(const Bounds &bounds, const Number &hd) const
Definition limiter.h:429
typename View::ScalarNumber ScalarNumber
Definition limiter.h:194
Limiter(const HyperbolicSystem &hyperbolic_system, const std::string &subsection="/Limiter")
Definition limiter.h:89
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 void quadratic_newton_step(Number &p_1, Number &p_2, const Number phi_p_1, const Number phi_p_2, const Number dphi_p_1, const Number dphi_p_2, const Number sign=Number(1.0))
Definition newton.h:39
DEAL_II_HOST_DEVICE_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)
DEAL_II_HOST_DEVICE T pow(const T x, const T b)
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 Number compare_and_apply_mask(const Number &left, const Number &right, const Number &true_value, const Number &false_value)
Definition simd.h:182