ryujin 2.1.1 revision ef0fcd4010d109b860652ece4a7b8963fb7d46b1
hyperbolic_system.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2020 - 2024 by the ryujin authors
4//
5
6#pragma once
7
8#include <compile_time_options.h>
9
10#include <convenience_macros.h>
11#include <discretization.h>
13#include <openmp.h>
14#include <patterns_conversion.h>
15#include <simd.h>
16#include <state_vector.h>
17
18#include <deal.II/base/parameter_acceptor.h>
19#include <deal.II/base/tensor.h>
20
21#include <array>
22
23namespace ryujin
24{
25 namespace Euler
26 {
27 template <int dim, typename Number>
28 class HyperbolicSystemView;
29
40 class HyperbolicSystem final : public dealii::ParameterAcceptor
41 {
42 public:
46 static inline const std::string problem_name =
47 "Compressible Euler equations (polytropic gas EOS, optimized)";
48
52 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
53
60 template <int dim, typename Number>
61 auto view() const
62 {
64 }
65
66 private:
71 double gamma_;
72
73 double reference_density_;
74 double vacuum_state_relaxation_small_;
75 double vacuum_state_relaxation_large_;
76
77 double gamma_inverse_;
78 double gamma_minus_one_inverse_;
79 double gamma_minus_one_over_gamma_plus_one_;
80 double gamma_plus_one_inverse_;
81
82 template <int dim, typename Number>
85 }; /* HyperbolicSystem */
86
87
104 template <int dim, typename Number>
106 {
107 public:
112 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
113 : hyperbolic_system_(hyperbolic_system)
114 {
115 }
116
120 template <int dim2, typename Number2>
121 auto view() const
122 {
123 return HyperbolicSystemView<dim2, Number2>{hyperbolic_system_};
124 }
125
130
135
136 DEAL_II_ALWAYS_INLINE inline ScalarNumber gamma() const
137 {
138 return hyperbolic_system_.gamma_;
139 }
140
141 DEAL_II_ALWAYS_INLINE inline ScalarNumber reference_density() const
142 {
143 return hyperbolic_system_.reference_density_;
144 }
145
146 DEAL_II_ALWAYS_INLINE inline ScalarNumber
148 {
149 return hyperbolic_system_.vacuum_state_relaxation_small_;
150 }
151
152 DEAL_II_ALWAYS_INLINE inline ScalarNumber
154 {
155 return hyperbolic_system_.vacuum_state_relaxation_large_;
156 }
157
159
167
168 DEAL_II_ALWAYS_INLINE inline ScalarNumber gamma_inverse() const
169 {
170 return ScalarNumber(hyperbolic_system_.gamma_inverse_);
171 }
172
173 DEAL_II_ALWAYS_INLINE inline ScalarNumber gamma_plus_one_inverse() const
174 {
175 return ScalarNumber(hyperbolic_system_.gamma_plus_one_inverse_);
176 }
177
178 DEAL_II_ALWAYS_INLINE inline ScalarNumber gamma_minus_one_inverse() const
179 {
180 return ScalarNumber(hyperbolic_system_.gamma_minus_one_inverse_);
181 }
182
183 DEAL_II_ALWAYS_INLINE inline ScalarNumber
185 {
186 return ScalarNumber(
187 hyperbolic_system_.gamma_minus_one_over_gamma_plus_one_);
188 }
189
193 static constexpr bool have_gamma = true;
194
198 static constexpr bool have_eos_interpolation_b = false;
199
201
205
206 private:
207 const HyperbolicSystem &hyperbolic_system_;
208
209 public:
211
215
219 static constexpr unsigned int problem_dimension = 2 + dim;
220
224 using state_type = dealii::Tensor<1, problem_dimension, Number>;
225
229 using flux_type =
230 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
231
236
241 static inline const auto component_names =
242 []() -> std::array<std::string, problem_dimension> {
243 if constexpr (dim == 1)
244 return {"rho", "m", "E"};
245 else if constexpr (dim == 2)
246 return {"rho", "m_1", "m_2", "E"};
247 else if constexpr (dim == 3)
248 return {"rho", "m_1", "m_2", "m_3", "E"};
249 __builtin_trap();
250 }();
251
256 static inline const auto primitive_component_names =
257 []() -> std::array<std::string, problem_dimension> {
258 if constexpr (dim == 1)
259 return {"rho", "v", "p"};
260 else if constexpr (dim == 2)
261 return {"rho", "v_1", "v_2", "p"};
262 else if constexpr (dim == 3)
263 return {"rho", "v_1", "v_2", "v_3", "p"};
264 __builtin_trap();
265 }();
266
270 static constexpr unsigned int n_precomputed_values = 2;
271
275 using precomputed_type = std::array<Number, n_precomputed_values>;
276
280 static inline const auto precomputed_names =
281 std::array<std::string, n_precomputed_values>{"s", "eta_h"};
282
286 static constexpr unsigned int n_initial_precomputed_values = 0;
287
292 std::array<Number, n_initial_precomputed_values>;
293
297 static inline const auto initial_precomputed_names =
298 std::array<std::string, n_initial_precomputed_values>{};
299
303 using StateVector = Vectors::
304 StateVector<ScalarNumber, problem_dimension, n_precomputed_values>;
305
311
317
325
327
331
335 static constexpr unsigned int n_precomputation_cycles = 1;
336
341 template <typename DISPATCH, typename SPARSITY>
342 void precomputation_loop(unsigned int cycle,
343 const DISPATCH &dispatch_check,
344 const SPARSITY &sparsity_simd,
345 StateVector &state_vector,
346 unsigned int left,
347 unsigned int right,
348 const bool skip_constrained_dofs = true) const;
349
351
355
360 static Number density(const state_type &U);
361
368 Number filter_vacuum_density(const Number &rho) const;
369
374 static dealii::Tensor<1, dim, Number> momentum(const state_type &U);
375
380 static Number total_energy(const state_type &U);
381
386 static Number internal_energy(const state_type &U);
387
394
405 Number pressure(const state_type &U) const;
406
414 Number speed_of_sound(const state_type &U) const;
415
423 Number specific_entropy(const state_type &U) const;
424
432 Number harten_entropy(const state_type &U) const;
433
442
447 Number mathematical_entropy(const state_type &U) const;
448
455
461 bool is_admissible(const state_type &U) const;
462
464
468
474 template <int component>
475 std::array<state_type, 2> linearized_eigenvector(
476 const state_type &U,
477 const dealii::Tensor<1, dim, Number> &normal) const;
478
485 template <int component>
487 const state_type &U,
488 const state_type &U_bar,
489 const dealii::Tensor<1, dim, Number> &normal) const;
490
509 template <typename Lambda>
511 apply_boundary_conditions(const dealii::types::boundary_id id,
512 const state_type &U,
513 const dealii::Tensor<1, dim, Number> &normal,
514 const Lambda &get_dirichlet_data) const;
515
517
521
532 flux_type f(const state_type &U) const;
533
555 const InitialPrecomputedVector &ipv,
556 const unsigned int i,
557 const state_type &U_i) const;
558
561 const InitialPrecomputedVector &ipv,
562 const unsigned int *js,
563 const state_type &U_j) const;
564
571 const flux_contribution_type &flux_j,
572 const dealii::Tensor<1, dim, Number> &c_ij) const;
573
575 static constexpr bool have_high_order_flux = false;
576
578 const flux_contribution_type &flux_i,
579 const flux_contribution_type &flux_j,
580 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
581
583
587
589 static constexpr bool have_source_terms = false;
590
592 const unsigned int i,
593 const state_type &U_i,
594 const ScalarNumber tau) const = delete;
595
597 const unsigned int *js,
598 const state_type &U_j,
599 const ScalarNumber tau) const = delete;
600
602
606
617 template <typename ST>
618 state_type expand_state(const ST &state) const;
619
633 template <typename ST>
634 state_type from_initial_state(const ST &initial_state) const;
635
640 state_type from_primitive_state(const state_type &primitive_state) const;
641
646 state_type to_primitive_state(const state_type &state) const;
647
653 template <typename Lambda>
655 const Lambda &lambda) const;
657 }; /* HyperbolicSystemView */
658
659
660 /*
661 * -------------------------------------------------------------------------
662 * Inline definitions
663 * -------------------------------------------------------------------------
664 */
665
666
667 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
668 : ParameterAcceptor(subsection)
669 {
670 gamma_ = 7. / 5.;
671 add_parameter("gamma", gamma_, "The ratio of specific heats");
672
673 reference_density_ = 1.;
674 add_parameter("reference density",
675 reference_density_,
676 "Problem specific density reference");
677
678 vacuum_state_relaxation_small_ = 1.e2;
679 add_parameter("vacuum state relaxation small",
680 vacuum_state_relaxation_small_,
681 "Problem specific vacuum relaxation parameter");
682
683 vacuum_state_relaxation_large_ = 1.e4;
684 add_parameter("vacuum state relaxation large",
685 vacuum_state_relaxation_large_,
686 "Problem specific vacuum relaxation parameter");
687
688 /*
689 * Precompute a number of derived gamma coefficients that contain
690 * divisions:
691 */
692 const auto compute_inverses = [this] {
693 gamma_inverse_ = 1. / gamma_;
694 gamma_plus_one_inverse_ = 1. / (gamma_ + 1.);
695 gamma_minus_one_inverse_ = 1. / (gamma_ - 1.);
696 gamma_minus_one_over_gamma_plus_one_ = (gamma_ - 1.) / (gamma_ + 1.);
697 };
698
699 compute_inverses();
700 ParameterAcceptor::parse_parameters_call_back.connect(compute_inverses);
701 }
702
703
704 template <int dim, typename Number>
705 template <typename DISPATCH, typename SPARSITY>
706 DEAL_II_ALWAYS_INLINE inline void
708 unsigned int cycle [[maybe_unused]],
709 const DISPATCH &dispatch_check,
710 const SPARSITY &sparsity_simd,
711 StateVector &state_vector,
712 unsigned int left,
713 unsigned int right,
714 const bool skip_constrained_dofs /*= true*/) const
715 {
716 Assert(cycle == 0, dealii::ExcInternalError());
717
718 const auto &U = std::get<0>(state_vector);
719 auto &precomputed = std::get<1>(state_vector);
720
721 /* We are inside a thread parallel context */
722
723 unsigned int stride_size = get_stride_size<Number>;
724
726 for (unsigned int i = left; i < right; i += stride_size) {
727
728 /* Skip constrained degrees of freedom: */
729 const unsigned int row_length = sparsity_simd.row_length(i);
730 if (skip_constrained_dofs && row_length == 1)
731 continue;
732
733 dispatch_check(i);
734
735 const auto U_i = U.template get_tensor<Number>(i);
736 const precomputed_type prec_i{specific_entropy(U_i),
737 harten_entropy(U_i)};
738 precomputed.template write_tensor<Number>(prec_i, i);
739 }
740 }
741
742
743 template <int dim, typename Number>
744 DEAL_II_ALWAYS_INLINE inline Number
746 {
747 return U[0];
748 }
749
750
751 template <int dim, typename Number>
752 DEAL_II_ALWAYS_INLINE inline Number
754 const Number &rho) const
755 {
756 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
757 const Number rho_cutoff_large =
758 reference_density() * vacuum_state_relaxation_large() * eps;
759
760 return dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
761 std::abs(rho), rho_cutoff_large, Number(0.), rho);
762 }
763
764
765 template <int dim, typename Number>
766 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
768 {
769 dealii::Tensor<1, dim, Number> result;
770 for (unsigned int i = 0; i < dim; ++i)
771 result[i] = U[1 + i];
772 return result;
773 }
774
775
776 template <int dim, typename Number>
777 DEAL_II_ALWAYS_INLINE inline Number
779 {
780 return U[1 + dim];
781 }
782
783
784 template <int dim, typename Number>
785 DEAL_II_ALWAYS_INLINE inline Number
787 {
788 /*
789 * rho e = (E - 1/2*m^2/rho)
790 */
791 const Number rho_inverse = ScalarNumber(1.) / density(U);
792 const auto m = momentum(U);
793 const Number E = total_energy(U);
794 return E - ScalarNumber(0.5) * m.norm_square() * rho_inverse;
795 }
796
797
798 template <int dim, typename Number>
799 DEAL_II_ALWAYS_INLINE inline auto
801 const state_type &U) -> state_type
802 {
803 /*
804 * With
805 * rho e = E - 1/2 |m|^2 / rho
806 * we get
807 * (rho e)' = (1/2m^2/rho^2, -m/rho , 1 )^T
808 */
809
810 const Number rho_inverse = ScalarNumber(1.) / density(U);
811 const auto u = momentum(U) * rho_inverse;
812
813 state_type result;
814
815 result[0] = ScalarNumber(0.5) * u.norm_square();
816 for (unsigned int i = 0; i < dim; ++i) {
817 result[1 + i] = -u[i];
818 }
819 result[dim + 1] = ScalarNumber(1.);
820
821 return result;
822 }
823
824
825 template <int dim, typename Number>
826 DEAL_II_ALWAYS_INLINE inline Number
828 {
829 /* p = (gamma - 1) * (rho e) */
830 return (gamma() - ScalarNumber(1.)) * internal_energy(U);
831 }
832
833
834 template <int dim, typename Number>
835 DEAL_II_ALWAYS_INLINE inline Number
837 {
838 /* c^2 = gamma * p / rho */
839 const Number rho_inverse = ScalarNumber(1.) / density(U);
840 const Number p = pressure(U);
841 return std::sqrt(gamma() * p * rho_inverse);
842 }
843
844
845 template <int dim, typename Number>
846 DEAL_II_ALWAYS_INLINE inline Number
848 const state_type &U) const
849 {
850 /* exp((gamma - 1)s) = (rho e) / rho ^ gamma */
851 const auto rho_inverse = ScalarNumber(1.) / density(U);
852 return internal_energy(U) * ryujin::pow(rho_inverse, gamma());
853 }
854
855
856 template <int dim, typename Number>
857 DEAL_II_ALWAYS_INLINE inline Number
859 {
860 /* rho^2 e = \rho E - 1/2*m^2 */
861
862 const Number rho = density(U);
863 const auto m = momentum(U);
864 const Number E = total_energy(U);
865
866 const Number rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
867 return ryujin::pow(rho_rho_e, gamma_plus_one_inverse());
868 }
869
870
871 template <int dim, typename Number>
872 DEAL_II_ALWAYS_INLINE inline auto
874 const state_type &U) const -> state_type
875 {
876 /*
877 * With
878 * eta = (rho^2 e) ^ 1/(gamma+1)
879 * rho^2 e = rho * E - 1/2 |m|^2
880 *
881 * we get
882 *
883 * eta' = 1/(gamma+1) * (rho^2 e) ^ -gamma/(gamma+1) * (E,-m,rho)^T
884 *
885 */
886
887 const Number rho = density(U);
888 const auto m = momentum(U);
889 const Number E = total_energy(U);
890
891 const Number rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
892
893 const auto factor =
894 gamma_plus_one_inverse() *
895 ryujin::pow(rho_rho_e, -gamma() * gamma_plus_one_inverse());
896
897 state_type result;
898
899 result[0] = factor * E;
900 for (unsigned int i = 0; i < dim; ++i)
901 result[1 + i] = -factor * m[i];
902 result[dim + 1] = factor * rho;
903
904 return result;
905 }
906
907
908 template <int dim, typename Number>
909 DEAL_II_ALWAYS_INLINE inline Number
911 const state_type &U) const
912 {
914 const auto p = pressure(U);
915 return ryujin::pow(p, gamma_inverse());
916 }
917
918
919 template <int dim, typename Number>
920 DEAL_II_ALWAYS_INLINE inline auto
922 const state_type &U) const -> state_type
923 {
924 /*
925 * With
926 * eta = p ^ (1/gamma)
927 * p = (gamma - 1) * (rho e)
928 * rho e = E - 1/2 |m|^2 / rho
929 *
930 * we get
931 *
932 * eta' = (gamma - 1)/gamma p ^(1/gamma - 1) *
933 *
934 * (1/2m^2/rho^2 , -m/rho , 1 )^T
935 */
936 const Number rho = density(U);
937 const Number rho_inverse = ScalarNumber(1.) / rho;
938 const auto u = momentum(U) * rho_inverse;
939 const auto p = pressure(U);
940
941 const auto factor = (gamma() - ScalarNumber(1.0)) * gamma_inverse() *
942 ryujin::pow(p, gamma_inverse() - ScalarNumber(1.));
943
944 state_type result;
945
946 result[0] = factor * ScalarNumber(0.5) * u.norm_square();
947 result[dim + 1] = factor;
948 for (unsigned int i = 0; i < dim; ++i) {
949 result[1 + i] = -factor * u[i];
950 }
951
952 return result;
953 }
954
955
956 template <int dim, typename Number>
957 DEAL_II_ALWAYS_INLINE inline bool
959 {
960 const auto rho_new = density(U);
961 const auto e_new = internal_energy(U);
962 const auto s_new = specific_entropy(U);
963
964 constexpr auto gt = dealii::SIMDComparison::greater_than;
965 using T = Number;
966 const auto test =
967 dealii::compare_and_apply_mask<gt>(rho_new, T(0.), T(0.), T(-1.)) + //
968 dealii::compare_and_apply_mask<gt>(e_new, T(0.), T(0.), T(-1.)) + //
969 dealii::compare_and_apply_mask<gt>(s_new, T(0.), T(0.), T(-1.));
970
971#ifdef DEBUG_OUTPUT
972 if (!(test == Number(0.))) {
973 std::cout << std::fixed << std::setprecision(16);
974 std::cout << "Bounds violation: Negative state [rho, e, s] detected!\n";
975 std::cout << "\t\trho: " << rho_new << "\n";
976 std::cout << "\t\tint: " << e_new << "\n";
977 std::cout << "\t\tent: " << s_new << "\n" << std::endl;
978 }
979#endif
980
981 return (test == Number(0.));
982 }
983
984
985 template <int dim, typename Number>
986 template <int component>
987 DEAL_II_ALWAYS_INLINE inline auto
989 const state_type &U, const dealii::Tensor<1, dim, Number> &normal) const
990 -> std::array<state_type, 2>
991 {
992 static_assert(component == 1 || component == problem_dimension,
993 "Only first and last eigenvectors implemented");
994
995 const auto rho = density(U);
996 const auto m = momentum(U);
997 const auto v = m / rho;
998 const auto a = speed_of_sound(U);
999 const auto gamma = this->gamma();
1000
1001 state_type b;
1002 state_type c;
1003
1004 const auto e_k = 0.5 * v.norm_square();
1005
1006 switch (component) {
1007 case 1:
1008 b[0] = (gamma - 1.) * e_k + a * v * normal;
1009 for (unsigned int i = 0; i < dim; ++i)
1010 b[1 + i] = (1. - gamma) * v[i] - a * normal[i];
1011 b[dim + 1] = gamma - 1.;
1012 b /= 2. * a * a;
1013
1014 c[0] = 1.;
1015 for (unsigned int i = 0; i < dim; ++i)
1016 c[1 + i] = v[i] - a * normal[i];
1017 c[dim + 1] = a * a / (gamma - 1) + e_k - a * (v * normal);
1018
1019 return {b, c};
1020
1021 case problem_dimension:
1022 b[0] = (gamma - 1.) * e_k - a * v * normal;
1023 for (unsigned int i = 0; i < dim; ++i)
1024 b[1 + i] = (1. - gamma) * v[i] + a * normal[i];
1025 b[dim + 1] = gamma - 1.;
1026 b /= 2. * a * a;
1027
1028 c[0] = 1.;
1029 for (unsigned int i = 0; i < dim; ++i)
1030 c[1 + i] = v[i] + a * normal[i];
1031 c[dim + 1] = a * a / (gamma - 1) + e_k + a * (v * normal);
1032
1033 return {b, c};
1034 }
1035
1036 __builtin_unreachable();
1037 }
1038
1039
1040 template <int dim, typename Number>
1041 template <int component>
1042 DEAL_II_ALWAYS_INLINE inline auto
1044 const state_type &U,
1045 const state_type &U_bar,
1046 const dealii::Tensor<1, dim, Number> &normal) const -> state_type
1047 {
1048 static_assert(component == 1 || component == 2,
1049 "component has to be 1 or 2");
1050
1051 const auto m = momentum(U);
1052 const auto rho = density(U);
1053 const auto a = speed_of_sound(U);
1054 const auto vn = m * normal / rho;
1055
1056 const auto m_bar = momentum(U_bar);
1057 const auto rho_bar = density(U_bar);
1058 const auto a_bar = speed_of_sound(U_bar);
1059 const auto vn_bar = m_bar * normal / rho_bar;
1060
1061 /* First Riemann characteristic: v* n - 2 / (gamma - 1) * a */
1062
1063 const auto R_1 = component == 1
1064 ? vn_bar - 2. * a_bar / (gamma() - ScalarNumber(1.))
1065 : vn - 2. * a / (gamma() - ScalarNumber(1.));
1066
1067 /* Second Riemann characteristic: v* n + 2 / (gamma() - 1) * a */
1068
1069 const auto R_2 = component == 2
1070 ? vn_bar + 2. * a_bar / (gamma() - ScalarNumber(1.))
1071 : vn + 2. * a / (gamma() - ScalarNumber(1.));
1072
1073 const auto p = pressure(U);
1074 const auto s = p / ryujin::pow(rho, gamma());
1075
1076 const auto vperp = m / rho - vn * normal;
1077
1078 const auto vn_new = 0.5 * (R_1 + R_2);
1079
1080 auto rho_new = 1. / (gamma() * s) *
1081 ryujin::fixed_power<2>(ScalarNumber((gamma() - 1.) / 4.) *
1082 (R_2 - R_1));
1083 rho_new = ryujin::pow(rho_new, 1. / (gamma() - 1.));
1084
1085 const auto p_new = s * std::pow(rho_new, gamma());
1086
1087 state_type U_new;
1088 U_new[0] = rho_new;
1089 for (unsigned int d = 0; d < dim; ++d) {
1090 U_new[1 + d] = rho_new * (vn_new * normal + vperp)[d];
1091 }
1092 U_new[1 + dim] = p_new / ScalarNumber(gamma() - 1.) +
1093 0.5 * rho_new * (vn_new * vn_new + vperp.norm_square());
1094
1095 return U_new;
1096 }
1097
1098
1099 template <int dim, typename Number>
1100 template <typename Lambda>
1101 DEAL_II_ALWAYS_INLINE inline auto
1103 dealii::types::boundary_id id,
1104 const state_type &U,
1105 const dealii::Tensor<1, dim, Number> &normal,
1106 const Lambda &get_dirichlet_data) const -> state_type
1107 {
1108 state_type result = U;
1109
1110 if (id == Boundary::dirichlet) {
1111 result = get_dirichlet_data();
1112
1113 } else if (id == Boundary::dirichlet_momentum) {
1114 /* Only enforce Dirichlet conditions on the momentum: */
1115 auto m_dirichlet = momentum(get_dirichlet_data());
1116 for (unsigned int k = 0; k < dim; ++k)
1117 result[k + 1] = m_dirichlet[k];
1118
1119 } else if (id == Boundary::slip) {
1120 auto m = momentum(U);
1121 m -= 1. * (m * normal) * normal;
1122 for (unsigned int k = 0; k < dim; ++k)
1123 result[k + 1] = m[k];
1124
1125 } else if (id == Boundary::no_slip) {
1126 for (unsigned int k = 0; k < dim; ++k)
1127 result[k + 1] = Number(0.);
1128
1129 } else if (id == Boundary::dynamic) {
1130 /*
1131 * On dynamic boundary conditions, we distinguish four cases:
1132 *
1133 * - supersonic inflow: prescribe full state
1134 * - subsonic inflow:
1135 * decompose into Riemann invariants and leave R_2
1136 * characteristic untouched.
1137 * - supersonic outflow: do nothing
1138 * - subsonic outflow:
1139 * decompose into Riemann invariants and prescribe incoming
1140 * R_1 characteristic.
1141 */
1142 const auto m = momentum(U);
1143 const auto rho = density(U);
1144 const auto a = speed_of_sound(U);
1145 const auto vn = m * normal / rho;
1146
1147 /* Supersonic inflow: */
1148 if (vn < -a) {
1149 result = get_dirichlet_data();
1150 }
1151
1152 /* Subsonic inflow: */
1153 if (vn >= -a && vn <= 0.) {
1154 const auto U_dirichlet = get_dirichlet_data();
1155 result = prescribe_riemann_characteristic<2>(U_dirichlet, U, normal);
1156 }
1157
1158 /* Subsonic outflow: */
1159 if (vn > 0. && vn <= a) {
1160 const auto U_dirichlet = get_dirichlet_data();
1161 result = prescribe_riemann_characteristic<1>(U, U_dirichlet, normal);
1162 }
1163
1164 /* Supersonic outflow: do nothing, i.e., keep U as is */
1165
1166 } else {
1167 AssertThrow(false, dealii::ExcNotImplemented());
1168 }
1169
1170 return result;
1171 }
1172
1173
1174 template <int dim, typename Number>
1175 DEAL_II_ALWAYS_INLINE inline auto
1177 {
1178 const auto rho_inverse = ScalarNumber(1.) / density(U);
1179 const auto m = momentum(U);
1180 const auto p = pressure(U);
1181 const auto E = total_energy(U);
1182
1183 flux_type result;
1184
1185 result[0] = m;
1186 for (unsigned int i = 0; i < dim; ++i) {
1187 result[1 + i] = m * (m[i] * rho_inverse);
1188 result[1 + i][i] += p;
1189 }
1190 result[dim + 1] = m * (rho_inverse * (E + p));
1191
1192 return result;
1193 }
1194
1195
1196 template <int dim, typename Number>
1197 DEAL_II_ALWAYS_INLINE inline auto
1199 const PrecomputedVector & /*pv*/,
1200 const InitialPrecomputedVector & /*ipv*/,
1201 const unsigned int /*i*/,
1202 const state_type &U_i) const -> flux_contribution_type
1203 {
1204 return f(U_i);
1205 }
1206
1207
1208 template <int dim, typename Number>
1209 DEAL_II_ALWAYS_INLINE inline auto
1211 const PrecomputedVector & /*pv*/,
1212 const InitialPrecomputedVector & /*ipv*/,
1213 const unsigned int * /*js*/,
1214 const state_type &U_j) const -> flux_contribution_type
1215 {
1216 return f(U_j);
1217 }
1218
1219
1220 template <int dim, typename Number>
1221 DEAL_II_ALWAYS_INLINE inline auto
1223 const flux_contribution_type &flux_i,
1224 const flux_contribution_type &flux_j,
1225 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
1226 {
1227 return -contract(add(flux_i, flux_j), c_ij);
1228 }
1229
1230
1231 template <int dim, typename Number>
1232 template <typename ST>
1234 -> state_type
1235 {
1236 using T = typename ST::value_type;
1237 static_assert(std::is_same_v<Number, T>, "template mismatch");
1238
1239 constexpr auto dim2 = ST::dimension - 2;
1240 static_assert(dim >= dim2,
1241 "the space dimension of the argument state must not be "
1242 "larger than the one of the target state");
1243
1244 state_type result;
1245 result[0] = state[0];
1246 result[dim + 1] = state[dim2 + 1];
1247 for (unsigned int i = 1; i < dim2 + 1; ++i)
1248 result[i] = state[i];
1249
1250 return result;
1251 }
1252
1253
1254 template <int dim, typename Number>
1255 template <typename ST>
1256 DEAL_II_ALWAYS_INLINE inline auto
1258 const ST &initial_state) const -> state_type
1259 {
1260 const auto primitive_state = expand_state(initial_state);
1261 return from_primitive_state(primitive_state);
1262 }
1263
1264
1265 template <int dim, typename Number>
1266 DEAL_II_ALWAYS_INLINE inline auto
1268 const state_type &primitive_state) const -> state_type
1269 {
1270 const auto &rho = primitive_state[0];
1271 /* extract velocity: */
1272 const auto u = /*SIC!*/ momentum(primitive_state);
1273 const auto &p = primitive_state[dim + 1];
1274
1275 auto state = primitive_state;
1276 /* Fix up momentum: */
1277 for (unsigned int i = 1; i < dim + 1; ++i)
1278 state[i] *= rho;
1279 /* Compute total energy: */
1280 state[dim + 1] =
1281 p / (ScalarNumber(gamma() - 1.)) + Number(0.5) * rho * u * u;
1282
1283 return state;
1284 }
1285
1286
1287 template <int dim, typename Number>
1288 DEAL_II_ALWAYS_INLINE inline auto
1290 const state_type &state) const -> state_type
1291 {
1292 const auto &rho = state[0];
1293 const auto rho_inverse = Number(1.) / rho;
1294 const auto p = pressure(state);
1295
1296 auto primitive_state = state;
1297 /* Fix up velocity: */
1298 for (unsigned int i = 1; i < dim + 1; ++i)
1299 primitive_state[i] *= rho_inverse;
1300 /* Set pressure: */
1301 primitive_state[dim + 1] = p;
1302
1303 return primitive_state;
1304 }
1305
1306
1307 template <int dim, typename Number>
1308 template <typename Lambda>
1310 const state_type &state, const Lambda &lambda) const -> state_type
1311 {
1312 auto result = state;
1313 const auto M = lambda(momentum(state));
1314 for (unsigned int d = 0; d < dim; ++d)
1315 result[1 + d] = M[d];
1316 return result;
1317 }
1318
1319 } // namespace Euler
1320} // namespace ryujin
typename get_value_type< Number >::type ScalarNumber
static constexpr unsigned int n_initial_precomputed_values
static constexpr bool have_eos_interpolation_b
state_type from_initial_state(const ST &initial_state) const
static Number internal_energy(const state_type &U)
state_type from_primitive_state(const state_type &primitive_state) const
dealii::Tensor< 1, problem_dimension, dealii::Tensor< 1, dim, Number > > flux_type
Number harten_entropy(const state_type &U) const
flux_contribution_type flux_contribution(const PrecomputedVector &pv, const InitialPrecomputedVector &ipv, const unsigned int i, const state_type &U_i) const
state_type high_order_flux_divergence(const flux_contribution_type &flux_i, const flux_contribution_type &flux_j, const dealii::Tensor< 1, dim, Number > &c_ij) const =delete
DEAL_II_ALWAYS_INLINE ScalarNumber reference_density() const
state_type harten_entropy_derivative(const state_type &U) const
static constexpr unsigned int n_precomputation_cycles
static constexpr bool have_high_order_flux
state_type nodal_source(const PrecomputedVector &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
state_type expand_state(const ST &state) const
HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
static constexpr unsigned int problem_dimension
dealii::Tensor< 1, problem_dimension, Number > state_type
flux_type f(const state_type &U) const
static constexpr unsigned int n_precomputed_values
state_type nodal_source(const PrecomputedVector &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const =delete
std::array< Number, n_precomputed_values > precomputed_type
std::array< Number, n_initial_precomputed_values > initial_precomputed_type
state_type prescribe_riemann_characteristic(const state_type &U, const state_type &U_bar, const dealii::Tensor< 1, dim, Number > &normal) const
Number pressure(const state_type &U) const
state_type apply_galilei_transform(const state_type &state, const Lambda &lambda) const
Number mathematical_entropy(const state_type &U) const
DEAL_II_ALWAYS_INLINE ScalarNumber gamma_inverse() const
DEAL_II_ALWAYS_INLINE ScalarNumber gamma() const
static Number total_energy(const state_type &U)
DEAL_II_ALWAYS_INLINE ScalarNumber vacuum_state_relaxation_small() const
void precomputation_loop(unsigned int cycle, const DISPATCH &dispatch_check, const SPARSITY &sparsity_simd, StateVector &state_vector, unsigned int left, unsigned int right, const bool skip_constrained_dofs=true) const
DEAL_II_ALWAYS_INLINE ScalarNumber gamma_minus_one_inverse() const
DEAL_II_ALWAYS_INLINE ScalarNumber gamma_plus_one_inverse() const
static Number density(const state_type &U)
Number filter_vacuum_density(const Number &rho) const
DEAL_II_ALWAYS_INLINE ScalarNumber vacuum_state_relaxation_large() const
Vectors::StateVector< ScalarNumber, problem_dimension, n_precomputed_values > StateVector
static state_type internal_energy_derivative(const state_type &U)
state_type flux_divergence(const flux_contribution_type &flux_i, const flux_contribution_type &flux_j, const dealii::Tensor< 1, dim, Number > &c_ij) const
std::array< state_type, 2 > linearized_eigenvector(const state_type &U, const dealii::Tensor< 1, dim, Number > &normal) const
DEAL_II_ALWAYS_INLINE ScalarNumber gamma_minus_one_over_gamma_plus_one() const
state_type mathematical_entropy_derivative(const state_type &U) const
state_type apply_boundary_conditions(const dealii::types::boundary_id id, const state_type &U, const dealii::Tensor< 1, dim, Number > &normal, const Lambda &get_dirichlet_data) const
state_type to_primitive_state(const state_type &state) const
static dealii::Tensor< 1, dim, Number > momentum(const state_type &U)
Number speed_of_sound(const state_type &U) const
bool is_admissible(const state_type &U) const
Number specific_entropy(const state_type &U) const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
static const std::string problem_name
@ dirichlet_momentum
#define RYUJIN_OMP_FOR
Definition: openmp.h:70
T pow(const T x, const T b)
DEAL_II_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, problem_dim, T > contract(const FT &flux_ij, const TT &c_ij)