ryujin 2.1.1 revision a15074459a388761bd8df6bd4ef7e6abe9d8077b
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
9
10#include <compile_time_options.h>
11#include <convenience_macros.h>
12#include <discretization.h>
14#include <openmp.h>
15#include <patterns_conversion.h>
16#include <simd.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 EulerAEOS
26 {
27 template <int dim, typename Number>
28 class HyperbolicSystemView;
29
41 class HyperbolicSystem final : public dealii::ParameterAcceptor
42 {
43 public:
47 static inline std::string problem_name =
48 "Compressible Euler equations (arbitrary EOS)";
49
53 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
54
61 template <int dim, typename Number>
62 auto view() const
63 {
65 }
66
67 private:
72
73 std::string equation_of_state_;
74 double reference_density_;
75 double vacuum_state_relaxation_small_;
76 double vacuum_state_relaxation_large_;
77 bool compute_strict_bounds_;
78
80 equation_of_state_list_;
81
82 using EquationOfState = EquationOfStateLibrary::EquationOfState;
83 std::shared_ptr<EquationOfState> selected_equation_of_state_;
84
85 template <int dim, typename Number>
88 }; /* HyperbolicSystem */
89
90
107 template <int dim, typename Number>
109 {
110 public:
115 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
116 : hyperbolic_system_(hyperbolic_system)
117 {
118 }
119
123 template <int dim2, typename Number2>
124 auto view() const
125 {
126 return HyperbolicSystemView<dim2, Number2>{hyperbolic_system_};
127 }
128
133
138
139 DEAL_II_ALWAYS_INLINE inline const std::string &equation_of_state() const
140 {
141 return hyperbolic_system_.equation_of_state_;
142 }
143
144 DEAL_II_ALWAYS_INLINE inline ScalarNumber reference_density() const
145 {
146 return hyperbolic_system_.reference_density_;
147 }
148
149 DEAL_II_ALWAYS_INLINE inline ScalarNumber
151 {
152 return hyperbolic_system_.vacuum_state_relaxation_small_;
153 }
154
155 DEAL_II_ALWAYS_INLINE inline ScalarNumber
157 {
158 return hyperbolic_system_.vacuum_state_relaxation_large_;
159 }
160
161 DEAL_II_ALWAYS_INLINE inline bool compute_strict_bounds() const
162 {
163 return hyperbolic_system_.compute_strict_bounds_;
164 }
165
167
171
176 DEAL_II_ALWAYS_INLINE inline Number eos_pressure(const Number &rho,
177 const Number &e) const
178 {
179 const auto &eos = hyperbolic_system_.selected_equation_of_state_;
180
181 if constexpr (std::is_same_v<ScalarNumber, Number>) {
182 return ScalarNumber(eos->pressure(rho, e));
183 } else {
184 Number p;
185 for (unsigned int k = 0; k < Number::size(); ++k) {
186 p[k] = ScalarNumber(eos->pressure(rho[k], e[k]));
187 }
188 return p;
189 }
190 }
191
196 DEAL_II_ALWAYS_INLINE inline Number
197 eos_specific_internal_energy(const Number &rho, const Number &p) const
198 {
199 const auto &eos = hyperbolic_system_.selected_equation_of_state_;
200
201 if constexpr (std::is_same_v<ScalarNumber, Number>) {
202 return ScalarNumber(eos->specific_internal_energy(rho, p));
203 } else {
204 Number e;
205 for (unsigned int k = 0; k < Number::size(); ++k) {
206 e[k] = ScalarNumber(eos->specific_internal_energy(rho[k], p[k]));
207 }
208 return e;
209 }
210 }
211
216 DEAL_II_ALWAYS_INLINE inline Number eos_temperature(const Number &rho,
217 const Number &e) const
218 {
219 const auto &eos = hyperbolic_system_.selected_equation_of_state_;
220
221 if constexpr (std::is_same_v<ScalarNumber, Number>) {
222 return ScalarNumber(eos->temperature(rho, e));
223 } else {
224 Number temp;
225 for (unsigned int k = 0; k < Number::size(); ++k) {
226 temp[k] = ScalarNumber(eos->temperature(rho[k], e[k]));
227 }
228 return temp;
229 }
230 }
231
236 DEAL_II_ALWAYS_INLINE inline Number
237 eos_speed_of_sound(const Number &rho, const Number &e) const
238 {
239 const auto &eos = hyperbolic_system_.selected_equation_of_state_;
240
241 if constexpr (std::is_same_v<ScalarNumber, Number>) {
242 return ScalarNumber(eos->speed_of_sound(rho, e));
243 } else {
244 Number c;
245 for (unsigned int k = 0; k < Number::size(); ++k) {
246 c[k] = ScalarNumber(eos->speed_of_sound(rho[k], e[k]));
247 }
248 return c;
249 }
250 }
251
255 DEAL_II_ALWAYS_INLINE inline ScalarNumber eos_interpolation_b() const
256 {
257 const auto &eos = hyperbolic_system_.selected_equation_of_state_;
258 return ScalarNumber(eos->interpolation_b());
259 }
260
264 static constexpr bool have_gamma = false;
265
269 static constexpr bool have_eos_interpolation_b = true;
270
272
276
277 private:
278 const HyperbolicSystem &hyperbolic_system_;
279
280 public:
282
286
290 static constexpr unsigned int problem_dimension = 2 + dim;
291
295 using state_type = dealii::Tensor<1, problem_dimension, Number>;
296
301
306 static inline const auto component_names =
307 []() -> std::array<std::string, problem_dimension> {
308 if constexpr (dim == 1)
309 return {"rho", "m", "E"};
310 else if constexpr (dim == 2)
311 return {"rho", "m_1", "m_2", "E"};
312 else if constexpr (dim == 3)
313 return {"rho", "m_1", "m_2", "m_3", "E"};
314 __builtin_trap();
315 }();
316
323 static inline const auto primitive_component_names =
324 []() -> std::array<std::string, problem_dimension> {
325 if constexpr (dim == 1)
326 return {"rho", "v", "e"};
327 else if constexpr (dim == 2)
328 return {"rho", "v_1", "v_2", "e"};
329 else if constexpr (dim == 3)
330 return {"rho", "v_1", "v_2", "v_3", "e"};
331 __builtin_trap();
332 }();
333
337 using flux_type =
338 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
339
344
346
350
354 static constexpr unsigned int n_precomputed_initial_values = 0;
355
360 std::array<Number, n_precomputed_initial_values>;
361
368
372 static inline const auto precomputed_initial_names =
373 std::array<std::string, n_precomputed_initial_values>{};
374
378 static constexpr unsigned int n_precomputed_values = 4;
379
383 using precomputed_state_type = std::array<Number, n_precomputed_values>;
384
390
394 static inline const auto precomputed_names =
395 std::array<std::string, n_precomputed_values>{
396 {"p",
397 "surrogate_gamma",
398 "surrogate_specific_entropy",
399 "surrogate_harten_entropy"}};
400
404 static constexpr unsigned int n_precomputation_cycles = 2;
405
410 template <typename DISPATCH, typename SPARSITY>
411 void precomputation_loop(unsigned int cycle,
412 const DISPATCH &dispatch_check,
413 precomputed_vector_type &precomputed_values,
414 const SPARSITY &sparsity_simd,
415 const vector_type &U,
416 unsigned int left,
417 unsigned int right) const;
418
420
424
429 static Number density(const state_type &U);
430
437 Number filter_vacuum_density(const Number &rho) const;
438
443 static dealii::Tensor<1, dim, Number> momentum(const state_type &U);
444
449 static Number total_energy(const state_type &U);
450
455 static Number internal_energy(const state_type &U);
456
463
465
471
482 const Number &gamma_min) const;
483
492 Number surrogate_harten_entropy(const state_type &U,
493 const Number &gamma_min) const;
494
505 const Number &eta,
506 const Number &gamma_min) const;
507
518 Number surrogate_gamma(const state_type &U, const Number &p) const;
519
534 Number surrogate_pressure(const state_type &U, const Number &gamma) const;
535
541 bool is_admissible(const state_type &U) const;
542
544
548
555 template <int component>
557 const state_type &U,
558 const state_type &U_bar,
559 const dealii::Tensor<1, dim, Number> &normal) const;
560
579 template <typename Lambda>
581 apply_boundary_conditions(const dealii::types::boundary_id id,
582 const state_type &U,
583 const dealii::Tensor<1, dim, Number> &normal,
584 const Lambda &get_dirichlet_data) const;
585
587
591
602 flux_type f(const state_type &U, const Number &p) const;
603
626 const unsigned int i,
627 const state_type &U_i) const;
628
632 const unsigned int *js,
633 const state_type &U_j) const;
634
641 const flux_contribution_type &flux_j,
642 const dealii::Tensor<1, dim, Number> &c_ij) const;
643
647 static constexpr bool have_high_order_flux = false;
648
650 const flux_contribution_type &flux_i,
651 const flux_contribution_type &flux_j,
652 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
653
658
660 static constexpr bool have_source_terms = false;
661
663 const unsigned int i,
664 const state_type &U_i,
665 const ScalarNumber tau) const = delete;
666
668 const unsigned int *js,
669 const state_type &U_j,
670 const ScalarNumber tau) const = delete;
671
673
677
688 template <typename ST>
689 state_type expand_state(const ST &state) const;
690
703 template <typename ST>
704 state_type from_initial_state(const ST &initial_state) const;
705
710 state_type from_primitive_state(const state_type &primitive_state) const;
711
716 state_type to_primitive_state(const state_type &state) const;
717
723 template <typename Lambda>
725 const Lambda &lambda) const;
727 }; /* HyperbolicSystemView */
728
729
730 /*
731 * -------------------------------------------------------------------------
732 * Inline definitions
733 * -------------------------------------------------------------------------
734 */
735
736
738 const std::string &subsection /*= "HyperbolicSystem"*/)
739 : ParameterAcceptor(subsection)
740 {
741 equation_of_state_ = "polytropic gas";
742 add_parameter(
743 "equation of state",
744 equation_of_state_,
745 "The equation of state. Valid names are given by any of the "
746 "subsections defined below");
747
748 compute_strict_bounds_ = true;
749 add_parameter(
750 "compute strict bounds",
751 compute_strict_bounds_,
752 "Compute strict, but significantly more expensive bounds at various "
753 "places: (a) an expensive, but better upper wavespeed estimate in "
754 "the approximate RiemannSolver; (b) entropy viscosity-commutator "
755 "with correct gamma_min over the stencil; (c) mathematically correct "
756 "surrogate specific entropy minimum with gamma_min over the "
757 "stencil.");
758
759 reference_density_ = 1.;
760 add_parameter("reference density",
761 reference_density_,
762 "Problem specific density reference");
763
764 vacuum_state_relaxation_small_ = 1.e2;
765 add_parameter("vacuum state relaxation small",
766 vacuum_state_relaxation_small_,
767 "Problem specific vacuum relaxation parameter");
768
769 vacuum_state_relaxation_large_ = 1.e4;
770 add_parameter("vacuum state relaxation large",
771 vacuum_state_relaxation_large_,
772 "Problem specific vacuum relaxation parameter");
773
774 /*
775 * And finally populate the equation of state list with all equation of
776 * state configurations defined in the EquationOfState namespace:
777 */
779 equation_of_state_list_, subsection);
780
781 const auto populate_functions = [this]() {
782 bool initialized = false;
783 for (auto &it : equation_of_state_list_)
784
785 /* Populate EOS-specific quantities and functions */
786 if (it->name() == equation_of_state_) {
787 selected_equation_of_state_ = it;
789 "Compressible Euler equations (" + it->name() + " EOS)";
790 initialized = true;
791 break;
792 }
793
794 AssertThrow(
795 initialized,
796 dealii::ExcMessage(
797 "Could not find an equation of state description with name \"" +
798 equation_of_state_ + "\""));
799 };
800
801 ParameterAcceptor::parse_parameters_call_back.connect(populate_functions);
802 populate_functions();
803 }
804
805
806 template <int dim, typename Number>
807 template <typename DISPATCH, typename SPARSITY>
808 DEAL_II_ALWAYS_INLINE inline void
810 unsigned int cycle [[maybe_unused]],
811 const DISPATCH &dispatch_check,
812 precomputed_vector_type &precomputed_values,
813 const SPARSITY &sparsity_simd,
814 const vector_type &U,
815 unsigned int left,
816 unsigned int right) const
817 {
818 Assert(cycle == 0 || cycle == 1, dealii::ExcInternalError());
819
820 /* We are inside a thread parallel context */
821
822 const auto &eos = hyperbolic_system_.selected_equation_of_state_;
823 unsigned int stride_size = get_stride_size<Number>;
824
825 if (cycle == 0) {
826 if (eos->prefer_vector_interface()) {
827 /*
828 * Set up temporary storage for p, rho, e and make two calls into
829 * the eos library.
830 */
831 const auto offset = left;
832 const auto size = right - left;
833
834 static /* shared */ std::vector<double> p;
835 static /* shared */ std::vector<double> rho;
836 static /* shared */ std::vector<double> e;
838 {
839 p.resize(size);
840 rho.resize(size);
841 e.resize(size);
842 }
843
845 for (unsigned int i = 0; i < size; i += stride_size) {
846 const auto U_i = U.template get_tensor<Number>(offset + i);
847 const auto rho_i = density(U_i);
848 const auto e_i = internal_energy(U_i) / rho_i;
849 /*
850 * Populate rho and e also for interpolated values from
851 * constrainted degrees of freedom so that the vectors contain
852 * physically admissible entries throughout.
853 */
854 write_entry<Number>(rho, rho_i, i);
855 write_entry<Number>(e, e_i, i);
856 }
857
858 /* Make sure the call into eospac (and others) is single threaded. */
860 {
861 eos->pressure(p, rho, e);
862 }
863
865 for (unsigned int i = 0; i < size; i += stride_size) {
866 /* Skip constrained degrees of freedom: */
867 const unsigned int row_length = sparsity_simd.row_length(i);
868 if (row_length == 1)
869 continue;
870
871 dispatch_check(i);
872
873 using PT = precomputed_state_type;
874 const auto U_i = U.template get_tensor<Number>(offset + i);
875 const auto p_i = get_entry<Number>(p, i);
876 const auto gamma_i = surrogate_gamma(U_i, p_i);
877 const PT prec_i{p_i, gamma_i, Number(0.), Number(0.)};
878 precomputed_values.template write_tensor<Number>(prec_i,
879 offset + i);
880 }
881 } else {
882 /*
883 * This is the variant with slightly better performance provided
884 * that a call to the eos is not too expensive. This variant
885 * calls into the eos library for every single degree of freedom.
886 */
888 for (unsigned int i = left; i < right; i += stride_size) {
889 /* Skip constrained degrees of freedom: */
890 const unsigned int row_length = sparsity_simd.row_length(i);
891 if (row_length == 1)
892 continue;
893
894 dispatch_check(i);
895
896 const auto U_i = U.template get_tensor<Number>(i);
897 const auto rho_i = density(U_i);
898 const auto e_i = internal_energy(U_i) / rho_i;
899 const auto p_i = eos_pressure(rho_i, e_i);
900
901 const auto gamma_i = surrogate_gamma(U_i, p_i);
902 using PT = precomputed_state_type;
903 const PT prec_i{p_i, gamma_i, Number(0.), Number(0.)};
904 precomputed_values.template write_tensor<Number>(prec_i, i);
905 }
906 } /* prefer_vector_interface */
907 } /* cycle == 0 */
908
909 if (cycle == 1) {
911 for (unsigned int i = left; i < right; i += stride_size) {
912 using PT = precomputed_state_type;
913
914 /* Skip constrained degrees of freedom: */
915 const unsigned int row_length = sparsity_simd.row_length(i);
916 if (row_length == 1)
917 continue;
918
919 dispatch_check(i);
920
921 const auto U_i = U.template get_tensor<Number>(i);
922 auto prec_i = precomputed_values.template get_tensor<Number, PT>(i);
923 auto &[p_i, gamma_min_i, s_i, eta_i] = prec_i;
924
925 const unsigned int *js = sparsity_simd.columns(i) + stride_size;
926 for (unsigned int col_idx = 1; col_idx < row_length;
927 ++col_idx, js += stride_size) {
928
929 const auto U_j = U.template get_tensor<Number>(js);
930 const auto prec_j =
931 precomputed_values.template get_tensor<Number, PT>(js);
932 auto &[p_j, gamma_min_j, s_j, eta_j] = prec_j;
933 const auto gamma_j = surrogate_gamma(U_j, p_j);
934 gamma_min_i = std::min(gamma_min_i, gamma_j);
935 }
936
937 s_i = surrogate_specific_entropy(U_i, gamma_min_i);
938 eta_i = surrogate_harten_entropy(U_i, gamma_min_i);
939 precomputed_values.template write_tensor<Number>(prec_i, i);
940 }
941 }
942 }
943
944
945 template <int dim, typename Number>
946 DEAL_II_ALWAYS_INLINE inline Number
948 {
949 return U[0];
950 }
951
952
953 template <int dim, typename Number>
954 DEAL_II_ALWAYS_INLINE inline Number
956 const Number &rho) const
957 {
958 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
959 const Number rho_cutoff_large =
960 reference_density() * vacuum_state_relaxation_large() * eps;
961
962 return dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
963 std::abs(rho), rho_cutoff_large, Number(0.), rho);
964 }
965
966
967 template <int dim, typename Number>
968 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
970 {
971 dealii::Tensor<1, dim, Number> result;
972 for (unsigned int i = 0; i < dim; ++i)
973 result[i] = U[1 + i];
974 return result;
975 }
976
977
978 template <int dim, typename Number>
979 DEAL_II_ALWAYS_INLINE inline Number
981 {
982 return U[1 + dim];
983 }
984
985
986 template <int dim, typename Number>
987 DEAL_II_ALWAYS_INLINE inline Number
989 {
990 /*
991 * rho e = (E - 1/2*m^2/rho)
992 */
993 const Number rho_inverse = ScalarNumber(1.) / density(U);
994 const auto m = momentum(U);
995 const Number E = total_energy(U);
996 return E - ScalarNumber(0.5) * m.norm_square() * rho_inverse;
997 }
998
999
1000 template <int dim, typename Number>
1001 DEAL_II_ALWAYS_INLINE inline auto
1003 const state_type &U) -> state_type
1004 {
1005 /*
1006 * With
1007 * rho e = E - 1/2 |m|^2 / rho
1008 * we get
1009 * (rho e)' = (1/2m^2/rho^2, -m/rho , 1 )^T
1010 */
1011
1012 const Number rho_inverse = ScalarNumber(1.) / density(U);
1013 const auto u = momentum(U) * rho_inverse;
1014
1015 state_type result;
1016
1017 result[0] = ScalarNumber(0.5) * u.norm_square();
1018 for (unsigned int i = 0; i < dim; ++i) {
1019 result[1 + i] = -u[i];
1020 }
1021 result[dim + 1] = ScalarNumber(1.);
1022
1023 return result;
1024 }
1025
1026
1027 template <int dim, typename Number>
1028 DEAL_II_ALWAYS_INLINE inline Number
1030 const state_type &U, const Number &gamma_min) const
1031 {
1033
1034 const auto rho = density(U);
1035 const auto rho_inverse = ScalarNumber(1.) / rho;
1036 const auto interpolation_b = Number(eos_interpolation_b());
1037 const auto covolume = Number(1.) - interpolation_b * rho;
1038
1039 return internal_energy(U) *
1040 ryujin::pow(rho_inverse - interpolation_b, gamma_min) / covolume;
1041 }
1042
1043
1044 template <int dim, typename Number>
1045 DEAL_II_ALWAYS_INLINE inline Number
1047 const state_type &U, const Number &gamma_min) const
1048 {
1049 const auto rho = density(U);
1050 const auto m = momentum(U);
1051 const auto E = total_energy(U);
1052 const auto rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
1053
1054 const auto exponent = ScalarNumber(1.) / (gamma_min + Number(1.));
1055
1056 const auto interpolation_b = Number(eos_interpolation_b());
1057 const auto covolume = Number(1.) - interpolation_b * rho;
1058 const auto covolume_term = ryujin::pow(covolume, gamma_min - Number(1.));
1059
1060 return ryujin::pow(rho_rho_e * covolume_term, exponent);
1061 }
1062
1063
1064 template <int dim, typename Number>
1065 DEAL_II_ALWAYS_INLINE inline auto
1067 const state_type &U, const Number &eta, const Number &gamma_min) const
1068 -> state_type
1069 {
1070 /*
1071 * With
1072 * eta = (rho^2 e * (1 - interpolation_b * rho)) ^ {1 / (gamma + 1)},
1073 * rho^2 e = rho * E - 1/2 |m|^2,
1074 *
1075 * we get
1076 *
1077 * eta' = factor * (1 - interpolation_b rho) * (E,-m,rho)^T +
1078 * factor * rho^2 e * (gamma - 1) * b * (1,0,0)^T
1079 *
1080 * factor = 1/(gamma+1) * (eta/(1-interpolation_b rho)^-gamma
1081 * / (1-interpolation_b rho)^2
1082 */
1083
1084 const auto rho = density(U);
1085 const auto m = momentum(U);
1086 const auto E = total_energy(U);
1087 const auto rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
1088
1089 const auto interpolation_b = Number(eos_interpolation_b());
1090 const auto covolume = Number(1.) - interpolation_b * rho;
1091 const auto covolume_inverse = Number(1.) / covolume;
1092
1093 const auto factor = ryujin::pow(eta * covolume_inverse, -gamma_min) *
1094 fixed_power<2>(covolume_inverse) /
1095 (gamma_min + Number(1.));
1096
1097 state_type result;
1098
1099 result[0] = factor * (covolume * E - (gamma_min - Number(1.)) *
1100 rho_rho_e * interpolation_b);
1101 for (unsigned int i = 0; i < dim; ++i)
1102 result[1 + i] = -factor * covolume * m[i];
1103 result[dim + 1] = factor * covolume * rho;
1104
1105 return result;
1106 }
1107
1108
1109 template <int dim, typename Number>
1110 DEAL_II_ALWAYS_INLINE inline Number
1112 const Number &p) const
1113 {
1114 const auto rho = density(U);
1115 const auto rho_e = internal_energy(U);
1116 const auto interpolation_b = Number(eos_interpolation_b());
1117 const auto covolume = Number(1.) - interpolation_b * rho;
1118
1119 return Number(1.) + p * covolume / rho_e;
1120 }
1121
1122
1123 template <int dim, typename Number>
1124 DEAL_II_ALWAYS_INLINE inline Number
1126 const state_type &U, const Number &gamma) const
1127 {
1128 const auto rho = density(U);
1129 const auto rho_e = internal_energy(U);
1130 const auto interpolation_b = Number(eos_interpolation_b());
1131 const auto covolume = Number(1.) - interpolation_b * rho;
1132
1133 return (gamma - Number(1.)) * rho_e / covolume;
1134 }
1135
1136
1137 template <int dim, typename Number>
1138 DEAL_II_ALWAYS_INLINE inline bool
1140 {
1141 const auto rho = density(U);
1142 const auto e = internal_energy(U);
1143
1144 constexpr auto gt = dealii::SIMDComparison::greater_than;
1145 using T = Number;
1146 const auto test =
1147 dealii::compare_and_apply_mask<gt>(rho, T(0.), T(0.), T(-1.)) + //
1148 dealii::compare_and_apply_mask<gt>(e, T(0.), T(0.), T(-1.));
1149
1150#ifdef DEBUG_OUTPUT
1151 if (!(test == Number(0.))) {
1152 std::cout << std::fixed << std::setprecision(16);
1153 std::cout << "Bounds violation: Negative state [rho, e] detected!\n";
1154 std::cout << "\t\trho: " << rho << "\n";
1155 std::cout << "\t\tint: " << e << "\n";
1156 }
1157#endif
1158
1159 return (test == Number(0.));
1160 }
1161
1162
1163 template <int dim, typename Number>
1164 template <int component>
1165 DEAL_II_ALWAYS_INLINE inline auto
1167 const state_type &U,
1168 const state_type &U_bar,
1169 const dealii::Tensor<1, dim, Number> &normal) const -> state_type
1170 {
1171 __builtin_trap(); // untested and likely needs to be refactored
1172
1173 static_assert(component == 1 || component == 2,
1174 "component has to be 1 or 2");
1175
1176 const auto m = momentum(U);
1177 const auto rho = density(U);
1178 const auto vn = m * normal / rho;
1179
1180 const auto p = surrogate_pressure(U); // FIXME: discuss
1181 const auto gamma = surrogate_gamma(U, p);
1182 const auto interpolation_b = ScalarNumber(eos_interpolation_b());
1183 const auto x = Number(1.) - interpolation_b * rho;
1184 const auto a = std::sqrt(gamma * p / (rho * x)); // local speed of sound
1185
1186
1187 const auto m_bar = momentum(U_bar);
1188 const auto rho_bar = density(U_bar);
1189 const auto vn_bar = m_bar * normal / rho_bar;
1190
1191 const auto p_bar = surrogate_pressure(U_bar); // FIXME: discuss
1192 const auto gamma_bar = surrogate_gamma(U_bar, p_bar);
1193 const auto x_bar = Number(1.) - interpolation_b * rho_bar;
1194 const auto a_bar = std::sqrt(gamma_bar * p_bar / (rho_bar * x_bar));
1195
1196 /* First Riemann characteristic: v* n - 2 / (gamma - 1) * a */
1197
1198 const auto R_1 = component == 1
1199 ? vn_bar - 2. * a_bar / (gamma_bar - 1.) * x_bar
1200 : vn - 2. * a / (gamma - 1.) * x;
1201
1202 /* Second Riemann characteristic: v* n + 2 / (gamma - 1) * a */
1203
1204 const auto R_2 = component == 2
1205 ? vn_bar + 2. * a_bar / (gamma_bar - 1.) * x_bar
1206 : vn + 2. * a / (gamma - 1.) * x;
1207
1208 const auto s = p / ryujin::pow(rho, gamma) * ryujin::pow(x, gamma);
1209
1210 const auto vperp = m / rho - vn * normal;
1211
1212 const auto vn_new = 0.5 * (R_1 + R_2);
1213
1214 auto rho_new =
1215 1. / (gamma * s) * ryujin::pow((gamma - 1.) / 4. * (R_2 - R_1), 2.);
1216 rho_new =
1217 1. / (ryujin::pow(rho_new, 1. / (1. - gamma)) + interpolation_b);
1218
1219 const auto x_new = 1. - interpolation_b * rho_new;
1220
1221 const auto p_new =
1222 s * std::pow(rho_new, gamma) / ryujin::pow(x_new, gamma);
1223
1224 state_type U_new;
1225 U_new[0] = rho_new;
1226 for (unsigned int d = 0; d < dim; ++d) {
1227 U_new[1 + d] = rho_new * (vn_new * normal + vperp)[d];
1228 }
1229 U_new[1 + dim] = p_new / (gamma - 1.) +
1230 0.5 * rho_new * (vn_new * vn_new + vperp.norm_square());
1231
1232 return U_new;
1233 }
1234
1235
1236 template <int dim, typename Number>
1237 template <typename Lambda>
1238 DEAL_II_ALWAYS_INLINE inline auto
1240 dealii::types::boundary_id id,
1241 const state_type &U,
1242 const dealii::Tensor<1, dim, Number> &normal,
1243 const Lambda &get_dirichlet_data) const -> state_type
1244 {
1245 state_type result = U;
1246
1247 if (id == Boundary::dirichlet) {
1248 result = get_dirichlet_data();
1249
1250 } else if (id == Boundary::slip) {
1251 auto m = momentum(U);
1252 m -= 1. * (m * normal) * normal;
1253 for (unsigned int k = 0; k < dim; ++k)
1254 result[k + 1] = m[k];
1255
1256 } else if (id == Boundary::no_slip) {
1257 for (unsigned int k = 0; k < dim; ++k)
1258 result[k + 1] = Number(0.);
1259
1260 } else if (id == Boundary::dynamic) {
1261 __builtin_trap(); // untested and likely needs to be refactored
1262#if 0
1263 /*
1264 * On dynamic boundary conditions, we distinguish four cases:
1265 *
1266 * - supersonic inflow: prescribe full state
1267 * - subsonic inflow:
1268 * decompose into Riemann invariants and leave R_2
1269 * characteristic untouched.
1270 * - supersonic outflow: do nothing
1271 * - subsonic outflow:
1272 * decompose into Riemann invariants and prescribe incoming
1273 * R_1 characteristic.
1274 */
1275 const auto m = momentum(U);
1276 const auto rho = density(U);
1277 const auto a = speed_of_sound(U);
1278 const auto vn = m * normal / rho;
1279
1280 /* Supersonic inflow: */
1281 if (vn < -a) {
1282 result = get_dirichlet_data();
1283 }
1284
1285 /* Subsonic inflow: */
1286 if (vn >= -a && vn <= 0.) {
1287 const auto U_dirichlet = get_dirichlet_data();
1288 result = prescribe_riemann_characteristic<2>(U_dirichlet, U, normal);
1289 }
1290
1291 /* Subsonic outflow: */
1292 if (vn > 0. && vn <= a) {
1293 const auto U_dirichlet = get_dirichlet_data();
1294 result = prescribe_riemann_characteristic<1>(U, U_dirichlet, normal);
1295 }
1296
1297 /* Supersonic outflow: do nothing, i.e., keep U as is */
1298#endif
1299 }
1300
1301 return result;
1302 }
1303
1304
1305 template <int dim, typename Number>
1306 DEAL_II_ALWAYS_INLINE inline auto
1308 const Number &p) const -> flux_type
1309 {
1310 const auto rho_inverse = ScalarNumber(1.) / density(U);
1311 const auto m = momentum(U);
1312 const auto E = total_energy(U);
1313
1314 flux_type result;
1315
1316 result[0] = m;
1317 for (unsigned int i = 0; i < dim; ++i) {
1318 result[1 + i] = m * (m[i] * rho_inverse);
1319 result[1 + i][i] += p;
1320 }
1321 result[dim + 1] = m * (rho_inverse * (E + p));
1322
1323 return result;
1324 }
1325
1326
1327 template <int dim, typename Number>
1328 DEAL_II_ALWAYS_INLINE inline auto
1330 const precomputed_vector_type &pv,
1331 const precomputed_initial_vector_type & /*piv*/,
1332 const unsigned int i,
1333 const state_type &U_i) const -> flux_contribution_type
1334 {
1335 const auto &[p_i, gamma_min_i, s_i, eta_i] =
1336 pv.template get_tensor<Number, precomputed_state_type>(i);
1337 return f(U_i, p_i);
1338 }
1339
1340
1341 template <int dim, typename Number>
1342 DEAL_II_ALWAYS_INLINE inline auto
1344 const precomputed_vector_type &pv,
1345 const precomputed_initial_vector_type & /*piv*/,
1346 const unsigned int *js,
1347 const state_type &U_j) const -> flux_contribution_type
1348 {
1349 const auto &[p_j, gamma_min_j, s_j, eta_j] =
1350 pv.template get_tensor<Number, precomputed_state_type>(js);
1351 return f(U_j, p_j);
1352 }
1353
1354
1355 template <int dim, typename Number>
1356 DEAL_II_ALWAYS_INLINE inline auto
1358 const flux_contribution_type &flux_i,
1359 const flux_contribution_type &flux_j,
1360 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
1361 {
1362 return -contract(add(flux_i, flux_j), c_ij);
1363 }
1364
1365
1366 template <int dim, typename Number>
1367 template <typename ST>
1369 -> state_type
1370 {
1371 using T = typename ST::value_type;
1372 static_assert(std::is_same_v<Number, T>, "template mismatch");
1373
1374 constexpr auto dim2 = ST::dimension - 2;
1375 static_assert(dim >= dim2,
1376 "the space dimension of the argument state must not be "
1377 "larger than the one of the target state");
1378
1379 state_type result;
1380 result[0] = state[0];
1381 result[dim + 1] = state[dim2 + 1];
1382 for (unsigned int i = 1; i < dim2 + 1; ++i)
1383 result[i] = state[i];
1384
1385 return result;
1386 }
1387
1388
1389 template <int dim, typename Number>
1390 template <typename ST>
1391 DEAL_II_ALWAYS_INLINE inline auto
1393 const ST &initial_state) const -> state_type
1394 {
1395 auto primitive_state = expand_state(initial_state);
1396
1397 /* pressure into specific internal energy: */
1398 const auto rho = density(primitive_state);
1399 const auto p = /*SIC!*/ total_energy(primitive_state);
1400 const auto e = eos_specific_internal_energy(rho, p);
1401 primitive_state[dim + 1] = e;
1402
1403 return from_primitive_state(primitive_state);
1404 }
1405
1406
1407 template <int dim, typename Number>
1408 DEAL_II_ALWAYS_INLINE inline auto
1410 const state_type &primitive_state) const -> state_type
1411 {
1412 const auto rho = density(primitive_state);
1413 /* extract velocity: */
1414 const auto u = /*SIC!*/ momentum(primitive_state);
1415 /* extract specific internal energy: */
1416 const auto &e = /*SIC!*/ total_energy(primitive_state);
1417
1418 auto state = primitive_state;
1419 /* Fix up momentum: */
1420 for (unsigned int i = 1; i < dim + 1; ++i)
1421 state[i] *= rho;
1422
1423 /* Compute total energy: */
1424 state[dim + 1] = rho * e + Number(0.5) * rho * u * u;
1425
1426 return state;
1427 }
1428
1429
1430 template <int dim, typename Number>
1431 DEAL_II_ALWAYS_INLINE inline auto
1433 const state_type &state) const -> state_type
1434 {
1435 const auto rho = density(state);
1436 const auto rho_inverse = Number(1.) / rho;
1437 const auto rho_e = internal_energy(state);
1438
1439 auto primitive_state = state;
1440 /* Fix up velocity: */
1441 for (unsigned int i = 1; i < dim + 1; ++i)
1442 primitive_state[i] *= rho_inverse;
1443 /* Set specific internal energy: */
1444 primitive_state[dim + 1] = rho_e * rho_inverse;
1445
1446 return primitive_state;
1447 }
1448
1449
1450 template <int dim, typename Number>
1451 template <typename Lambda>
1453 const state_type &state, const Lambda &lambda) const -> state_type
1454 {
1455 auto result = state;
1456 const auto M = lambda(momentum(state));
1457 for (unsigned int d = 0; d < dim; ++d)
1458 result[1 + d] = M[d];
1459 return result;
1460 }
1461 } // namespace EulerAEOS
1462} // namespace ryujin
dealii::Tensor< 1, problem_dimension, Number > state_type
state_type from_initial_state(const ST &initial_state) const
Number surrogate_harten_entropy(const state_type &U, const Number &gamma_min) const
std::array< Number, n_precomputed_values > precomputed_state_type
static Number internal_energy(const state_type &U)
state_type to_primitive_state(const state_type &state) 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
std::array< Number, n_precomputed_initial_values > precomputed_initial_state_type
typename get_value_type< Number >::type ScalarNumber
state_type nodal_source(const precomputed_vector_type &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const =delete
static dealii::Tensor< 1, dim, Number > momentum(const state_type &U)
void precomputation_loop(unsigned int cycle, const DISPATCH &dispatch_check, precomputed_vector_type &precomputed_values, const SPARSITY &sparsity_simd, const vector_type &U, unsigned int left, unsigned int right) const
Number surrogate_pressure(const state_type &U, const Number &gamma) const
DEAL_II_ALWAYS_INLINE const std::string & equation_of_state() const
DEAL_II_ALWAYS_INLINE ScalarNumber vacuum_state_relaxation_large() const
static constexpr unsigned int n_precomputed_values
DEAL_II_ALWAYS_INLINE ScalarNumber reference_density() const
state_type from_primitive_state(const state_type &primitive_state) const
static state_type internal_energy_derivative(const state_type &U)
DEAL_II_ALWAYS_INLINE Number eos_temperature(const Number &rho, const Number &e) const
DEAL_II_ALWAYS_INLINE ScalarNumber eos_interpolation_b() const
DEAL_II_ALWAYS_INLINE Number eos_pressure(const Number &rho, const Number &e) const
static constexpr unsigned int problem_dimension
Number surrogate_specific_entropy(const state_type &U, const Number &gamma_min) const
static Number total_energy(const state_type &U)
bool is_admissible(const state_type &U) const
DEAL_II_ALWAYS_INLINE bool compute_strict_bounds() const
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
DEAL_II_ALWAYS_INLINE Number eos_specific_internal_energy(const Number &rho, const Number &p) const
state_type nodal_source(const precomputed_vector_type &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
static constexpr unsigned int n_precomputation_cycles
HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
Number filter_vacuum_density(const Number &rho) const
flux_type f(const state_type &U, const Number &p) const
flux_contribution_type flux_contribution(const precomputed_vector_type &pv, const precomputed_initial_vector_type &piv, const unsigned int i, const state_type &U_i) const
state_type expand_state(const ST &state) const
state_type surrogate_harten_entropy_derivative(const state_type &U, const Number &eta, const Number &gamma_min) const
DEAL_II_ALWAYS_INLINE ScalarNumber vacuum_state_relaxation_small() const
Number surrogate_gamma(const state_type &U, const Number &p) const
state_type prescribe_riemann_characteristic(const state_type &U, const state_type &U_bar, const dealii::Tensor< 1, dim, Number > &normal) const
DEAL_II_ALWAYS_INLINE Number eos_speed_of_sound(const Number &rho, const Number &e) const
static constexpr unsigned int n_precomputed_initial_values
dealii::Tensor< 1, problem_dimension, dealii::Tensor< 1, dim, Number > > flux_type
static Number density(const state_type &U)
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 apply_galilei_transform(const state_type &state, const Lambda &lambda) const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
typename get_value_type< Number >::type ScalarNumber
std::array< Number, n_precomputed_values > precomputed_state_type
dealii::Tensor< 1, problem_dimension, Number > state_type
void populate_equation_of_state_list(equation_of_state_list_type &equation_of_state_list, const std::string &subsection)
#define RYUJIN_OMP_FOR
Definition: openmp.h:70
#define RYUJIN_OMP_SINGLE
Definition: openmp.h:100
T pow(const T x, const T b)
std::set< std::shared_ptr< EquationOfState > > equation_of_state_list_type
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)