ryujin 2.1.1 revision ee5cbcbf2346c1299c942d0e1f13b46449973c18
Loading...
Searching...
No Matches
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 - 2026 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>
12#include <gpu.h>
13#include <loop.h>
15#include <patterns_conversion.h>
16#include <simd.h>
17#include <state_vector.h>
18
19#include <deal.II/base/memory_space.h>
20#include <deal.II/base/parameter_acceptor.h>
21#include <deal.II/base/tensor.h>
22
23#include <array>
24
25namespace ryujin
26{
27 namespace Euler
28 {
29 template <int dim,
30 typename Number,
31 typename MemorySpace = dealii::MemorySpace::Host>
32 class HyperbolicSystemView;
33
44 class HyperbolicSystem final : public dealii::ParameterAcceptor
45 {
46 public:
50 static inline const std::string problem_name =
51 "Compressible Euler equations (polytropic gas EOS, optimized)";
52
88
92 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
93
99 template <int dim,
100 typename Number = double,
101 typename MemorySpace = dealii::MemorySpace::Host>
103
111 template <int dim,
112 typename Number,
113 typename MemorySpace = dealii::MemorySpace::Host>
114 auto view() const
115 {
116 return View<dim, Number, MemorySpace>{*this};
117 }
118
127 template <typename MemorySpace = dealii::MemorySpace::Host,
128 int dim,
129 typename ScalarNumber>
131 const OfflineData<dim, ScalarNumber> &offline_data,
133 &state_vector,
134 const bool skip_constrained_dofs = true) const;
135
136 private:
141
148 void update_parameters();
149
150 Mirrored<Parameters> parameters_;
151
153
154 template <int, typename, typename>
156 }; /* HyperbolicSystem */
157
158
182 template <int dim, typename Number, typename MemorySpace>
184 {
185 public:
186 static_assert(
187 std::is_same_v<MemorySpace, dealii::MemorySpace::Host> ||
188 std::is_same_v<MemorySpace, dealii::MemorySpace::Default>,
189 "Unexpected memory space");
190
195
200
204 static constexpr unsigned int problem_dimension = 2 + dim;
205
209 using state_type = dealii::Tensor<1, problem_dimension, Number>;
210
214 using flux_type =
215 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
216
221
226 static inline const auto component_names =
227 []() -> std::array<std::string, problem_dimension> {
228 if constexpr (dim == 1)
229 return {"rho", "m", "E"};
230 else if constexpr (dim == 2)
231 return {"rho", "m_1", "m_2", "E"};
232 else if constexpr (dim == 3)
233 return {"rho", "m_1", "m_2", "m_3", "E"};
234 __builtin_trap();
235 }();
236
241 static inline const auto primitive_component_names =
242 []() -> std::array<std::string, problem_dimension> {
243 if constexpr (dim == 1)
244 return {"rho", "v", "p"};
245 else if constexpr (dim == 2)
246 return {"rho", "v_1", "v_2", "p"};
247 else if constexpr (dim == 3)
248 return {"rho", "v_1", "v_2", "v_3", "p"};
249 __builtin_trap();
250 }();
251
255 static constexpr unsigned int n_precomputed_values = 2;
256
260 using precomputed_type = std::array<Number, n_precomputed_values>;
261
265 static inline const auto precomputed_names =
266 std::array<std::string, n_precomputed_values>{"s", "eta_h"};
267
271 static constexpr unsigned int n_initial_precomputed_values = 0;
272
277 std::array<Number, n_initial_precomputed_values>;
278
282 static inline const auto initial_precomputed_names =
283 std::array<std::string, n_initial_precomputed_values>{};
284
288 using StateVector = Vectors::
289 StateVector<ScalarNumber, problem_dimension, n_precomputed_values>;
290
296
302
310 dealii::VectorizedArray<ScalarNumber>::size(),
311 MemorySpace,
312 /*writable=*/false>;
313
321
329 dealii::VectorizedArray<ScalarNumber>::size(),
330 MemorySpace,
331 /*writable=*/false>;
332
334
338
343 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
344 : parameters_(
345 hyperbolic_system.parameters_.template view<MemorySpace>())
346 {
347 }
348
350
354
355 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma() const
356 {
357 return ScalarNumber(parameters_->gamma);
358 }
359
360 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber reference_density() const
361 {
362 return ScalarNumber(parameters_->reference_density);
363 }
364
365 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
367 {
368 return ScalarNumber(parameters_->vacuum_state_relaxation_small);
369 }
370
371 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
373 {
374 return ScalarNumber(parameters_->vacuum_state_relaxation_large);
375 }
376
378
386
387 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma_inverse() const
388 {
389 return ScalarNumber(parameters_->gamma_inverse);
390 }
391
392 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
394 {
395 return ScalarNumber(parameters_->gamma_plus_one_inverse);
396 }
397
398 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
400 {
401 return ScalarNumber(parameters_->gamma_minus_one_inverse);
402 }
403
404 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
409
411
415
416 static constexpr bool have_gamma = true;
417 static constexpr bool have_covolume_constant = false;
418 static constexpr bool have_energy_equation = true;
419
421
425
430 static DEAL_II_HOST_DEVICE Number density(const state_type &U);
431
438 DEAL_II_HOST_DEVICE Number filter_vacuum_density(const Number &rho) const;
439
444 static DEAL_II_HOST_DEVICE dealii::Tensor<1, dim, Number>
445 momentum(const state_type &U);
446
451 static DEAL_II_HOST_DEVICE Number total_energy(const state_type &U);
452
457 static DEAL_II_HOST_DEVICE Number internal_energy(const state_type &U);
458
464 static DEAL_II_HOST_DEVICE state_type
466
477 DEAL_II_HOST_DEVICE Number pressure(const state_type &U) const;
478
486 DEAL_II_HOST_DEVICE Number speed_of_sound(const state_type &U) const;
487
495 DEAL_II_HOST_DEVICE Number specific_entropy(const state_type &U) const;
496
504 DEAL_II_HOST_DEVICE Number harten_entropy(const state_type &U) const;
505
513 DEAL_II_HOST_DEVICE state_type
515
520 DEAL_II_HOST_DEVICE Number
521 mathematical_entropy(const state_type &U) const;
522
528 DEAL_II_HOST_DEVICE state_type
530
536 DEAL_II_HOST_DEVICE bool is_admissible(const state_type &U) const;
537
539
543
549 template <int component>
550 DEAL_II_HOST_DEVICE std::array<state_type, 2> linearized_eigenvector(
551 const state_type &U,
552 const dealii::Tensor<1, dim, Number> &normal) const;
553
560 template <int component>
562 const state_type &U,
563 const state_type &U_bar,
564 const dealii::Tensor<1, dim, Number> &normal) const;
565
584 template <typename Lambda>
585 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type
586 apply_boundary_conditions(const dealii::types::boundary_id id,
587 const state_type &U,
588 const dealii::Tensor<1, dim, Number> &normal,
589 const Lambda &get_dirichlet_data) const;
590
592
596
607 DEAL_II_HOST_DEVICE flux_type f(const state_type &U) const;
608
628 DEAL_II_HOST_DEVICE
632 const unsigned int i,
633 const state_type &U_i) const;
634
635 DEAL_II_HOST_DEVICE
639 const unsigned int *js,
640 const state_type &U_j) const;
641
646 DEAL_II_HOST_DEVICE
649 const flux_contribution_type &flux_j,
650 const dealii::Tensor<1, dim, Number> &c_ij) const;
651
653 static constexpr bool have_high_order_flux = false;
654
655 DEAL_II_HOST_DEVICE
657 const flux_contribution_type &flux_i,
658 const flux_contribution_type &flux_j,
659 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
660
662
666
668 static constexpr bool have_source_terms = false;
669
670 DEAL_II_HOST_DEVICE
672 const unsigned int i,
673 const state_type &U_i,
674 const ScalarNumber tau) const = delete;
675
676 DEAL_II_HOST_DEVICE
678 const unsigned int *js,
679 const state_type &U_j,
680 const ScalarNumber tau) const = delete;
681
683
687
698 template <typename ST>
699 DEAL_II_HOST_DEVICE state_type expand_state(const ST &state) const;
700
714 template <typename ST>
715 DEAL_II_HOST_DEVICE state_type
716 from_initial_state(const ST &initial_state) const;
717
722 DEAL_II_HOST_DEVICE
723 state_type from_primitive_state(const state_type &primitive_state) const;
724
729 DEAL_II_HOST_DEVICE
730 state_type to_primitive_state(const state_type &state) const;
731
737 template <typename Lambda>
739 const state_type &state, const Lambda &lambda) const;
740
741 private:
743
747
748 const HyperbolicSystem::Parameters *const parameters_;
749
751 }; /* HyperbolicSystemView */
752
753
754 /*
755 * -------------------------------------------------------------------------
756 * Inline definitions
757 * -------------------------------------------------------------------------
758 */
759
760 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
761 : ParameterAcceptor(subsection)
762 , parameters_("euler_hyperbolic_system_parameters",
764 {
765 /*
766 * Note: We bind the parameters directly to the storage held by the
767 * Mirrored object. The corresponding memory is allocated once in the
768 * constructor and never reallocated, and the
769 * implicit_transfers_host_resident policy guarantees that the host
770 * storage is never deallocated: the addresses thus remain valid for
771 * the lifetime of this object.
772 */
773 auto &parameters = *parameters_.view();
774
775 parameters.gamma = 7. / 5.;
776 add_parameter("gamma", parameters.gamma, "The ratio of specific heats");
777
778 parameters.reference_density = 1.;
779 add_parameter("reference density",
780 parameters.reference_density,
781 "Problem specific density reference");
782
783 parameters.vacuum_state_relaxation_small = 1.e2;
784 add_parameter("vacuum state relaxation small",
785 parameters.vacuum_state_relaxation_small,
786 "Problem specific vacuum relaxation parameter");
787
788 parameters.vacuum_state_relaxation_large = 1.e4;
789 add_parameter("vacuum state relaxation large",
790 parameters.vacuum_state_relaxation_large,
791 "Problem specific vacuum relaxation parameter");
792
793 ParameterAcceptor::parse_parameters_call_back.connect(
794 [this] { update_parameters(); });
795
796 update_parameters();
797 }
798
799
800 inline void HyperbolicSystem::update_parameters()
801 {
802 auto &parameters = *parameters_.view();
803
804 /*
805 * Precompute a number of derived gamma coefficients that contain
806 * divisions:
807 */
808 const auto gamma = parameters.gamma;
809 parameters.gamma_inverse = 1. / gamma;
810 parameters.gamma_plus_one_inverse = 1. / (gamma + 1.);
811 parameters.gamma_minus_one_inverse = 1. / (gamma - 1.);
812 parameters.gamma_minus_one_over_gamma_plus_one =
813 (gamma - 1.) / (gamma + 1.);
814 }
815
816
817 template <typename MemorySpace, int dim, typename ScalarNumber>
819 const OfflineData<dim, ScalarNumber> &offline_data,
821 &state_vector,
822 const bool skip_constrained_dofs) const
823 {
824 const unsigned int n_internal = offline_data.n_locally_internal();
825 const unsigned int n_owned = offline_data.n_locally_owned();
826
827 const auto sparsity_simd_view =
828 offline_data.sparsity_pattern_simd().template view<MemorySpace>();
829
830 /* We only read the hyperbolic state vector: */
831 const auto U_view =
832 std::get<0>(std::as_const(state_vector)).template view<MemorySpace>();
833 const auto precomputed_view =
834 std::get<1>(state_vector).template view<MemorySpace>();
835
836 const auto hyperbolic_system_views =
837 make_select_view<dim, ScalarNumber, MemorySpace>(*this);
838
839 const auto body = [=](auto sentinel, unsigned int i) {
840 using T = decltype(sentinel);
842 using precomputed_type = typename View::precomputed_type;
843
844 const unsigned int row_length = sparsity_simd_view.row_length(i);
845 if (skip_constrained_dofs && row_length == 1)
846 return;
847
848 const auto view = hyperbolic_system_views.template view<T>();
849
850 const auto U_i = U_view.template read_tensor<T>(i);
851 const precomputed_type prec_i{view.specific_entropy(U_i),
852 view.harten_entropy(U_i)};
853 precomputed_view.template write_tensor<T>(prec_i, i);
854 };
855
856 loop<MemorySpace, ScalarNumber>(
857 "hyperbolic_kernel_01b", body, 0, n_internal, n_owned);
858 }
859
860
861 template <int dim, typename Number, typename MemorySpace>
862 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
867
868
869 template <int dim, typename Number, typename MemorySpace>
870 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
872 const Number &rho) const
873 {
874 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
875 const Number rho_cutoff_large =
876 reference_density() * vacuum_state_relaxation_large() * eps;
877
878 return ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
879 std::abs(rho), rho_cutoff_large, Number(0.), rho);
880 }
881
882
883 template <int dim, typename Number, typename MemorySpace>
884 DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor<1, dim, Number>
886 const state_type &U)
887 {
888 dealii::Tensor<1, dim, Number> result;
889 for (unsigned int i = 0; i < dim; ++i)
890 result[i] = U[1 + i];
891 return result;
892 }
893
894
895 template <int dim, typename Number, typename MemorySpace>
896 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
898 const state_type &U)
899 {
900 return U[1 + dim];
901 }
902
903
904 template <int dim, typename Number, typename MemorySpace>
905 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
907 const state_type &U)
908 {
909 /*
910 * rho e = (E - 1/2*m^2/rho)
911 */
912 const Number rho_inverse = ScalarNumber(1.) / density(U);
913 const auto m = momentum(U);
914 const Number E = total_energy(U);
915 return E - ScalarNumber(0.5) * m.norm_square() * rho_inverse;
916 }
917
918
919 template <int dim, typename Number, typename MemorySpace>
920 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
922 const state_type &U) -> state_type
923 {
924 /*
925 * With
926 * rho e = E - 1/2 |m|^2 / rho
927 * we get
928 * (rho e)' = (1/2m^2/rho^2, -m/rho , 1 )^T
929 */
930
931 const Number rho_inverse = ScalarNumber(1.) / density(U);
932 const auto u = momentum(U) * rho_inverse;
933
934 state_type result;
935
936 result[0] = ScalarNumber(0.5) * u.norm_square();
937 for (unsigned int i = 0; i < dim; ++i) {
938 result[1 + i] = -u[i];
939 }
940 result[dim + 1] = ScalarNumber(1.);
941
942 return result;
943 }
944
945
946 template <int dim, typename Number, typename MemorySpace>
947 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
949 const state_type &U) const
950 {
951 /* p = (gamma - 1) * (rho e) */
952 return (gamma() - ScalarNumber(1.)) * internal_energy(U);
953 }
954
955
956 template <int dim, typename Number, typename MemorySpace>
957 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
959 const state_type &U) const
960 {
961 /* c^2 = gamma * p / rho */
962 const Number rho_inverse = ScalarNumber(1.) / density(U);
963 const Number p = pressure(U);
964 return std::sqrt(gamma() * p * rho_inverse);
965 }
966
967
968 template <int dim, typename Number, typename MemorySpace>
969 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
971 const state_type &U) const
972 {
973 /* exp((gamma - 1)s) = (rho e) / rho ^ gamma */
974 const auto rho_inverse = ScalarNumber(1.) / density(U);
975 return internal_energy(U) * ryujin::pow(rho_inverse, gamma());
976 }
977
978
979 template <int dim, typename Number, typename MemorySpace>
980 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
982 const state_type &U) const
983 {
984 /* rho^2 e = \rho E - 1/2*m^2 */
985
986 const Number rho = density(U);
987 const auto m = momentum(U);
988 const Number E = total_energy(U);
989
990 const Number rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
991 return ryujin::pow(rho_rho_e, gamma_plus_one_inverse());
992 }
993
994
995 template <int dim, typename Number, typename MemorySpace>
996 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
998 const state_type &U) const -> state_type
999 {
1000 /*
1001 * With
1002 * eta = (rho^2 e) ^ 1/(gamma+1)
1003 * rho^2 e = rho * E - 1/2 |m|^2
1004 *
1005 * we get
1006 *
1007 * eta' = 1/(gamma+1) * (rho^2 e) ^ -gamma/(gamma+1) * (E,-m,rho)^T
1008 *
1009 */
1010
1011 const Number rho = density(U);
1012 const auto m = momentum(U);
1013 const Number E = total_energy(U);
1014
1015 const Number rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
1016
1017 const auto factor =
1018 gamma_plus_one_inverse() *
1019 ryujin::pow(rho_rho_e, -gamma() * gamma_plus_one_inverse());
1020
1021 state_type result;
1022
1023 result[0] = factor * E;
1024 for (unsigned int i = 0; i < dim; ++i)
1025 result[1 + i] = -factor * m[i];
1026 result[dim + 1] = factor * rho;
1027
1028 return result;
1029 }
1030
1031
1032 template <int dim, typename Number, typename MemorySpace>
1033 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
1035 const state_type &U) const
1036 {
1038 const auto p = pressure(U);
1039 return ryujin::pow(p, gamma_inverse());
1040 }
1041
1042
1043 template <int dim, typename Number, typename MemorySpace>
1044 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1047 {
1048 /*
1049 * With
1050 * eta = p ^ (1/gamma)
1051 * p = (gamma - 1) * (rho e)
1052 * rho e = E - 1/2 |m|^2 / rho
1053 *
1054 * we get
1055 *
1056 * eta' = (gamma - 1)/gamma p ^(1/gamma - 1) *
1057 *
1058 * (1/2m^2/rho^2 , -m/rho , 1 )^T
1059 */
1060 const Number rho = density(U);
1061 const Number rho_inverse = ScalarNumber(1.) / rho;
1062 const auto u = momentum(U) * rho_inverse;
1063 const auto p = pressure(U);
1064
1065 const auto factor = (gamma() - ScalarNumber(1.0)) * gamma_inverse() *
1066 ryujin::pow(p, gamma_inverse() - ScalarNumber(1.));
1067
1068 state_type result;
1069
1070 result[0] = factor * ScalarNumber(0.5) * u.norm_square();
1071 result[dim + 1] = factor;
1072 for (unsigned int i = 0; i < dim; ++i) {
1073 result[1 + i] = -factor * u[i];
1074 }
1075
1076 return result;
1077 }
1078
1079
1080 template <int dim, typename Number, typename MemorySpace>
1081 DEAL_II_HOST_DEVICE_ALWAYS_INLINE bool
1083 const state_type &U) const
1084 {
1085 const auto rho_new = density(U);
1086 const auto e_new = internal_energy(U);
1087 const auto s_new = specific_entropy(U);
1088
1089 constexpr auto gt = dealii::SIMDComparison::greater_than;
1090 using T = Number;
1091 const auto test =
1092 ryujin::compare_and_apply_mask<gt>(rho_new, T(0.), T(0.), T(-1.)) + //
1093 ryujin::compare_and_apply_mask<gt>(e_new, T(0.), T(0.), T(-1.)) + //
1094 ryujin::compare_and_apply_mask<gt>(s_new, T(0.), T(0.), T(-1.));
1095
1096#ifdef DEBUG_OUTPUT
1097 if (!(test == Number(0.))) {
1098 std::cout << std::fixed << std::setprecision(16);
1099 std::cout << "Bounds violation: Negative state [rho, e, s] detected!\n";
1100 std::cout << "\t\trho: " << rho_new << "\n";
1101 std::cout << "\t\tint: " << e_new << "\n";
1102 std::cout << "\t\tent: " << s_new << "\n" << std::endl;
1103 }
1104#endif
1105
1106 return (test == Number(0.));
1107 }
1108
1109
1110 template <int dim, typename Number, typename MemorySpace>
1111 template <int component>
1112 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1114 const state_type &U, const dealii::Tensor<1, dim, Number> &normal) const
1115 -> std::array<state_type, 2>
1116 {
1117 static_assert(component == 1 || component == problem_dimension,
1118 "Only first and last eigenvectors implemented");
1119
1120 const auto rho = density(U);
1121 const auto m = momentum(U);
1122 const auto v = m / rho;
1123 const auto a = speed_of_sound(U);
1124 const auto gamma = this->gamma();
1125
1126 state_type b;
1127 state_type c;
1128
1129 const auto e_k = 0.5 * v.norm_square();
1130
1131 switch (component) {
1132 case 1:
1133 b[0] = (gamma - 1.) * e_k + a * v * normal;
1134 for (unsigned int i = 0; i < dim; ++i)
1135 b[1 + i] = (1. - gamma) * v[i] - a * normal[i];
1136 b[dim + 1] = gamma - 1.;
1137 b /= 2. * a * a;
1138
1139 c[0] = 1.;
1140 for (unsigned int i = 0; i < dim; ++i)
1141 c[1 + i] = v[i] - a * normal[i];
1142 c[dim + 1] = a * a / (gamma - 1) + e_k - a * (v * normal);
1143
1144 return {b, c};
1145
1146 case problem_dimension:
1147 b[0] = (gamma - 1.) * e_k - a * v * normal;
1148 for (unsigned int i = 0; i < dim; ++i)
1149 b[1 + i] = (1. - gamma) * v[i] + a * normal[i];
1150 b[dim + 1] = gamma - 1.;
1151 b /= 2. * a * a;
1152
1153 c[0] = 1.;
1154 for (unsigned int i = 0; i < dim; ++i)
1155 c[1 + i] = v[i] + a * normal[i];
1156 c[dim + 1] = a * a / (gamma - 1) + e_k + a * (v * normal);
1157
1158 return {b, c};
1159 }
1160
1161 __builtin_unreachable();
1162 }
1163
1164
1165 template <int dim, typename Number, typename MemorySpace>
1166 template <int component>
1167 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1170 const state_type &U,
1171 const state_type &U_bar,
1172 const dealii::Tensor<1, dim, Number> &normal) const -> state_type
1173 {
1174 static_assert(component == 1 || component == 2,
1175 "component has to be 1 or 2");
1176
1177 const auto m = momentum(U);
1178 const auto rho = density(U);
1179 const auto a = speed_of_sound(U);
1180 const auto vn = m * normal / rho;
1181
1182 const auto m_bar = momentum(U_bar);
1183 const auto rho_bar = density(U_bar);
1184 const auto a_bar = speed_of_sound(U_bar);
1185 const auto vn_bar = m_bar * normal / rho_bar;
1186
1187 /* First Riemann characteristic: v* n - 2 / (gamma - 1) * a */
1188
1189 const auto R_1 = component == 1
1190 ? vn_bar - 2. * a_bar / (gamma() - ScalarNumber(1.))
1191 : vn - 2. * a / (gamma() - ScalarNumber(1.));
1192
1193 /* Second Riemann characteristic: v* n + 2 / (gamma() - 1) * a */
1194
1195 const auto R_2 = component == 2
1196 ? vn_bar + 2. * a_bar / (gamma() - ScalarNumber(1.))
1197 : vn + 2. * a / (gamma() - ScalarNumber(1.));
1198
1199 const auto p = pressure(U);
1200 const auto s = p / ryujin::pow(rho, gamma());
1201
1202 const auto vperp = m / rho - vn * normal;
1203
1204 const auto vn_new = 0.5 * (R_1 + R_2);
1205
1206 auto rho_new = 1. / (gamma() * s) *
1207 ryujin::fixed_power<2>(ScalarNumber((gamma() - 1.) / 4.) *
1208 (R_2 - R_1));
1209 rho_new = ryujin::pow(rho_new, 1. / (gamma() - 1.));
1210
1211 const auto p_new = s * std::pow(rho_new, gamma());
1212
1213 state_type U_new;
1214 U_new[0] = rho_new;
1215 for (unsigned int d = 0; d < dim; ++d) {
1216 U_new[1 + d] = rho_new * (vn_new * normal + vperp)[d];
1217 }
1218 U_new[1 + dim] = p_new / ScalarNumber(gamma() - 1.) +
1219 0.5 * rho_new * (vn_new * vn_new + vperp.norm_square());
1220
1221 return U_new;
1222 }
1223
1224
1225 template <int dim, typename Number, typename MemorySpace>
1226 template <typename Lambda>
1227 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1229 dealii::types::boundary_id id,
1230 const state_type &U,
1231 const dealii::Tensor<1, dim, Number> &normal,
1232 const Lambda &get_dirichlet_data) const -> state_type
1233 {
1234 state_type result = U;
1235
1236 if (id == Boundary::dirichlet) {
1237 result = get_dirichlet_data();
1238
1239 } else if (id == Boundary::dirichlet_momentum) {
1240 /*
1241 * Only enforce Dirichlet conditions on the momentum, and keep the
1242 * internal energy constant:
1243 */
1244 const auto m_dirichlet = momentum(get_dirichlet_data());
1245 const auto rho = density(result);
1246 const auto m = momentum(result);
1247
1248 for (unsigned int k = 0; k < dim; ++k)
1249 result[k + 1] = m_dirichlet[k];
1250 result[dim + 1] +=
1251 Number(0.5) / rho * (m_dirichlet.norm_square() - m.norm_square());
1252
1253 } else if (id == Boundary::dirichlet_velocity) {
1254 /*
1255 * Only enforce Dirichlet conditions on the velocity, and keep the
1256 * internal energy constant:
1257 */
1258 const auto U_dirichlet = get_dirichlet_data();
1259 const auto rho_dirichlet = density(U_dirichlet);
1260 const auto v_dirichlet = momentum(U_dirichlet) / rho_dirichlet;
1261 const auto rho = density(result);
1262 const auto v = momentum(result) / rho;
1263
1264 for (unsigned int k = 0; k < dim; ++k)
1265 result[k + 1] = rho * v_dirichlet[k];
1266 result[dim + 1] +=
1267 Number(0.5) * rho * (v_dirichlet.norm_square() - v.norm_square());
1268
1269 } else if (id == Boundary::slip) {
1270 auto m = momentum(U);
1271 m -= 1. * (m * normal) * normal;
1272 for (unsigned int k = 0; k < dim; ++k)
1273 result[k + 1] = m[k];
1274
1275 } else if (id == Boundary::no_slip) {
1276 for (unsigned int k = 0; k < dim; ++k)
1277 result[k + 1] = Number(0.);
1278
1279 } else if (id == Boundary::dynamic) {
1280 /*
1281 * On dynamic boundary conditions, we distinguish four cases:
1282 *
1283 * - supersonic inflow: prescribe full state
1284 * - subsonic inflow:
1285 * decompose into Riemann invariants and leave R_2
1286 * characteristic untouched.
1287 * - supersonic outflow: do nothing
1288 * - subsonic outflow:
1289 * decompose into Riemann invariants and prescribe incoming
1290 * R_1 characteristic.
1291 */
1292 const auto m = momentum(U);
1293 const auto rho = density(U);
1294 const auto a = speed_of_sound(U);
1295 const auto vn = m * normal / rho;
1296
1297 /* Supersonic inflow: */
1298 if (vn < -a) {
1299 result = get_dirichlet_data();
1300 }
1301
1302 /* Subsonic inflow: */
1303 if (vn >= -a && vn <= 0.) {
1304 const auto U_dirichlet = get_dirichlet_data();
1305 result = prescribe_riemann_characteristic<2>(U_dirichlet, U, normal);
1306 }
1307
1308 /* Subsonic outflow: */
1309 if (vn > 0. && vn <= a) {
1310 const auto U_dirichlet = get_dirichlet_data();
1311 result = prescribe_riemann_characteristic<1>(U, U_dirichlet, normal);
1312 }
1313
1314 /* Supersonic outflow: do nothing, i.e., keep U as is */
1315
1316 } else {
1317 Assert(false, dealii::ExcNotImplemented());
1318 }
1319
1320 return result;
1321 }
1322
1323
1324 template <int dim, typename Number, typename MemorySpace>
1325 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1327 -> flux_type
1328 {
1329 const auto rho_inverse = ScalarNumber(1.) / density(U);
1330 const auto m = momentum(U);
1331 const auto p = pressure(U);
1332 const auto E = total_energy(U);
1333
1334 flux_type result;
1335
1336 result[0] = m;
1337 for (unsigned int i = 0; i < dim; ++i) {
1338 result[1 + i] = m * (m[i] * rho_inverse);
1339 result[1 + i][i] += p;
1340 }
1341 result[dim + 1] = m * (rho_inverse * (E + p));
1342
1343 return result;
1344 }
1345
1346
1347 template <int dim, typename Number, typename MemorySpace>
1348 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1350 const PrecomputedVectorView & /*pv*/,
1351 const InitialPrecomputedVectorView & /*ipv*/,
1352 const unsigned int /*i*/,
1353 const state_type &U_i) const -> flux_contribution_type
1354 {
1355 return f(U_i);
1356 }
1357
1358
1359 template <int dim, typename Number, typename MemorySpace>
1360 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1362 const PrecomputedVectorView & /*pv*/,
1363 const InitialPrecomputedVectorView & /*ipv*/,
1364 const unsigned int * /*js*/,
1365 const state_type &U_j) const -> flux_contribution_type
1366 {
1367 return f(U_j);
1368 }
1369
1370
1371 template <int dim, typename Number, typename MemorySpace>
1372 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1374 const flux_contribution_type &flux_i,
1375 const flux_contribution_type &flux_j,
1376 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
1377 {
1378 return -contract(add(flux_i, flux_j), c_ij);
1379 }
1380
1381
1382 template <int dim, typename Number, typename MemorySpace>
1383 template <typename ST>
1384 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1386 const ST &state) const -> state_type
1387 {
1388 using T = typename ST::value_type;
1389 static_assert(std::is_same_v<Number, T>, "template mismatch");
1390
1391 constexpr auto dim2 = ST::dimension - 2;
1392 static_assert(dim >= dim2,
1393 "the space dimension of the argument state must not be "
1394 "larger than the one of the target state");
1395
1396 state_type result;
1397 result[0] = state[0];
1398 result[dim + 1] = state[dim2 + 1];
1399 for (unsigned int i = 1; i < dim2 + 1; ++i)
1400 result[i] = state[i];
1401
1402 return result;
1403 }
1404
1405
1406 template <int dim, typename Number, typename MemorySpace>
1407 template <typename ST>
1408 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1410 const ST &initial_state) const -> state_type
1411 {
1412 const auto primitive_state = expand_state(initial_state);
1413 return from_primitive_state(primitive_state);
1414 }
1415
1416
1417 template <int dim, typename Number, typename MemorySpace>
1418 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1420 const state_type &primitive_state) const -> state_type
1421 {
1422 const auto &rho = primitive_state[0];
1423 /* extract velocity: */
1424 const auto u = /*SIC!*/ momentum(primitive_state);
1425 const auto &p = primitive_state[dim + 1];
1426
1427 auto state = primitive_state;
1428 /* Fix up momentum: */
1429 for (unsigned int i = 1; i < dim + 1; ++i)
1430 state[i] *= rho;
1431 /* Compute total energy: */
1432 state[dim + 1] =
1433 p / (ScalarNumber(gamma() - 1.)) + Number(0.5) * rho * u * u;
1434
1435 return state;
1436 }
1437
1438
1439 template <int dim, typename Number, typename MemorySpace>
1440 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1442 const state_type &state) const -> state_type
1443 {
1444 const auto &rho = state[0];
1445 const auto rho_inverse = Number(1.) / rho;
1446 const auto p = pressure(state);
1447
1448 auto primitive_state = state;
1449 /* Fix up velocity: */
1450 for (unsigned int i = 1; i < dim + 1; ++i)
1451 primitive_state[i] *= rho_inverse;
1452 /* Set pressure: */
1453 primitive_state[dim + 1] = p;
1454
1455 return primitive_state;
1456 }
1457
1458
1459 template <int dim, typename Number, typename MemorySpace>
1460 template <typename Lambda>
1461 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1463 const state_type &state, const Lambda &lambda) const -> state_type
1464 {
1465 auto result = state;
1466 const auto M = lambda(momentum(state));
1467 for (unsigned int d = 0; d < dim; ++d)
1468 result[1 + d] = M[d];
1469 return result;
1470 }
1471
1472 } // namespace Euler
1473} // namespace ryujin
static constexpr bool have_covolume_constant
DEAL_II_HOST_DEVICE state_type mathematical_entropy_derivative(const state_type &U) const
DEAL_II_HOST_DEVICE Number filter_vacuum_density(const Number &rho) const
DEAL_II_HOST_DEVICE state_type apply_galilei_transform(const state_type &state, const Lambda &lambda) const
DEAL_II_HOST_DEVICE Number pressure(const state_type &U) const
DEAL_II_HOST_DEVICE state_type from_primitive_state(const state_type &primitive_state) const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma_minus_one_inverse() const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber reference_density() const
DEAL_II_HOST_DEVICE state_type prescribe_riemann_characteristic(const state_type &U, const state_type &U_bar, const dealii::Tensor< 1, dim, Number > &normal) const
DEAL_II_HOST_DEVICE state_type from_initial_state(const ST &initial_state) const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE 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
DEAL_II_HOST_DEVICE 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_HOST_DEVICE_ALWAYS_INLINE ScalarNumber vacuum_state_relaxation_large() const
DEAL_II_HOST_DEVICE std::array< state_type, 2 > linearized_eigenvector(const state_type &U, const dealii::Tensor< 1, dim, Number > &normal) const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma_minus_one_over_gamma_plus_one() const
dealii::Tensor< 1, problem_dimension, Number > state_type
DEAL_II_HOST_DEVICE Number mathematical_entropy(const state_type &U) const
DEAL_II_HOST_DEVICE bool is_admissible(const state_type &U) const
DEAL_II_HOST_DEVICE state_type nodal_source(const PrecomputedVectorView &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const =delete
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma_inverse() const
std::array< Number, n_precomputed_values > precomputed_type
DEAL_II_HOST_DEVICE flux_contribution_type flux_contribution(const PrecomputedVectorView &pv, const InitialPrecomputedVectorView &ipv, const unsigned int i, const state_type &U_i) const
static DEAL_II_HOST_DEVICE dealii::Tensor< 1, dim, Number > momentum(const state_type &U)
DEAL_II_HOST_DEVICE state_type harten_entropy_derivative(const state_type &U) const
HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
static DEAL_II_HOST_DEVICE Number density(const state_type &U)
DEAL_II_HOST_DEVICE flux_type f(const state_type &U) const
static constexpr unsigned int problem_dimension
DEAL_II_HOST_DEVICE state_type nodal_source(const PrecomputedVectorView &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
DEAL_II_HOST_DEVICE Number speed_of_sound(const state_type &U) const
DEAL_II_HOST_DEVICE state_type expand_state(const ST &state) const
static DEAL_II_HOST_DEVICE Number internal_energy(const state_type &U)
Vectors::StateVector< ScalarNumber, problem_dimension, n_precomputed_values > StateVector
static constexpr unsigned int n_precomputed_values
static DEAL_II_HOST_DEVICE state_type internal_energy_derivative(const state_type &U)
typename get_value_type< Number >::type ScalarNumber
dealii::Tensor< 1, problem_dimension, dealii::Tensor< 1, dim, Number > > flux_type
DEAL_II_HOST_DEVICE 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_initial_precomputed_values > initial_precomputed_type
DEAL_II_HOST_DEVICE state_type to_primitive_state(const state_type &state) const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma() const
DEAL_II_HOST_DEVICE Number harten_entropy(const state_type &U) const
static DEAL_II_HOST_DEVICE Number total_energy(const state_type &U)
DEAL_II_HOST_DEVICE Number specific_entropy(const state_type &U) const
static constexpr unsigned int n_initial_precomputed_values
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber vacuum_state_relaxation_small() const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma_plus_one_inverse() const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
static const std::string problem_name
void fill_precomputed_values(const OfflineData< dim, ScalarNumber > &offline_data, typename HyperbolicSystemView< dim, ScalarNumber >::StateVector &state_vector, const bool skip_constrained_dofs=true) const
const auto & n_locally_owned() const
const auto & sparsity_pattern_simd() const
const auto & n_locally_internal() const
TransferPolicy
Definition gpu.h:88
@ dirichlet_momentum
@ dirichlet_velocity
DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor< 1, problem_dim, T > contract(const FT &flux_ij, const TT &c_ij)
DEAL_II_HOST_DEVICE_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)
DEAL_II_HOST_DEVICE T pow(const T x, const T b)