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