ryujin 2.1.1 revision 1c453cc82f1d29edf537280cd96267402ac73e60
hyperbolic_system.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0
3// [LANL Copyright Statement]
4// Copyright (C) 2020 - 2024 by the ryujin authors
5// Copyright (C) 2023 - 2024 by Triad National Security, LLC
6//
7
8#pragma once
9
10#include <convenience_macros.h>
11#include <deal.II/base/config.h>
12#include <discretization.h>
14#include <openmp.h>
15#include <patterns_conversion.h>
16#include <simd.h>
17#include <state_vector.h>
18
19#include <deal.II/base/parameter_acceptor.h>
20#include <deal.II/base/tensor.h>
21
22#include <array>
23
24namespace ryujin
25{
26 namespace ShallowWater
27 {
28 template <int dim, typename Number>
29 class HyperbolicSystemView;
30
40 class HyperbolicSystem final : public dealii::ParameterAcceptor
41 {
42 public:
46 static inline const std::string problem_name = "Shallow water equations";
47
51 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
52
59 template <int dim, typename Number>
60 auto view() const
61 {
63 }
64
65 private:
70 double gravity_;
71 double manning_friction_coefficient_;
72
73 double reference_water_depth_;
74 double dry_state_relaxation_factor_;
75 double dry_state_relaxation_small_;
76 double dry_state_relaxation_large_;
77
78 template <int dim, typename Number>
81 }; /* HyperbolicSystem */
82
83
100 template <int dim, typename Number>
102 {
103 public:
108 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
109 : hyperbolic_system_(hyperbolic_system)
110 {
111 }
112
116 template <int dim2, typename Number2>
117 auto view() const
118 {
119 return HyperbolicSystemView<dim2, Number2>{hyperbolic_system_};
120 }
121
126
131
132 DEAL_II_ALWAYS_INLINE inline ScalarNumber gravity() const
133 {
134 return hyperbolic_system_.gravity_;
135 }
136
137 DEAL_II_ALWAYS_INLINE inline ScalarNumber
139 {
140 return hyperbolic_system_.manning_friction_coefficient_;
141 }
142
143 DEAL_II_ALWAYS_INLINE inline ScalarNumber reference_water_depth() const
144 {
145 return hyperbolic_system_.reference_water_depth_;
146 }
147
148 DEAL_II_ALWAYS_INLINE inline ScalarNumber
150 {
151 return hyperbolic_system_.dry_state_relaxation_factor_;
152 }
153
154 DEAL_II_ALWAYS_INLINE inline ScalarNumber
156 {
157 return hyperbolic_system_.dry_state_relaxation_small_;
158 }
159
160 DEAL_II_ALWAYS_INLINE inline ScalarNumber
162 {
163 return hyperbolic_system_.dry_state_relaxation_large_;
164 }
165
167
171
172 private:
173 const HyperbolicSystem &hyperbolic_system_;
174
175 public:
177
181
185 static constexpr unsigned int problem_dimension = 1 + dim;
186
190 using state_type = dealii::Tensor<1, problem_dimension, Number>;
191
195 using flux_type =
196 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
197
201 using flux_contribution_type = std::tuple<state_type, Number>;
202
207 static inline const auto component_names =
208 []() -> std::array<std::string, problem_dimension> {
209 if constexpr (dim == 1)
210 return {"h", "m"};
211 else if constexpr (dim == 2)
212 return {"h", "m_1", "m_2"};
213 else if constexpr (dim == 3)
214 return {"h", "m_1", "m_2", "m_3"};
215 __builtin_trap();
216 }();
217
222 static inline const auto primitive_component_names =
223 []() -> std::array<std::string, problem_dimension> {
224 if constexpr (dim == 1)
225 return {"h", "v"};
226 else if constexpr (dim == 2)
227 return {"h", "v_1", "v_2"};
228 else if constexpr (dim == 3)
229 return {"h", "v_1", "v_2", "v_3"};
230 __builtin_trap();
231 }();
232
236 static constexpr unsigned int n_precomputed_values = 2;
237
241 using precomputed_type = std::array<Number, n_precomputed_values>;
242
246 static inline const auto precomputed_names =
247 std::array<std::string, n_precomputed_values>{"eta_m", "h_star"};
248
252 static constexpr unsigned int n_initial_precomputed_values = 1;
253
258 std::array<Number, n_initial_precomputed_values>;
259
263 static inline const auto initial_precomputed_names =
264 std::array<std::string, n_initial_precomputed_values>{"bathymetry"};
265
269 using StateVector = Vectors::
270 StateVector<ScalarNumber, problem_dimension, n_precomputed_values>;
271
277
285
287
291
295 static constexpr unsigned int n_precomputation_cycles = 1;
296
301 template <typename DISPATCH, typename SPARSITY>
302 void precomputation_loop(unsigned int cycle,
303 const DISPATCH &dispatch_check,
304 const SPARSITY &sparsity_simd,
305 StateVector &state_vector,
306 unsigned int left,
307 unsigned int right) const;
308
310
314
319 static Number water_depth(const state_type &U);
320
327 Number inverse_water_depth_mollified(const state_type &U) const;
328
335 Number water_depth_sharp(const state_type &U) const;
336
343 Number inverse_water_depth_sharp(const state_type &U) const;
344
351 Number filter_dry_water_depth(const Number &h) const;
352
357 static dealii::Tensor<1, dim, Number> momentum(const state_type &U);
358
366 Number kinetic_energy(const state_type &U) const;
367
375 Number pressure(const state_type &U) const;
376
384 Number speed_of_sound(const state_type &U) const;
385
390 Number mathematical_entropy(const state_type &U) const;
391
397
403 bool is_admissible(const state_type &U) const;
404
406
410
416 template <int component>
418 const state_type &U,
419 const state_type &U_bar,
420 const dealii::Tensor<1, dim, Number> &normal) const;
421
425 template <typename Lambda>
427 apply_boundary_conditions(const dealii::types::boundary_id id,
428 const state_type &U,
429 const dealii::Tensor<1, dim, Number> &normal,
430 const Lambda &get_dirichlet_data) const;
431
433
437
447 flux_type f(const state_type &U) const;
448
458 flux_type g(const state_type &U) const;
459
466 const Number &Z_left,
467 const Number &Z_right) const;
468
474 std::array<state_type, 2>
476 const flux_contribution_type &) const;
477
500 const InitialPrecomputedVector &piv,
501 const unsigned int i,
502 const state_type &U_i) const;
503
506 const InitialPrecomputedVector &piv,
507 const unsigned int *js,
508 const state_type &U_j) const;
509
517 const flux_contribution_type &flux_j,
518 const dealii::Tensor<1, dim, Number> &c_ij) const;
519
523 static constexpr bool have_high_order_flux = true;
524
531 const flux_contribution_type &flux_i,
532 const flux_contribution_type &flux_j,
533 const dealii::Tensor<1, dim, Number> &c_ij) const;
534
541 const flux_contribution_type &flux_j,
542 const dealii::Tensor<1, dim, Number> &c_ij,
543 const Number &d_ij) const;
544
546
550
552 static constexpr bool have_source_terms = true;
553
560 const Number &h_star,
561 const ScalarNumber tau) const;
562
564 const unsigned int i,
565 const state_type &U_i,
566 const ScalarNumber tau) const;
567
569 const unsigned int *js,
570 const state_type &U_j,
571 const ScalarNumber tau) const;
572
574
579
590 template <typename ST>
591 state_type expand_state(const ST &state) const;
592
604 template <typename ST>
605 state_type from_initial_state(const ST &initial_state) const;
606
611 state_type from_primitive_state(const state_type &primitive_state) const;
612
616 state_type to_primitive_state(const state_type &state) const;
617
623 template <typename Lambda>
625 const Lambda &lambda) const;
626
627 }; /* HyperbolicSystemView */
628
629
630 /*
631 * -------------------------------------------------------------------------
632 * Inline definitions
633 * -------------------------------------------------------------------------
634 */
635
636
637 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
638 : ParameterAcceptor(subsection)
639 {
640 gravity_ = 9.81;
641 add_parameter("gravity", gravity_, "Gravitational constant [m/s^2]");
642
643 manning_friction_coefficient_ = 0.;
644 add_parameter("manning friction coefficient",
645 manning_friction_coefficient_,
646 "Roughness coefficient for friction source");
647
648 reference_water_depth_ = 1.;
649 add_parameter("reference water depth",
650 reference_water_depth_,
651 "Problem specific water depth reference");
652
653 dry_state_relaxation_factor_ = 2.e-1;
654 add_parameter("dry state relaxation factor",
655 dry_state_relaxation_factor_,
656 "Problem specific dry-state relaxation parameter");
657
658 dry_state_relaxation_small_ = 1.e2;
659 add_parameter("dry state relaxation small",
660 dry_state_relaxation_small_,
661 "Problem specific dry-state relaxation parameter");
662
663 dry_state_relaxation_large_ = 1.e4;
664 add_parameter("dry state relaxation large",
665 dry_state_relaxation_large_,
666 "Problem specific dry-state relaxation parameter");
667 }
668
669
670 template <int dim, typename Number>
671 template <typename DISPATCH, typename SPARSITY>
672 DEAL_II_ALWAYS_INLINE inline void
674 unsigned int cycle [[maybe_unused]],
675 const DISPATCH &dispatch_check,
676 const SPARSITY &sparsity_simd,
677 StateVector &state_vector,
678 unsigned int left,
679 unsigned int right) const
680 {
681 Assert(cycle == 0, dealii::ExcInternalError());
682
683 const auto &U = std::get<0>(state_vector);
684 auto &precomputed = std::get<1>(state_vector);
685
686 /* We are inside a thread parallel context */
687
688 unsigned int stride_size = get_stride_size<Number>;
689
691 for (unsigned int i = left; i < right; i += stride_size) {
692
693 /* Skip constrained degrees of freedom: */
694 const unsigned int row_length = sparsity_simd.row_length(i);
695 if (row_length == 1)
696 continue;
697
698 dispatch_check(i);
699
700 const auto U_i = U.template get_tensor<Number>(i);
701
702 const auto eta_m = mathematical_entropy(U_i);
703
704 const auto h_sharp = water_depth_sharp(U_i);
705 const auto h_star = ryujin::pow(h_sharp, ScalarNumber(4. / 3.));
706
707 const precomputed_type prec_i{eta_m, h_star};
708 precomputed.template write_tensor<Number>(prec_i, i);
709 }
710 }
711
712
713 template <int dim, typename Number>
714 DEAL_II_ALWAYS_INLINE inline Number
716 {
717 return U[0];
718 }
719
720
721 template <int dim, typename Number>
722 DEAL_II_ALWAYS_INLINE inline Number
724 const state_type &U) const
725 {
726 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
727
728 const Number h_cutoff_mollified =
729 reference_water_depth() * dry_state_relaxation_large() * Number(eps);
730
731 const Number h = water_depth(U);
732 const Number h_pos = positive_part(water_depth(U));
733 const Number h_max = std::max(h, h_cutoff_mollified);
734 const Number denom = h * h + h_max * h_max;
735 return ScalarNumber(2.) * h_pos / denom;
736 }
737
738
739 template <int dim, typename Number>
740 DEAL_II_ALWAYS_INLINE inline Number
742 const state_type &U) const
743 {
744 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
745
746 const Number h_cutoff_small =
747 reference_water_depth() * dry_state_relaxation_small() * Number(eps);
748
749 const Number h = water_depth(U);
750 const Number h_max = std::max(h, h_cutoff_small);
751 return h_max;
752 }
753
754
755 template <int dim, typename Number>
756 DEAL_II_ALWAYS_INLINE inline Number
758 const state_type &U) const
759 {
760 return ScalarNumber(1.) / water_depth_sharp(U);
761 }
762
763
764 template <int dim, typename Number>
765 DEAL_II_ALWAYS_INLINE inline Number
767 const Number &h) const
768 {
770 constexpr ScalarNumber eps = std::numeric_limits<ScalarNumber>::epsilon();
771
772 const Number h_cutoff_large =
773 reference_water_depth() * dry_state_relaxation_large() * Number(eps);
774
775 return dealii::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
776 std::abs(h), h_cutoff_large, Number(0.), h);
777 }
778
779
780 template <int dim, typename Number>
781 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
783 {
784 dealii::Tensor<1, dim, Number> result;
785
786 for (unsigned int i = 0; i < dim; ++i)
787 result[i] = U[1 + i];
788 return result;
789 }
790
791
792 template <int dim, typename Number>
793 DEAL_II_ALWAYS_INLINE inline Number
795 {
796 const auto h = water_depth(U);
797 const auto vel = momentum(U) * inverse_water_depth_sharp(U);
798
799 /* KE = 1/2 h |v|^2 */
800 return ScalarNumber(0.5) * h * vel.norm_square();
801 }
802
803
804 template <int dim, typename Number>
805 DEAL_II_ALWAYS_INLINE inline Number
807 {
808 const Number h_sqd = U[0] * U[0];
809
810 /* p = 1/2 g h^2 */
811 return ScalarNumber(0.5) * gravity() * h_sqd;
812 }
813
814
815 template <int dim, typename Number>
816 DEAL_II_ALWAYS_INLINE inline Number
818 {
819 /* c^2 = g * h */
820 return std::sqrt(gravity() * U[0]);
821 }
822
823
824 template <int dim, typename Number>
825 DEAL_II_ALWAYS_INLINE inline Number
827 const state_type &U) const
828 {
829 const auto p = pressure(U);
830 const auto k_e = kinetic_energy(U);
831 return p + k_e;
832 }
833
834
835 template <int dim, typename Number>
836 DEAL_II_ALWAYS_INLINE inline auto
838 const state_type &U) const -> state_type
839 {
840 /*
841 * With
842 * eta = 1/2 g h^2 + 1/2 |m|^2 / h
843 *
844 * we get
845 *
846 * eta' = (g h - 1/2 |vel|^2, vel)
847 *
848 * where vel = m / h
849 */
850
851 state_type result;
852
853 const Number &h = U[0];
854 const auto vel = momentum(U) * inverse_water_depth_sharp(U);
855
856 // water depth component
857 result[0] = gravity() * h - ScalarNumber(0.5) * vel.norm_square();
858
859 // momentum components
860 for (unsigned int i = 0; i < dim; ++i) {
861 result[1 + i] = vel[i];
862 }
863
864 return result;
865 }
866
867
868 template <int dim, typename Number>
869 DEAL_II_ALWAYS_INLINE inline bool
871 {
872 const auto h = filter_dry_water_depth(water_depth(U));
873
874 constexpr auto gte = dealii::SIMDComparison::greater_than_or_equal;
875 const auto test = dealii::compare_and_apply_mask<gte>(
876 h, Number(0.), Number(0.), Number(-1.));
877
878#ifdef DEBUG_OUTPUT
879 if (!(test == Number(0.))) {
880 std::cout << std::fixed << std::setprecision(16);
881 std::cout << "Bounds violation: Negative state [h] detected!\n";
882 std::cout << "\t\th: " << h << "\n" << std::endl;
883 __builtin_trap();
884 }
885#endif
886
887 return (test == Number(0.));
888 }
889
890
891 template <int dim, typename Number>
892 template <int component>
893 DEAL_II_ALWAYS_INLINE inline auto
895 const state_type &U,
896 const state_type &U_bar,
897 const dealii::Tensor<1, dim, Number> &normal) const -> state_type
898 {
899 /* Note that U_bar are the dirichlet values that are prescribed */
900 static_assert(component == 1 || component == 2,
901 "component has to be 1 or 2");
902
904
905 const auto m = momentum(U);
906 const auto a = speed_of_sound(U);
907 const auto vn = m * normal * inverse_water_depth_sharp(U);
908
909 const auto m_bar = momentum(U_bar);
910 const auto a_bar = speed_of_sound(U_bar);
911 const auto vn_bar = m_bar * normal * inverse_water_depth_sharp(U_bar);
912
913 /* First Riemann characteristic: v * n - 2 * a */
914
915 const auto R_1 = component == 1 ? vn_bar - ScalarNumber(2.) * a_bar
916 : vn - ScalarNumber(2.) * a;
917
918 /* Second Riemann characteristic: v * n + 2 * a */
919
920 const auto R_2 = component == 2 ? vn_bar + ScalarNumber(2.) * a_bar
921 : vn + ScalarNumber(2.) * a;
922
923 const auto vperp = m * inverse_water_depth_sharp(U) - vn * normal;
924
925 const auto vn_new = ScalarNumber(0.5) * (R_1 + R_2);
926
927 const auto h_new =
928 ryujin::fixed_power<2>((R_2 - R_1) / ScalarNumber(4.)) / gravity();
929
930 state_type U_new;
931 U_new[0] = h_new;
932 for (unsigned int d = 0; d < dim; ++d) {
933 U_new[1 + d] = h_new * (vn_new * normal + vperp)[d];
934 }
935
936 return U_new;
937 }
938
939
940 template <int dim, typename Number>
941 template <typename Lambda>
942 DEAL_II_ALWAYS_INLINE inline auto
944 const dealii::types::boundary_id id,
945 const state_type &U,
946 const dealii::Tensor<1, dim, Number> &normal,
947 const Lambda &get_dirichlet_data) const -> state_type
948 {
949 state_type result = U;
950
951 if (id == Boundary::dirichlet) {
952 result = get_dirichlet_data();
953
954 } else if (id == Boundary::dirichlet_momentum) {
955 /*
956 * For some benchmarks for the Shallow Water Equations, only the
957 * momentum is enforced. We "do nothing" for the water
958 * depth.
959 */
960 auto m_dir = momentum(get_dirichlet_data());
961 for (unsigned int k = 0; k < dim; ++k)
962 result[k + 1] = m_dir[k];
963
964 } else if (id == Boundary::slip) {
965 auto m = momentum(U);
966 m -= 1. * (m * normal) * normal;
967 for (unsigned int k = 0; k < dim; ++k)
968 result[k + 1] = m[k];
969
970 } else if (id == Boundary::no_slip) {
971 for (unsigned int k = 0; k < dim; ++k)
972 result[k + 1] = Number(0.);
973
974 } else if (id == Boundary::dynamic) {
975 /*
976 * On dynamic boundary conditions, we distinguish four cases:
977 *
978 * - supersonic inflow: prescribe full state
979 * - subsonic inflow:
980 * decompose into Riemann invariants and leave R_2
981 * characteristic untouched.
982 * - supersonic outflow: do nothing
983 * - subsonic outflow:
984 * decompose into Riemann invariants and prescribe incoming
985 * R_1 characteristic.
986 */
987 const auto m = momentum(U);
988 const auto h_inverse = inverse_water_depth_sharp(U);
989 const auto a = speed_of_sound(U);
990 const auto vn = m * normal * h_inverse;
991
992 /* Supersonic inflow: */
993 if (vn < -a) {
994 result = get_dirichlet_data();
995 }
996
997 /* Subsonic inflow: */
998 if (vn >= -a && vn <= 0.) {
999 const auto U_dirichlet = get_dirichlet_data();
1000 result = prescribe_riemann_characteristic<2>(U_dirichlet, U, normal);
1001 }
1002
1003 /* Subsonic outflow: */
1004 if (vn > 0. && vn <= a) {
1005 const auto U_dirichlet = get_dirichlet_data();
1006 result = prescribe_riemann_characteristic<1>(U, U_dirichlet, normal);
1007 }
1008
1009 /* Supersonic outflow: do nothing, i.e., keep U as is */
1010 }
1011
1012 return result;
1013 }
1014
1015
1016 template <int dim, typename Number>
1017 DEAL_II_ALWAYS_INLINE inline auto
1019 {
1020 const auto h_inverse = inverse_water_depth_sharp(U);
1021 const auto m = momentum(U);
1022 const auto p = pressure(U);
1023
1024 flux_type result;
1025
1026 result[0] = (m * h_inverse) * U[0];
1027 for (unsigned int i = 0; i < dim; ++i) {
1028 result[1 + i] = (m * h_inverse) * m[i];
1029 result[1 + i][i] += p;
1030 }
1031 return result;
1032 }
1033
1034
1035 template <int dim, typename Number>
1036 DEAL_II_ALWAYS_INLINE inline auto
1038 {
1039 const auto h_inverse = inverse_water_depth_sharp(U);
1040 const auto m = momentum(U);
1041
1042 flux_type result;
1043
1044 result[0] = (m * h_inverse) * U[0];
1045 for (unsigned int i = 0; i < dim; ++i) {
1046 result[1 + i] = (m * h_inverse) * m[i];
1047 }
1048 return result;
1049 }
1050
1051
1052 template <int dim, typename Number>
1053 DEAL_II_ALWAYS_INLINE inline auto
1055 const Number &Z_left,
1056 const Number &Z_right) const
1057 -> state_type
1058 {
1059 const Number Z_max = std::max(Z_left, Z_right);
1060 const Number h = water_depth(U);
1061 const Number H_star = std::max(Number(0.), h + Z_left - Z_max);
1062
1063 return U * H_star * inverse_water_depth_mollified(U);
1064 }
1065
1066
1067 template <int dim, typename Number>
1068 DEAL_II_ALWAYS_INLINE inline auto
1070 const flux_contribution_type &flux_i,
1071 const flux_contribution_type &flux_j) const -> std::array<state_type, 2>
1072 {
1073 const auto &[U_i, Z_i] = flux_i;
1074 const auto &[U_j, Z_j] = flux_j;
1075
1076 const auto U_star_ij = star_state(U_i, Z_i, Z_j);
1077 const auto U_star_ji = star_state(U_j, Z_j, Z_i);
1078
1079 return {U_star_ij, U_star_ji};
1080 }
1081
1082
1083 template <int dim, typename Number>
1084 DEAL_II_ALWAYS_INLINE inline auto
1086 const PrecomputedVector & /*pv*/,
1087 const InitialPrecomputedVector &piv,
1088 const unsigned int i,
1089 const state_type &U_i) const -> flux_contribution_type
1090 {
1091 const auto Z_i = piv.template get_tensor<Number>(i)[0];
1092 return {U_i, Z_i};
1093 }
1094
1095
1096 template <int dim, typename Number>
1097 DEAL_II_ALWAYS_INLINE inline auto
1099 const PrecomputedVector & /*pv*/,
1100 const InitialPrecomputedVector &piv,
1101 const unsigned int *js,
1102 const state_type &U_j) const -> flux_contribution_type
1103 {
1104 const auto Z_j = piv.template get_tensor<Number>(js)[0];
1105 return {U_j, Z_j};
1106 }
1107
1108
1109 template <int dim, typename Number>
1110 DEAL_II_ALWAYS_INLINE inline auto
1112 const flux_contribution_type &flux_i,
1113 const flux_contribution_type &flux_j,
1114 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
1115 {
1116 const auto &[U_i, Z_i] = flux_i;
1117 const auto &[U_star_ij, U_star_ji] = equilibrated_states(flux_i, flux_j);
1118
1119 const auto H_i = water_depth(U_i);
1120 const auto H_star_ij = water_depth(U_star_ij);
1121 const auto H_star_ji = water_depth(U_star_ji);
1122
1123 const auto g_i = g(U_star_ij);
1124 const auto g_j = g(U_star_ji);
1125
1126 auto result = -add(g_i, g_j);
1127
1128 const auto factor =
1129 (ScalarNumber(0.5) * (H_star_ji * H_star_ji - H_star_ij * H_star_ij) +
1130 H_i * H_i) *
1131 gravity();
1132
1133 for (unsigned int i = 0; i < dim; ++i) {
1134 result[1 + i][i] -= factor;
1135 }
1136
1137 return contract(result, c_ij);
1138 }
1139
1140
1141 template <int dim, typename Number>
1142 DEAL_II_ALWAYS_INLINE inline auto
1144 const flux_contribution_type &flux_i,
1145 const flux_contribution_type &flux_j,
1146 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
1147 {
1148 const auto &[U_i, Z_i] = flux_i;
1149 const auto &[U_j, Z_j] = flux_j;
1150
1151 const auto H_i = water_depth(U_i);
1152 const auto H_j = water_depth(U_j);
1153
1154 const auto g_i = g(U_i);
1155 const auto g_j = g(U_j);
1156
1157 auto result = -add(g_i, g_j);
1158
1159 const auto factor = gravity() * H_i * (H_j + Z_j - Z_i);
1160 for (unsigned int i = 0; i < dim; ++i) {
1161 result[1 + i][i] -= factor;
1162 }
1163
1164 return contract(result, c_ij);
1165 }
1166
1167
1168 template <int dim, typename Number>
1169 DEAL_II_ALWAYS_INLINE inline auto
1171 const flux_contribution_type &flux_i,
1172 const flux_contribution_type &flux_j,
1173 const dealii::Tensor<1, dim, Number> &c_ij,
1174 const Number &d_ij) const -> state_type
1175 {
1176 const auto &[U_i, Z_i] = flux_i;
1177 const auto &[U_j, Z_j] = flux_j;
1178 const auto U_star_ij = star_state(U_i, Z_i, Z_j);
1179
1180 const auto h_inverse = inverse_water_depth_sharp(U_i);
1181 const auto m = momentum(U_i);
1182 const auto factor = ScalarNumber(2.) * (d_ij + h_inverse * (m * c_ij));
1183
1184 return -factor * (U_star_ij - U_i);
1185 }
1186
1187
1188 template <int dim, typename Number>
1189 DEAL_II_ALWAYS_INLINE inline auto
1191 const state_type &U, const Number &h_star, const ScalarNumber tau) const
1192 -> state_type
1193 {
1194 state_type result;
1195
1196 const auto g = gravity();
1197 const auto n = manning_friction_coefficient();
1198
1199 const auto h_inverse = inverse_water_depth_mollified(U);
1200
1201 const auto m = momentum(U);
1202 const auto v_norm = (m * h_inverse).norm();
1203 const auto factor = ScalarNumber(2.) * g * n * n * v_norm;
1204
1205 const auto denominator = h_star + std::max(h_star, tau * factor);
1206 const auto denominator_inverse = ScalarNumber(1.) / denominator;
1207
1208 for (unsigned int d = 0; d < dim; ++d)
1209 result[d + 1] = -factor * denominator_inverse * m[d];
1210
1211 return result;
1212 }
1213
1214
1215 template <int dim, typename Number>
1216 DEAL_II_ALWAYS_INLINE inline auto
1218 const PrecomputedVector &pv,
1219 const unsigned int i,
1220 const state_type &U_i,
1221 const ScalarNumber tau) const -> state_type
1222 {
1223 const auto &[eta_m, h_star] =
1224 pv.template get_tensor<Number, precomputed_type>(i);
1225
1226 return manning_friction(U_i, h_star, tau);
1227 }
1228
1229
1230 template <int dim, typename Number>
1231 DEAL_II_ALWAYS_INLINE inline auto
1233 const PrecomputedVector &pv,
1234 const unsigned int *js,
1235 const state_type &U_j,
1236 const ScalarNumber tau) const -> state_type
1237 {
1238 const auto &[eta_m, h_star] =
1239 pv.template get_tensor<Number, precomputed_type>(js);
1240
1241 return manning_friction(U_j, h_star, tau);
1242 }
1243
1244
1245 template <int dim, typename Number>
1246 template <typename ST>
1247 DEAL_II_ALWAYS_INLINE inline auto
1249 -> state_type
1250 {
1251 using T = typename ST::value_type;
1252 static_assert(std::is_same_v<Number, T>, "template mismatch");
1253
1254 constexpr auto dim2 = ST::dimension - 1;
1255 static_assert(dim >= dim2,
1256 "the space dimension of the argument state must not be "
1257 "larger than the one of the target state");
1258
1259 state_type result;
1260 result[0] = state[0];
1261 for (unsigned int i = 1; i < dim2 + 1; ++i)
1262 result[i] = state[i];
1263
1264 return result;
1265 }
1266
1267 template <int dim, typename Number>
1268 template <typename ST>
1269 DEAL_II_ALWAYS_INLINE inline auto
1271 const ST &initial_state) const -> state_type
1272 {
1273 const auto primitive_state = expand_state(initial_state);
1274 return from_primitive_state(primitive_state);
1275 }
1276
1277
1278 template <int dim, typename Number>
1279 DEAL_II_ALWAYS_INLINE inline auto
1281 const state_type &primitive_state) const -> state_type
1282 {
1283 const auto &h = primitive_state[0];
1284
1285 auto state = primitive_state;
1286 /* Fix up momentum: */
1287 for (unsigned int i = 1; i < dim + 1; ++i)
1288 state[i] *= h;
1289
1290 return state;
1291 }
1292
1293
1294 template <int dim, typename Number>
1295 DEAL_II_ALWAYS_INLINE inline auto
1297 const state_type &state) const -> state_type
1298 {
1299 const auto h_inverse = inverse_water_depth_sharp(state);
1300
1301 auto primitive_state = state;
1302 /* Fix up velocity: */
1303 for (unsigned int i = 1; i < dim + 1; ++i)
1304 primitive_state[i] *= h_inverse;
1305
1306 return primitive_state;
1307 }
1308
1309
1310 template <int dim, typename Number>
1311 template <typename Lambda>
1312 DEAL_II_ALWAYS_INLINE inline auto
1314 const state_type &state, const Lambda &lambda) const -> state_type
1315 {
1316 auto result = state;
1317 auto M = lambda(momentum(state));
1318 for (unsigned int d = 0; d < dim; ++d)
1319 result[1 + d] = M[d];
1320 return result;
1321 }
1322
1323 } // namespace ShallowWater
1324} // namespace ryujin
typename get_value_type< Number >::type ScalarNumber
dealii::Tensor< 1, problem_dimension, Number > state_type
std::array< Number, n_precomputed_values > precomputed_type
Vectors::StateVector< ScalarNumber, problem_dimension, n_precomputed_values > StateVector
dealii::Tensor< 1, problem_dimension, dealii::Tensor< 1, dim, Number > > flux_type
Number pressure(const state_type &U) 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 ScalarNumber gravity() const
bool is_admissible(const state_type &U) const
state_type mathematical_entropy_derivative(const state_type &U) const
typename get_value_type< Number >::type ScalarNumber
static Number water_depth(const state_type &U)
DEAL_II_ALWAYS_INLINE ScalarNumber dry_state_relaxation_large() const
void precomputation_loop(unsigned int cycle, const DISPATCH &dispatch_check, const SPARSITY &sparsity_simd, StateVector &state_vector, unsigned int left, unsigned int right) const
static constexpr unsigned int n_initial_precomputed_values
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
DEAL_II_ALWAYS_INLINE ScalarNumber dry_state_relaxation_small() const
Number inverse_water_depth_mollified(const state_type &U) const
Number water_depth_sharp(const state_type &U) const
Vectors::StateVector< ScalarNumber, problem_dimension, n_precomputed_values > StateVector
state_type nodal_source(const PrecomputedVector &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const
static constexpr unsigned int n_precomputed_values
Number inverse_water_depth_sharp(const state_type &U) const
Number kinetic_energy(const state_type &U) const
Number filter_dry_water_depth(const Number &h) const
state_type from_primitive_state(const state_type &primitive_state) const
state_type manning_friction(const state_type &U, const Number &h_star, const ScalarNumber tau) const
state_type expand_state(const ST &state) const
std::array< Number, n_initial_precomputed_values > initial_precomputed_type
DEAL_II_ALWAYS_INLINE ScalarNumber manning_friction_coefficient() const
Number speed_of_sound(const state_type &U) const
state_type star_state(const state_type &U, const Number &Z_left, const Number &Z_right) const
dealii::Tensor< 1, problem_dimension, Number > state_type
static dealii::Tensor< 1, dim, Number > momentum(const state_type &U)
state_type affine_shift(const flux_contribution_type &flux_i, const flux_contribution_type &flux_j, const dealii::Tensor< 1, dim, Number > &c_ij, const Number &d_ij) const
std::array< Number, n_precomputed_values > precomputed_type
state_type to_primitive_state(const state_type &state) const
state_type from_initial_state(const ST &initial_state) const
static constexpr unsigned int problem_dimension
flux_contribution_type flux_contribution(const PrecomputedVector &pv, const InitialPrecomputedVector &piv, const unsigned int i, const state_type &U_i) const
static constexpr unsigned int n_precomputation_cycles
flux_type g(const state_type &U) const
Number mathematical_entropy(const state_type &U) const
HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
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
std::array< state_type, 2 > equilibrated_states(const flux_contribution_type &, const flux_contribution_type &) const
DEAL_II_ALWAYS_INLINE ScalarNumber dry_state_relaxation_factor() const
std::tuple< state_type, Number > flux_contribution_type
flux_type f(const state_type &U) const
state_type prescribe_riemann_characteristic(const state_type &U, const state_type &U_bar, const dealii::Tensor< 1, dim, Number > &normal) const
state_type apply_galilei_transform(const state_type &state, const Lambda &lambda) const
DEAL_II_ALWAYS_INLINE ScalarNumber reference_water_depth() const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
@ dirichlet_momentum
#define RYUJIN_OMP_FOR
Definition: openmp.h:70
T pow(const T x, const T b)
DEAL_II_ALWAYS_INLINE Number positive_part(const Number number)
Definition: simd.h:112
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)