ryujin 2.5.0 revision c64172211cf21344cb9b9b0f3a1266aa6400d392
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 <ryujin/base/compile_time_options.h>
10#include <ryujin/base/gpu.h>
11#include <ryujin/base/loop.h>
13#include <ryujin/base/simd.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
45 {
46 public:
82
86 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
87
93 template <int dim,
94 typename Number = double,
95 typename MemorySpace = dealii::MemorySpace::Host>
97
105 template <int dim,
106 typename Number,
107 typename MemorySpace = dealii::MemorySpace::Host>
108 auto view() const
109 {
110 return View<dim, Number, MemorySpace>{*this};
111 }
112
121 template <typename MemorySpace = dealii::MemorySpace::Host,
122 int dim,
123 typename ScalarNumber>
125 const OfflineData<dim, ScalarNumber> &offline_data,
126 StateVector<ScalarNumber> &state_vector,
127 const bool skip_constrained_dofs = true) const;
128
129 private:
134
139 void update_parameters();
140
141 Mirrored<Parameters> parameters_;
142
143 template <int, typename, typename>
145
147 }; /* HyperbolicSystem */
148
149
171 template <int dim, typename Number, typename MemorySpace>
173 {
174 public:
175 static_assert(
176 std::is_same_v<MemorySpace, dealii::MemorySpace::Host> ||
177 std::is_same_v<MemorySpace, dealii::MemorySpace::Default>,
178 "Unexpected memory space");
179
184
189
193 static constexpr unsigned int problem_dimension = 2 + dim;
194
198 using state_type = dealii::Tensor<1, problem_dimension, Number>;
199
203 using flux_type =
204 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
205
210
214 static constexpr unsigned int n_precomputed_values = 2;
215
219 using precomputed_type = std::array<Number, n_precomputed_values>;
220
224 static constexpr unsigned int n_initial_precomputed_values = 0;
225
230 std::array<Number, n_initial_precomputed_values>;
231
232 template <int n_comp>
235
241
248
250
254
259 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
260 : parameters_(
261 hyperbolic_system.parameters_.template view<MemorySpace>())
262 {
263 }
264
266
270
271 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma() const
272 {
273 return ScalarNumber(parameters_->gamma);
274 }
275
276 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber reference_density() const
277 {
278 return ScalarNumber(parameters_->reference_density);
279 }
280
281 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
283 {
284 return ScalarNumber(parameters_->vacuum_state_relaxation_small);
285 }
286
287 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
289 {
290 return ScalarNumber(parameters_->vacuum_state_relaxation_large);
291 }
292
294
302
303 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber gamma_inverse() const
304 {
305 return ScalarNumber(parameters_->gamma_inverse);
306 }
307
308 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
310 {
311 return ScalarNumber(parameters_->gamma_plus_one_inverse);
312 }
313
314 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
316 {
317 return ScalarNumber(parameters_->gamma_minus_one_inverse);
318 }
319
320 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
325
327
331
332 static constexpr bool have_gamma = true;
333 static constexpr bool have_covolume_constant = false;
334 static constexpr bool have_energy_equation = true;
335
337
341
346 static DEAL_II_HOST_DEVICE Number density(const state_type &U);
347
354 DEAL_II_HOST_DEVICE Number filter_vacuum_density(const Number &rho) const;
355
360 static DEAL_II_HOST_DEVICE dealii::Tensor<1, dim, Number>
361 momentum(const state_type &U);
362
367 static DEAL_II_HOST_DEVICE Number total_energy(const state_type &U);
368
373 static DEAL_II_HOST_DEVICE Number internal_energy(const state_type &U);
374
380 static DEAL_II_HOST_DEVICE state_type
382
393 DEAL_II_HOST_DEVICE Number pressure(const state_type &U) const;
394
402 DEAL_II_HOST_DEVICE Number speed_of_sound(const state_type &U) const;
403
411 DEAL_II_HOST_DEVICE Number specific_entropy(const state_type &U) const;
412
420 DEAL_II_HOST_DEVICE Number harten_entropy(const state_type &U) const;
421
429 DEAL_II_HOST_DEVICE state_type
431
436 DEAL_II_HOST_DEVICE Number
437 mathematical_entropy(const state_type &U) const;
438
444 DEAL_II_HOST_DEVICE state_type
446
452 DEAL_II_HOST_DEVICE bool is_admissible(const state_type &U) const;
453
455
459
465 template <int component>
466 DEAL_II_HOST_DEVICE std::array<state_type, 2> linearized_eigenvector(
467 const state_type &U,
468 const dealii::Tensor<1, dim, Number> &normal) const;
469
476 template <int component>
478 const state_type &U,
479 const state_type &U_bar,
480 const dealii::Tensor<1, dim, Number> &normal) const;
481
500 template <typename Lambda>
501 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type
502 apply_boundary_conditions(const dealii::types::boundary_id id,
503 const state_type &U,
504 const dealii::Tensor<1, dim, Number> &normal,
505 const Lambda &get_dirichlet_data) const;
506
508
512
523 DEAL_II_HOST_DEVICE flux_type f(const state_type &U) const;
524
544 DEAL_II_HOST_DEVICE
548 const unsigned int i,
549 const state_type &U_i) const;
550
551 DEAL_II_HOST_DEVICE
555 const unsigned int *js,
556 const state_type &U_j) const;
557
562 DEAL_II_HOST_DEVICE
565 const flux_contribution_type &flux_j,
566 const dealii::Tensor<1, dim, Number> &c_ij) const;
567
569 static constexpr bool have_high_order_flux = false;
570
571 DEAL_II_HOST_DEVICE
573 const flux_contribution_type &flux_i,
574 const flux_contribution_type &flux_j,
575 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
576
578
582
584 static constexpr bool have_source_terms = false;
585
586 DEAL_II_HOST_DEVICE
588 const unsigned int i,
589 const state_type &U_i,
590 const ScalarNumber tau) const = delete;
591
592 DEAL_II_HOST_DEVICE
594 const unsigned int *js,
595 const state_type &U_j,
596 const ScalarNumber tau) const = delete;
597
599
603
614 template <typename ST>
615 DEAL_II_HOST_DEVICE state_type expand_state(const ST &state) const;
616
630 template <typename ST>
631 DEAL_II_HOST_DEVICE state_type
632 from_initial_state(const ST &initial_state) const;
633
638 DEAL_II_HOST_DEVICE
639 state_type from_primitive_state(const state_type &primitive_state) const;
640
645 DEAL_II_HOST_DEVICE
647
653 template <typename Lambda>
655 const state_type &state, const Lambda &lambda) const;
656
657 private:
659
663
664 const HyperbolicSystem::Parameters *const parameters_;
665
667 }; /* HyperbolicSystemView */
668
669
670 /*
671 * -------------------------------------------------------------------------
672 * Inline definitions
673 * -------------------------------------------------------------------------
674 */
675
676 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
677 : Interface::HyperbolicSystem(
678 "Compressible Euler equations (polytropic gas EOS, optimized)",
679 {{{"rho", "m", "E"},
680 {"rho", "m_1", "m_2", "E"},
681 {"rho", "m_1", "m_2", "m_3", "E"}}},
682 {{{"rho", "v", "p"},
683 {"rho", "v_1", "v_2", "p"},
684 {"rho", "v_1", "v_2", "v_3", "p"}}},
685 {{{"s", "eta_h"}, {"s", "eta_h"}, {"s", "eta_h"}}},
686 {},
687 subsection)
688 , parameters_("euler_hyperbolic_system_parameters",
690 {
691 /* reference remains valid due to implicit_transfers_host_resident */
692 auto &parameters = *parameters_.view();
693
694 parameters.gamma = 7. / 5.;
695 add_parameter("gamma", parameters.gamma, "The ratio of specific heats");
696
697 parameters.reference_density = 1.;
698 add_parameter("reference density",
699 parameters.reference_density,
700 "Problem specific density reference");
701
702 parameters.vacuum_state_relaxation_small = 1.e2;
703 add_parameter("vacuum state relaxation small",
704 parameters.vacuum_state_relaxation_small,
705 "Problem specific vacuum relaxation parameter");
706
707 parameters.vacuum_state_relaxation_large = 1.e4;
708 add_parameter("vacuum state relaxation large",
709 parameters.vacuum_state_relaxation_large,
710 "Problem specific vacuum relaxation parameter");
711
712 ParameterAcceptor::parse_parameters_call_back.connect(
713 [this] { update_parameters(); });
714
715 update_parameters();
716 }
717
718
719 inline void HyperbolicSystem::update_parameters()
720 {
721 auto &parameters = *parameters_.view();
722
723 /*
724 * Precompute a number of derived gamma coefficients that contain
725 * divisions:
726 */
727 const auto gamma = parameters.gamma;
728 parameters.gamma_inverse = 1. / gamma;
729 parameters.gamma_plus_one_inverse = 1. / (gamma + 1.);
730 parameters.gamma_minus_one_inverse = 1. / (gamma - 1.);
731 parameters.gamma_minus_one_over_gamma_plus_one =
732 (gamma - 1.) / (gamma + 1.);
733 }
734
735
736 template <typename MemorySpace, int dim, typename ScalarNumber>
738 const OfflineData<dim, ScalarNumber> &offline_data,
739 StateVector<ScalarNumber> &state_vector,
740 const bool skip_constrained_dofs) const
741 {
742 const unsigned int n_internal = offline_data.n_locally_internal();
743 const unsigned int n_owned = offline_data.n_locally_owned();
744
746
747 const auto sparsity_simd_view =
748 offline_data.sparsity_pattern_simd().template view<MemorySpace>();
749
750 /* We only read the hyperbolic state vector: */
751 const auto U_view =
752 std::as_const(state_vector)
753 .state
754 .template view<ScalarView::problem_dimension, MemorySpace>();
755 const auto precomputed_view =
756 state_vector.precomputed
757 .template view<ScalarView::n_precomputed_values, MemorySpace>();
758
759 const auto hyperbolic_system_views =
760 make_select_view<dim, ScalarNumber, MemorySpace>(*this);
761
762 const auto body = [=](auto sentinel, unsigned int i) {
763 using T = decltype(sentinel);
765 using precomputed_type = typename View::precomputed_type;
766
767 const unsigned int row_length = sparsity_simd_view.row_length(i);
768 if (skip_constrained_dofs && row_length == 1)
769 return;
770
771 const auto view = hyperbolic_system_views.template view<T>();
772
773 const auto U_i = U_view.template read_tensor<T>(i);
774 const precomputed_type prec_i{view.specific_entropy(U_i),
775 view.harten_entropy(U_i)};
776 precomputed_view.template write_tensor<T>(prec_i, i);
777 };
778
779 loop<MemorySpace, ScalarNumber>(
780 "hyperbolic_kernel_01b", body, 0, n_internal, n_owned);
781 }
782
783
784 template <int dim, typename Number, typename MemorySpace>
785 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
790
791
792 template <int dim, typename Number, typename MemorySpace>
793 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
795 const Number &rho) const
796 {
797 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
798 const Number rho_cutoff_large =
799 reference_density() * vacuum_state_relaxation_large() * eps;
800
801 return ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
802 std::abs(rho), rho_cutoff_large, Number(0.), rho);
803 }
804
805
806 template <int dim, typename Number, typename MemorySpace>
807 DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor<1, dim, Number>
809 const state_type &U)
810 {
811 dealii::Tensor<1, dim, Number> result;
812 for (unsigned int i = 0; i < dim; ++i)
813 result[i] = U[1 + i];
814 return result;
815 }
816
817
818 template <int dim, typename Number, typename MemorySpace>
819 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
821 const state_type &U)
822 {
823 return U[1 + dim];
824 }
825
826
827 template <int dim, typename Number, typename MemorySpace>
828 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
830 const state_type &U)
831 {
832 /*
833 * rho e = (E - 1/2*m^2/rho)
834 */
835 const Number rho_inverse = ScalarNumber(1.) / density(U);
836 const auto m = momentum(U);
837 const Number E = total_energy(U);
838 return E - ScalarNumber(0.5) * m.norm_square() * rho_inverse;
839 }
840
841
842 template <int dim, typename Number, typename MemorySpace>
843 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
845 const state_type &U) -> state_type
846 {
847 /*
848 * With
849 * rho e = E - 1/2 |m|^2 / rho
850 * we get
851 * (rho e)' = (1/2m^2/rho^2, -m/rho , 1 )^T
852 */
853
854 const Number rho_inverse = ScalarNumber(1.) / density(U);
855 const auto u = momentum(U) * rho_inverse;
856
857 state_type result;
858
859 result[0] = ScalarNumber(0.5) * u.norm_square();
860 for (unsigned int i = 0; i < dim; ++i) {
861 result[1 + i] = -u[i];
862 }
863 result[dim + 1] = ScalarNumber(1.);
864
865 return result;
866 }
867
868
869 template <int dim, typename Number, typename MemorySpace>
870 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
872 const state_type &U) const
873 {
874 /* p = (gamma - 1) * (rho e) */
875 return (gamma() - ScalarNumber(1.)) * internal_energy(U);
876 }
877
878
879 template <int dim, typename Number, typename MemorySpace>
880 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
882 const state_type &U) const
883 {
884 /* c^2 = gamma * p / rho */
885 const Number rho_inverse = ScalarNumber(1.) / density(U);
886 const Number p = pressure(U);
887 return std::sqrt(gamma() * p * rho_inverse);
888 }
889
890
891 template <int dim, typename Number, typename MemorySpace>
892 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
894 const state_type &U) const
895 {
896 /* exp((gamma - 1)s) = (rho e) / rho ^ gamma */
897 const auto rho_inverse = ScalarNumber(1.) / density(U);
898 return internal_energy(U) * ryujin::pow(rho_inverse, gamma());
899 }
900
901
902 template <int dim, typename Number, typename MemorySpace>
903 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
905 const state_type &U) const
906 {
907 /* rho^2 e = \rho E - 1/2*m^2 */
908
909 const Number rho = density(U);
910 const auto m = momentum(U);
911 const Number E = total_energy(U);
912
913 const Number rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
914 return ryujin::pow(rho_rho_e, gamma_plus_one_inverse());
915 }
916
917
918 template <int dim, typename Number, typename MemorySpace>
919 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
921 const state_type &U) const -> state_type
922 {
923 /*
924 * With
925 * eta = (rho^2 e) ^ 1/(gamma+1)
926 * rho^2 e = rho * E - 1/2 |m|^2
927 *
928 * we get
929 *
930 * eta' = 1/(gamma+1) * (rho^2 e) ^ -gamma/(gamma+1) * (E,-m,rho)^T
931 *
932 */
933
934 const Number rho = density(U);
935 const auto m = momentum(U);
936 const Number E = total_energy(U);
937
938 const Number rho_rho_e = rho * E - ScalarNumber(0.5) * m.norm_square();
939
940 const auto factor =
941 gamma_plus_one_inverse() *
942 ryujin::pow(rho_rho_e, -gamma() * gamma_plus_one_inverse());
943
944 state_type result;
945
946 result[0] = factor * E;
947 for (unsigned int i = 0; i < dim; ++i)
948 result[1 + i] = -factor * m[i];
949 result[dim + 1] = factor * rho;
950
951 return result;
952 }
953
954
955 template <int dim, typename Number, typename MemorySpace>
956 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
958 const state_type &U) const
959 {
961 const auto p = pressure(U);
962 return ryujin::pow(p, gamma_inverse());
963 }
964
965
966 template <int dim, typename Number, typename MemorySpace>
967 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
970 {
971 /*
972 * With
973 * eta = p ^ (1/gamma)
974 * p = (gamma - 1) * (rho e)
975 * rho e = E - 1/2 |m|^2 / rho
976 *
977 * we get
978 *
979 * eta' = (gamma - 1)/gamma p ^(1/gamma - 1) *
980 *
981 * (1/2m^2/rho^2 , -m/rho , 1 )^T
982 */
983 const Number rho = density(U);
984 const Number rho_inverse = ScalarNumber(1.) / rho;
985 const auto u = momentum(U) * rho_inverse;
986 const auto p = pressure(U);
987
988 const auto factor = (gamma() - ScalarNumber(1.0)) * gamma_inverse() *
989 ryujin::pow(p, gamma_inverse() - ScalarNumber(1.));
990
991 state_type result;
992
993 result[0] = factor * ScalarNumber(0.5) * u.norm_square();
994 result[dim + 1] = factor;
995 for (unsigned int i = 0; i < dim; ++i) {
996 result[1 + i] = -factor * u[i];
997 }
998
999 return result;
1000 }
1001
1002
1003 template <int dim, typename Number, typename MemorySpace>
1004 DEAL_II_HOST_DEVICE_ALWAYS_INLINE bool
1006 const state_type &U) const
1007 {
1008 const auto rho_new = density(U);
1009 const auto e_new = internal_energy(U);
1010 const auto s_new = specific_entropy(U);
1011
1012 constexpr auto gt = dealii::SIMDComparison::greater_than;
1013 using T = Number;
1014 const auto test =
1015 ryujin::compare_and_apply_mask<gt>(rho_new, T(0.), T(0.), T(-1.)) + //
1016 ryujin::compare_and_apply_mask<gt>(e_new, T(0.), T(0.), T(-1.)) + //
1017 ryujin::compare_and_apply_mask<gt>(s_new, T(0.), T(0.), T(-1.));
1018
1019#ifdef DEBUG_OUTPUT
1020 if (!(test == Number(0.))) {
1021 std::cout << std::fixed << std::setprecision(16);
1022 std::cout << "Bounds violation: Negative state [rho, e, s] detected!\n";
1023 std::cout << "\t\trho: " << rho_new << "\n";
1024 std::cout << "\t\tint: " << e_new << "\n";
1025 std::cout << "\t\tent: " << s_new << "\n" << std::endl;
1026 }
1027#endif
1028
1029 return (test == Number(0.));
1030 }
1031
1032
1033 template <int dim, typename Number, typename MemorySpace>
1034 template <int component>
1035 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1037 const state_type &U, const dealii::Tensor<1, dim, Number> &normal) const
1038 -> std::array<state_type, 2>
1039 {
1040 static_assert(component == 1 || component == problem_dimension,
1041 "Only first and last eigenvectors implemented");
1042
1043 const auto rho = density(U);
1044 const auto m = momentum(U);
1045 const auto v = m / rho;
1046 const auto a = speed_of_sound(U);
1047 const auto gamma = this->gamma();
1048
1049 state_type b;
1050 state_type c;
1051
1052 const auto e_k = 0.5 * v.norm_square();
1053
1054 switch (component) {
1055 case 1:
1056 b[0] = (gamma - 1.) * e_k + a * v * normal;
1057 for (unsigned int i = 0; i < dim; ++i)
1058 b[1 + i] = (1. - gamma) * v[i] - a * normal[i];
1059 b[dim + 1] = gamma - 1.;
1060 b /= 2. * a * a;
1061
1062 c[0] = 1.;
1063 for (unsigned int i = 0; i < dim; ++i)
1064 c[1 + i] = v[i] - a * normal[i];
1065 c[dim + 1] = a * a / (gamma - 1) + e_k - a * (v * normal);
1066
1067 return {b, c};
1068
1069 case problem_dimension:
1070 b[0] = (gamma - 1.) * e_k - a * v * normal;
1071 for (unsigned int i = 0; i < dim; ++i)
1072 b[1 + i] = (1. - gamma) * v[i] + a * normal[i];
1073 b[dim + 1] = gamma - 1.;
1074 b /= 2. * a * a;
1075
1076 c[0] = 1.;
1077 for (unsigned int i = 0; i < dim; ++i)
1078 c[1 + i] = v[i] + a * normal[i];
1079 c[dim + 1] = a * a / (gamma - 1) + e_k + a * (v * normal);
1080
1081 return {b, c};
1082 }
1083
1084 __builtin_unreachable();
1085 }
1086
1087
1088 template <int dim, typename Number, typename MemorySpace>
1089 template <int component>
1090 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1093 const state_type &U,
1094 const state_type &U_bar,
1095 const dealii::Tensor<1, dim, Number> &normal) const -> state_type
1096 {
1097 static_assert(component == 1 || component == 2,
1098 "component has to be 1 or 2");
1099
1100 const auto m = momentum(U);
1101 const auto rho = density(U);
1102 const auto a = speed_of_sound(U);
1103 const auto vn = m * normal / rho;
1104
1105 const auto m_bar = momentum(U_bar);
1106 const auto rho_bar = density(U_bar);
1107 const auto a_bar = speed_of_sound(U_bar);
1108 const auto vn_bar = m_bar * normal / rho_bar;
1109
1110 /* First Riemann characteristic: v* n - 2 / (gamma - 1) * a */
1111
1112 const auto R_1 = component == 1
1113 ? vn_bar - 2. * a_bar / (gamma() - ScalarNumber(1.))
1114 : vn - 2. * a / (gamma() - ScalarNumber(1.));
1115
1116 /* Second Riemann characteristic: v* n + 2 / (gamma() - 1) * a */
1117
1118 const auto R_2 = component == 2
1119 ? vn_bar + 2. * a_bar / (gamma() - ScalarNumber(1.))
1120 : vn + 2. * a / (gamma() - ScalarNumber(1.));
1121
1122 const auto p = pressure(U);
1123 const auto s = p / ryujin::pow(rho, gamma());
1124
1125 const auto vperp = m / rho - vn * normal;
1126
1127 const auto vn_new = 0.5 * (R_1 + R_2);
1128
1129 auto rho_new = 1. / (gamma() * s) *
1130 ryujin::fixed_power<2>(ScalarNumber((gamma() - 1.) / 4.) *
1131 (R_2 - R_1));
1132 rho_new = ryujin::pow(rho_new, 1. / (gamma() - 1.));
1133
1134 const auto p_new = s * std::pow(rho_new, gamma());
1135
1136 state_type U_new;
1137 U_new[0] = rho_new;
1138 for (unsigned int d = 0; d < dim; ++d) {
1139 U_new[1 + d] = rho_new * (vn_new * normal + vperp)[d];
1140 }
1141 U_new[1 + dim] = p_new / ScalarNumber(gamma() - 1.) +
1142 0.5 * rho_new * (vn_new * vn_new + vperp.norm_square());
1143
1144 return U_new;
1145 }
1146
1147
1148 template <int dim, typename Number, typename MemorySpace>
1149 template <typename Lambda>
1150 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1152 dealii::types::boundary_id id,
1153 const state_type &U,
1154 const dealii::Tensor<1, dim, Number> &normal,
1155 const Lambda &get_dirichlet_data) const -> state_type
1156 {
1157 state_type result = U;
1158
1159 if (id == Boundary::dirichlet) {
1160 result = get_dirichlet_data();
1161
1162 } else if (id == Boundary::dirichlet_momentum) {
1163 /*
1164 * Only enforce Dirichlet conditions on the momentum, and keep the
1165 * internal energy constant:
1166 */
1167 const auto m_dirichlet = momentum(get_dirichlet_data());
1168 const auto rho = density(result);
1169 const auto m = momentum(result);
1170
1171 for (unsigned int k = 0; k < dim; ++k)
1172 result[k + 1] = m_dirichlet[k];
1173 result[dim + 1] +=
1174 Number(0.5) / rho * (m_dirichlet.norm_square() - m.norm_square());
1175
1176 } else if (id == Boundary::dirichlet_velocity) {
1177 /*
1178 * Only enforce Dirichlet conditions on the velocity, and keep the
1179 * internal energy constant:
1180 */
1181 const auto U_dirichlet = get_dirichlet_data();
1182 const auto rho_dirichlet = density(U_dirichlet);
1183 const auto v_dirichlet = momentum(U_dirichlet) / rho_dirichlet;
1184 const auto rho = density(result);
1185 const auto v = momentum(result) / rho;
1186
1187 for (unsigned int k = 0; k < dim; ++k)
1188 result[k + 1] = rho * v_dirichlet[k];
1189 result[dim + 1] +=
1190 Number(0.5) * rho * (v_dirichlet.norm_square() - v.norm_square());
1191
1192 } else if (id == Boundary::slip) {
1193 auto m = momentum(U);
1194 m -= 1. * (m * normal) * normal;
1195 for (unsigned int k = 0; k < dim; ++k)
1196 result[k + 1] = m[k];
1197
1198 } else if (id == Boundary::no_slip) {
1199 for (unsigned int k = 0; k < dim; ++k)
1200 result[k + 1] = Number(0.);
1201
1202 } else if (id == Boundary::dynamic) {
1203 /*
1204 * On dynamic boundary conditions, we distinguish four cases:
1205 *
1206 * - supersonic inflow: prescribe full state
1207 * - subsonic inflow:
1208 * decompose into Riemann invariants and leave R_2
1209 * characteristic untouched.
1210 * - supersonic outflow: do nothing
1211 * - subsonic outflow:
1212 * decompose into Riemann invariants and prescribe incoming
1213 * R_1 characteristic.
1214 */
1215 const auto m = momentum(U);
1216 const auto rho = density(U);
1217 const auto a = speed_of_sound(U);
1218 const auto vn = m * normal / rho;
1219
1220 /* Supersonic inflow: */
1221 if (vn < -a) {
1222 result = get_dirichlet_data();
1223 }
1224
1225 /* Subsonic inflow: */
1226 if (vn >= -a && vn <= 0.) {
1227 const auto U_dirichlet = get_dirichlet_data();
1228 result = prescribe_riemann_characteristic<2>(U_dirichlet, U, normal);
1229 }
1230
1231 /* Subsonic outflow: */
1232 if (vn > 0. && vn <= a) {
1233 const auto U_dirichlet = get_dirichlet_data();
1234 result = prescribe_riemann_characteristic<1>(U, U_dirichlet, normal);
1235 }
1236
1237 /* Supersonic outflow: do nothing, i.e., keep U as is */
1238
1239 } else {
1240 Assert(false, dealii::ExcNotImplemented());
1241 }
1242
1243 return result;
1244 }
1245
1246
1247 template <int dim, typename Number, typename MemorySpace>
1248 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1250 -> flux_type
1251 {
1252 const auto rho_inverse = ScalarNumber(1.) / density(U);
1253 const auto m = momentum(U);
1254 const auto p = pressure(U);
1255 const auto E = total_energy(U);
1256
1257 flux_type result;
1258
1259 result[0] = m;
1260 for (unsigned int i = 0; i < dim; ++i) {
1261 result[1 + i] = m * (m[i] * rho_inverse);
1262 result[1 + i][i] += p;
1263 }
1264 result[dim + 1] = m * (rho_inverse * (E + p));
1265
1266 return result;
1267 }
1268
1269
1270 template <int dim, typename Number, typename MemorySpace>
1271 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1273 const PrecomputedVectorView & /*pv*/,
1274 const InitialPrecomputedVectorView & /*ipv*/,
1275 const unsigned int /*i*/,
1276 const state_type &U_i) const -> flux_contribution_type
1277 {
1278 return f(U_i);
1279 }
1280
1281
1282 template <int dim, typename Number, typename MemorySpace>
1283 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1285 const PrecomputedVectorView & /*pv*/,
1286 const InitialPrecomputedVectorView & /*ipv*/,
1287 const unsigned int * /*js*/,
1288 const state_type &U_j) const -> flux_contribution_type
1289 {
1290 return f(U_j);
1291 }
1292
1293
1294 template <int dim, typename Number, typename MemorySpace>
1295 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1297 const flux_contribution_type &flux_i,
1298 const flux_contribution_type &flux_j,
1299 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
1300 {
1301 return -contract(add(flux_i, flux_j), c_ij);
1302 }
1303
1304
1305 template <int dim, typename Number, typename MemorySpace>
1306 template <typename ST>
1307 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1309 const ST &state) const -> state_type
1310 {
1311 using T = typename ST::value_type;
1312 static_assert(std::is_same_v<Number, T>, "template mismatch");
1313
1314 constexpr auto dim2 = ST::dimension - 2;
1315 static_assert(dim >= dim2,
1316 "the space dimension of the argument state must not be "
1317 "larger than the one of the target state");
1318
1319 state_type result;
1320 result[0] = state[0];
1321 result[dim + 1] = state[dim2 + 1];
1322 for (unsigned int i = 1; i < dim2 + 1; ++i)
1323 result[i] = state[i];
1324
1325 return result;
1326 }
1327
1328
1329 template <int dim, typename Number, typename MemorySpace>
1330 template <typename ST>
1331 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1333 const ST &initial_state) const -> state_type
1334 {
1335 const auto primitive_state = expand_state(initial_state);
1336 return from_primitive_state(primitive_state);
1337 }
1338
1339
1340 template <int dim, typename Number, typename MemorySpace>
1341 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1343 const state_type &primitive_state) const -> state_type
1344 {
1345 const auto &rho = primitive_state[0];
1346 /* extract velocity: */
1347 const auto u = /*SIC!*/ momentum(primitive_state);
1348 const auto &p = primitive_state[dim + 1];
1349
1350 auto state = primitive_state;
1351 /* Fix up momentum: */
1352 for (unsigned int i = 1; i < dim + 1; ++i)
1353 state[i] *= rho;
1354 /* Compute total energy: */
1355 state[dim + 1] =
1356 p / (ScalarNumber(gamma() - 1.)) + Number(0.5) * rho * u * u;
1357
1358 return state;
1359 }
1360
1361
1362 template <int dim, typename Number, typename MemorySpace>
1363 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1365 const state_type &state) const -> state_type
1366 {
1367 const auto &rho = state[0];
1368 const auto rho_inverse = Number(1.) / rho;
1369 const auto p = pressure(state);
1370
1371 auto primitive_state = state;
1372 /* Fix up velocity: */
1373 for (unsigned int i = 1; i < dim + 1; ++i)
1374 primitive_state[i] *= rho_inverse;
1375 /* Set pressure: */
1376 primitive_state[dim + 1] = p;
1377
1378 return primitive_state;
1379 }
1380
1381
1382 template <int dim, typename Number, typename MemorySpace>
1383 template <typename Lambda>
1384 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
1386 const state_type &state, const Lambda &lambda) const -> state_type
1387 {
1388 auto result = state;
1389 const auto M = lambda(momentum(state));
1390 for (unsigned int d = 0; d < dim; ++d)
1391 result[1 + d] = M[d];
1392 return result;
1393 }
1394 } // namespace Euler
1395} // 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)
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")
void fill_precomputed_values(const OfflineData< dim, ScalarNumber > &offline_data, StateVector< ScalarNumber > &state_vector, const bool skip_constrained_dofs=true) const
@ dirichlet_momentum
@ dirichlet_velocity
DEAL_II_HOST_DEVICE T pow(const T x, const T b)
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)
MultiComponentVector< Number > precomputed