20 namespace ShallowWater
22 struct HyperbolicDescription;
25 using namespace dealii;
36 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void atomic_store(T *ptr,
const T value)
38#if KOKKOS_VERSION >= 40000 || defined(KOKKOS_ENABLE_IMPL_DESUL_ATOMICS)
39 Kokkos::atomic_store(ptr, value);
41 Kokkos::atomic_exchange(ptr, value);
46 template <
typename HyperbolicDescription,
int dim,
typename Number>
52 const std::string &subsection )
54 problem_dimension, n_precomputed_values, subsection)
55 , indicator_(hyperbolic_system, subsection +
"/indicator")
56 , limiter_(hyperbolic_system, subsection +
"/limiter")
57 , wave_speed_estimator_(hyperbolic_system,
58 subsection +
"/wave speed estimator")
59 , mpi_ensemble_(mpi_ensemble)
60 , offline_data_(&offline_data)
61 , hyperbolic_system_(&hyperbolic_system)
62 , initial_values_(&initial_values)
67 template <
typename HyperbolicDescription,
int dim,
typename Number>
72 <<
"HyperbolicModule<HyperbolicDescription, dim, Number>::prepare()"
76 const auto limiter_view = limiter_.template view<dim, Number>();
77 AssertThrow(limiter_view.iterations() <= 2,
79 "The number of limiter iterations must be between [0,2]"));
83 [[maybe_unused]]
const auto &hyperbolic_system = *hyperbolic_system_;
84 AssertDimension(hyperbolic_system.state_names(dim).size(),
86 AssertDimension(hyperbolic_system.primitive_names(dim).size(),
88 AssertDimension(hyperbolic_system.precomputed_names(dim).size(),
89 n_precomputed_values);
90 AssertDimension(hyperbolic_system.initial_precomputed_names(dim).size(),
91 n_initial_precomputed_values);
95 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
98 alpha_.reinit_with_scalar_partitioner(
101 bounds_.reinit_with_scalar_partitioner(scalar_partitioner, n_bounds);
102 r_.reinit_with_vector_partitioner(
103 offline_data_->hyperbolic_vector_partitioner(), problem_dimension);
107 boundary_states_.reinit(offline_data_->boundary_indices().size() *
113 const auto &sparsity_simd = offline_data_->sparsity_pattern_simd();
114 dij_matrix_.reinit(sparsity_simd);
115 lij_matrix_.reinit(sparsity_simd);
116 lij_matrix_next_.reinit(sparsity_simd);
117 pij_matrix_.reinit(sparsity_simd);
121 initial_precomputed_ =
122 initial_values_->interpolate_initial_precomputed_vector();
131 bounds_.template move_to_memory_space<MemorySpace>();
132 r_.template move_to_memory_space<MemorySpace>();
134 dij_matrix_.template move_to_memory_space<MemorySpace>();
135 lij_matrix_.template move_to_memory_space<MemorySpace>();
136 lij_matrix_next_.template move_to_memory_space<MemorySpace>();
137 pij_matrix_.template move_to_memory_space<MemorySpace>();
140 initial_precomputed_.template copy_to_memory_space<MemorySpace>();
160 template <
typename HyperbolicDescription,
int dim,
typename Number>
166 std::cout <<
"HyperbolicModule<dim, Number>::reinit_state_vector()"
170 auto &[U, Q, U_dynamic, Q_dynamic] = state_vector;
171 U.reinit_with_vector_partitioner(
172 offline_data_->hyperbolic_vector_partitioner(), problem_dimension);
173 Q.reinit_with_vector_partitioner(
174 offline_data_->precomputed_vector_partitioner(), n_precomputed_values);
178 constexpr auto nan = std::numeric_limits<Number>::signaling_NaN();
179 for (
auto *vector : {&U, &Q}) {
180 auto &data = vector->deal_ii_vector();
181 std::fill_n(data.begin(), data.locally_owned_size(), nan);
194 template <
typename HyperbolicDescription,
int dim,
typename Number>
200 std::cout <<
"HyperbolicModule<HyperbolicDescription, dim, "
201 "Number>::prepare_state_vector()"
207 move_to_memory_space<MemorySpace>(
210 auto &[U, Q, U_dynamic, Q_dynamic] = state_vector;
213 "time step [H] 1 - update boundary values, precompute values");
219 apply_boundary_conditions<MemorySpace>(U, t);
221 U.template deal_ii_vector<MemorySpace>().update_ghost_values();
227 hyperbolic_system_->template fill_precomputed_values<MemorySpace>(
228 *offline_data_, state_vector);
230 Q.template view<n_precomputed_values, MemorySpace>().update_ghost_values();
234 template <
typename HyperbolicDescription,
int dim,
typename Number>
240 std::cout <<
"HyperbolicModule<HyperbolicDescription, dim, "
241 "Number>::fill_precomputed_values()"
247 move_to_memory_space<MemorySpace>(
250 hyperbolic_system_->template fill_precomputed_values<MemorySpace>(
251 *offline_data_, state_vector,
false);
253 state_vector.
precomputed.template view<n_precomputed_values, MemorySpace>()
254 .update_ghost_values();
258 template <
typename HyperbolicDescription,
int dim,
typename Number>
259 template <
typename MemorySpace>
262 const Number t)
const
264 constexpr auto n_comp = problem_dimension;
266 const auto &boundary_indices = offline_data_->boundary_indices();
267 const auto n_boundary_indices =
268 static_cast<unsigned int>(boundary_indices.size());
273 const auto U_view = std::as_const(U).template view<n_comp, MemorySpace>();
274 const auto *indices = boundary_indices.template view<MemorySpace>();
275 auto *states = boundary_states_.template view<MemorySpace>();
277 const auto body = [=](
auto ,
unsigned int k) {
278 const auto U_i = U_view.read_tensor(indices[k]);
279 for (
unsigned int d = 0; d < n_comp; ++d)
280 states[k * n_comp + d] = U_i[d];
283 loop<MemorySpace, Number>(
"hyperbolic_kernel_01a",
293 auto *states = [&]() {
295 ComputingTimer::Scope scope(
296 "time step [X] _ - memory space transfers");
297 return boundary_states_.template view<dealii::MemorySpace::Host>();
299 return boundary_states_.template view<dealii::MemorySpace::Host>();
302 const auto &boundary_map = offline_data_->boundary_map();
303 const auto &boundary_slots = offline_data_->boundary_slots();
304 const auto view = hyperbolic_system_->template view<dim, Number>();
307 for (std::size_t e = 0; e < boundary_map.size(); ++e) {
308 const auto &[i, normal, normal_mass, boundary_mass, id, position] =
325 const auto k = boundary_slots[e];
328 for (
unsigned int d = 0; d < n_comp; ++d)
329 U_i[d] = states[k * n_comp + d];
332 auto get_dirichlet = [position = position, t = t,
this]() {
333 return initial_values_->initial_state(position, t);
336 U_i = view.apply_boundary_conditions(
id, U_i, normal, get_dirichlet);
338 for (
unsigned int d = 0; d < n_comp; ++d)
339 states[k * n_comp + d] = U_i[d];
346 const auto U_view = U.template view<n_comp, MemorySpace>();
347 const auto *indices = boundary_indices.template view<MemorySpace>();
348 const auto *states = [&]() {
350 ComputingTimer::Scope scope(
351 "time step [X] _ - memory space transfers");
352 return std::as_const(boundary_states_).template view<MemorySpace>();
354 return std::as_const(boundary_states_).template view<MemorySpace>();
357 const auto body = [=](
auto ,
unsigned int k) {
359 for (
unsigned int d = 0; d < n_comp; ++d)
360 U_i[d] = states[k * n_comp + d];
361 U_view.write_tensor(U_i, indices[k]);
364 loop<MemorySpace, Number>(
"hyperbolic_kernel_01a",
386 template <
typename T>
387 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
bool
388 all_below_diagonal(
unsigned int i,
const unsigned int *js)
390 if constexpr (std::is_same_v<T, typename get_value_type<T>::type>) {
398 constexpr auto simd_length = T::size();
400 bool all_below_diagonal =
true;
401 for (
unsigned int k = 0; k < simd_length; ++k)
402 if (js[k] >= i + k) {
403 all_below_diagonal =
false;
406 return all_below_diagonal;
412 template <
typename HyperbolicDescription,
int dim,
typename Number>
419 Number tau_max )
const
421 switch (stage_state_vectors.size()) {
423 return step<0>(old_state_vector,
430 return step<1>(old_state_vector,
437 return step<2>(old_state_vector,
444 return step<3>(old_state_vector,
451 return step<4>(old_state_vector,
458 AssertThrow(
false, dealii::ExcMessage(
"Unsupported number of stages."));
464 template <
typename HyperbolicDescription,
int dim,
typename Number>
465 template <
int stages>
468 StageVectors stage_state_vectors,
469 StageWeights stage_weights,
472 Number tau_max)
const
474 Assert(stage_state_vectors.size() == stages &&
475 stage_weights.size() == stages,
476 dealii::ExcMessage(
"The number of stage state vectors and stage "
477 "weights must match the number of stages."));
480 std::cout <<
"HyperbolicModule<HyperbolicDescription, dim, Number>::step()"
486 copy_to_memory_space<MemorySpace>(
488 for (
int s = 0; s < stages; ++s)
489 copy_to_memory_space<MemorySpace>(stage_state_vectors.begin()[s].get(),
494 auto &[old_U, old_Q, old_U_dynamic, old_Q_dynamic] = old_state_vector;
495 auto &new_U = new_state_vector.
state;
518 constexpr bool shallow_water =
519 std::is_same_v<HyperbolicDescription,
524 const unsigned int n_internal = offline_data_->n_locally_internal();
525 const unsigned int n_owned = offline_data_->n_locally_owned();
529 const auto sparsity_simd_view =
530 offline_data_->sparsity_pattern_simd().template view<MemorySpace>();
532 const auto mass_matrix_view =
533 offline_data_->mass_matrix().template view<MemorySpace>();
534 const auto lumped_mass_matrix_view =
535 offline_data_->lumped_mass_matrix().template view<1, MemorySpace>();
536 const auto lumped_mass_matrix_inverse_view =
537 offline_data_->lumped_mass_matrix_inverse()
538 .template view<1, MemorySpace>();
540 const auto cij_matrix_view =
541 offline_data_->cij_matrix().template view<MemorySpace>();
547 const bool have_discontinuous_ansatz =
548 offline_data_->discretization().have_discontinuous_ansatz();
549 using MatrixReadView =
550 decltype(offline_data_->mass_matrix().template view<MemorySpace>());
551 const auto mass_matrix_inverse_view =
552 have_discontinuous_ansatz
553 ? offline_data_->mass_matrix_inverse().template view<MemorySpace>()
555 const auto incidence_matrix_view =
556 have_discontinuous_ansatz
557 ? offline_data_->incidence_matrix().template view<MemorySpace>()
560 const auto *coupling_boundary_pairs =
561 offline_data_->coupling_boundary_pairs().template view<MemorySpace>();
562 const auto n_coupling_boundary_pairs =
563 offline_data_->coupling_boundary_pairs().size();
565 const Number measure_of_omega_inverse =
566 Number(1.) / offline_data_->measure_of_omega();
570 const auto dij_matrix_view = dij_matrix_.template view<MemorySpace>();
571 const auto lij_matrix_view = lij_matrix_.template view<MemorySpace>();
572 const auto lij_matrix_next_view =
573 lij_matrix_next_.template view<MemorySpace>();
574 const auto pij_matrix_view = pij_matrix_.template view<MemorySpace>();
578 const auto initial_precomputed_view =
580 .template view<n_initial_precomputed_values, MemorySpace>();
582 const auto old_U_view =
583 old_U.template view<problem_dimension, MemorySpace>();
584 const auto old_precomputed_view =
585 old_Q.template view<n_precomputed_values, MemorySpace>();
592 using HyperbolicVectorView = std::remove_const_t<
decltype(old_U_view)>;
593 using PrecomputedVectorView =
594 std::remove_const_t<
decltype(old_precomputed_view)>;
596 Kokkos::Array<HyperbolicVectorView, stages> stage_U_view;
597 Kokkos::Array<PrecomputedVectorView, stages> stage_precomputed_view;
598 Kokkos::Array<Number, stages> stage_weight;
599 for (
int s = 0; s < stages; ++s) {
600 const auto &[U_s, Q_s, U_dynamic_s, Q_dynamic_s] =
601 stage_state_vectors.begin()[s].get();
602 stage_U_view[s] = U_s.template view<problem_dimension, MemorySpace>();
603 stage_precomputed_view[s] =
604 Q_s.template view<n_precomputed_values, MemorySpace>();
605 stage_weight[s] = stage_weights.begin()[s];
608 const auto new_U_view =
609 new_U.template view<problem_dimension, MemorySpace>();
611 const auto alpha_view = alpha_.template view<1, MemorySpace>();
612 const auto bounds_view = bounds_.template view<n_bounds, MemorySpace>();
613 const auto r_view = r_.template view<problem_dimension, MemorySpace>();
622 const Number cfl = this->cfl_;
624 const auto hyperbolic_system_views =
625 make_select_view<dim, Number, MemorySpace>(*hyperbolic_system_);
627 const auto indicator_views =
628 make_select_view<dim, Number, MemorySpace>(indicator_);
630 const auto limiter_views =
631 make_select_view<dim, Number, MemorySpace>(limiter_);
632 const auto n_limiter_iterations =
633 limiter_.template view<dim, Number>().iterations();
635 const auto wave_speed_estimator_views =
636 make_select_view<dim, Number, MemorySpace>(wave_speed_estimator_);
644 const auto scoped_name = [&step_no](
const auto &name,
645 const bool advance =
true) {
646 advance || step_no--;
647 return "time step [H] " + std::to_string(++step_no) +
" - " + name;
650 const auto loop_name = [&step_no]() {
651 return "hyperbolic_kernel_" + std::format(
"{:02}", step_no);
655 Mirrored<int> restart_needed(
"hyperbolic_module_restart_needed",
657 *restart_needed.view() = 0;
685 ComputingTimer::Scope scope(scoped_name(
"compute d_ij, and alpha_i"));
687 const auto body = [=](
auto sentinel,
unsigned int i) {
688 using T =
decltype(sentinel);
690 const unsigned int stride_size = sparsity_simd_view.stride_of_row(i);
692 const auto wave_speed_estimator_view =
693 wave_speed_estimator_views.template view<T>();
695 auto indicator_view = indicator_views.template view<T>();
698 const unsigned int row_length = sparsity_simd_view.row_length(i);
702 const auto U_i = old_U_view.template read_tensor<T>(i);
704 indicator_view.reset(old_precomputed_view, i, U_i);
706 const unsigned int *js = sparsity_simd_view.columns(i);
707 for (
unsigned int col_idx = 0; col_idx < row_length;
708 ++col_idx, js += stride_size) {
710 const auto U_j = old_U_view.template read_tensor<T>(js);
712 const auto c_ij = cij_matrix_view.template read_tensor<T>(i, col_idx);
714 indicator_view.accumulate(old_precomputed_view, js, U_j, c_ij);
721 if (all_below_diagonal<T>(i, js))
724 const auto norm = c_ij.norm();
725 const auto n_ij = c_ij / norm;
726 const auto lambda_max = wave_speed_estimator_view.compute(
727 old_precomputed_view, U_i, U_j, i, js, n_ij);
728 const auto d_ij = norm * lambda_max;
730 dij_matrix_view.write_entry(d_ij, i, col_idx,
true);
733 const auto mass = lumped_mass_matrix_view.template read_entry<T>(i);
734 const auto hd_i = mass * measure_of_omega_inverse;
735 alpha_view.template write_entry<T>(indicator_view.alpha(hd_i), i);
738 loop<MemorySpace, Number>(loop_name(), body, 0, n_internal, n_owned);
740 alpha_view.update_ghost_values();
750 ComputingTimer::Scope scope(
751 scoped_name(
"compute bdry d_ij, diag d_ii, and tau_max"));
767 const auto body_boundary = [=](
auto,
const unsigned int k) {
768 const auto &[i, col_idx, j] = coupling_boundary_pairs[k];
770 const auto wave_speed_estimator_view =
771 wave_speed_estimator_views.template view<Number>();
784 const auto U_i = old_U_view.read_tensor(i);
785 const auto U_j = old_U_view.read_tensor(j);
787 const auto c_ji = cij_matrix_view.read_transposed_tensor(i, col_idx);
788 Assert(c_ji.norm() > 1.e-12, ExcInternalError());
789 const auto norm_ji = c_ji.norm();
790 const auto n_ji = c_ji / norm_ji;
792 const auto d_ij = dij_matrix_view.read_entry(i, col_idx);
794 const auto lambda_max = wave_speed_estimator_view.compute(
795 old_precomputed_view, U_j, U_i, j, &i, n_ji);
796 const auto d_ji = norm_ji * lambda_max;
798 dij_matrix_view.write_entry(std::max(d_ij, d_ji), i, col_idx);
801 loop<MemorySpace, Number>(loop_name() +
'a',
805 n_coupling_boundary_pairs);
808 const auto body = [=](
auto,
unsigned int i) -> Number {
810#ifdef DEBUG_SYMMETRY_CHECK
811 const auto wave_speed_estimator_view =
812 wave_speed_estimator_views.template view<Number>();
816 const unsigned int row_length = sparsity_simd_view.row_length(i);
818 return std::numeric_limits<Number>::max();
820 Number d_sum = Number(0.);
823 const unsigned int stride_size = sparsity_simd_view.stride_of_row(i);
824 const unsigned int *js = sparsity_simd_view.columns(i);
825 for (
unsigned int col_idx = 1; col_idx < row_length; ++col_idx) {
826 const auto j = *(js + col_idx * stride_size);
830 const auto d_ji = dij_matrix_view.read_transposed_entry(i, col_idx);
832#ifdef DEBUG_SYMMETRY_CHECK
835 const auto U_i = old_U_view.read_tensor(i);
836 const auto U_j = old_U_view.read_tensor(j);
838 const auto c_ij = cij_matrix_view.read_tensor(i, col_idx);
839 Assert(c_ij.norm() > 1.e-12, ExcInternalError());
840 const auto norm_ij = c_ij.norm();
841 const auto n_ij = c_ij / norm_ij;
843 const auto lambda_max = wave_speed_estimator_view.compute(
844 old_precomputed_view, U_i, U_j, i, &j, n_ij);
845 const auto d_ij = norm_ij * lambda_max;
847 Assert(d_ij <= d_ji + 1.0e-12,
848 dealii::ExcMessage(
"d_ij not symmetrized correctly on "
849 "boundary degrees of freedom."));
852 dij_matrix_view.write_entry(d_ji, i, col_idx);
855 d_sum -= dij_matrix_view.read_entry(i, col_idx);
864 std::min(d_sum, Number(-1.e6) * std::numeric_limits<Number>::min());
867 dij_matrix_view.write_entry(d_sum, i, 0);
869 const Number mass = lumped_mass_matrix_view.read_entry(i);
870 return cfl * mass / (Number(-2.) * d_sum);
873 reduction_loop<MemorySpace>(
874 loop_name() +
'b', body, Kokkos::Min<Number>(tau_max), 0, n_owned);
878 ComputingTimer::Scope scope(
"time step [X] _ - synchronization barriers");
884 tau_max = Utilities::MPI::min(
885 tau_max, mpi_ensemble_.synchronization_communicator());
888 !std::isnan(tau_max) && !std::isinf(tau_max) && tau_max > 0.,
890 "I'm sorry, Dave. I'm afraid I can't do that.\nWe crashed."));
892 tau = (tau == Number(0.) ? tau_max : tau);
895 std::cout <<
" computed tau_max = " << tau_max <<
" (CFL = " << cfl
897 std::cout <<
" step with tau = " << tau << std::endl;
901 *restart_needed.view() =
902 (tau > this->acceptable_tau_max_ratio_ * tau_max);
905 if (*restart_needed.view() && this->id_violation_strategy_ ==
910 std::cout <<
" signalling restart (suggested_tau_max = "
911 << tau_max <<
")" << std::endl;
914 throw Restart{tau_max};
919 int *restart_needed_view = restart_needed.view<MemorySpace>();
923 dij_matrix_view.update_ghost_rows();
933 ComputingTimer::Scope scope(
934 scoped_name(
"l.-o. update, compute bounds, r_i, and p_ij"));
936 const Number weight =
937 -std::accumulate(stage_weights.begin(), stage_weights.end(), -1.);
939 const auto body = [=](
auto sentinel,
940 auto have_discontinuous_ansatz,
941 const unsigned int i) {
942 using T =
decltype(sentinel);
944 const auto view = hyperbolic_system_views.template view<T>();
946 using View =
decltype(view);
947 using flux_contribution_type =
typename View::flux_contribution_type;
948 using state_type =
typename View::state_type;
950 const unsigned int stride_size = sparsity_simd_view.stride_of_row(i);
952 auto limiter_view = limiter_views.template view<T>();
955 const unsigned int row_length = sparsity_simd_view.row_length(i);
959 const auto U_i = old_U_view.template read_tensor<T>(i);
962 const auto alpha_i = alpha_view.template read_entry<T>(i);
963 const auto m_i = lumped_mass_matrix_view.template read_entry<T>(i);
965 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
967 const auto flux_i = view.flux_contribution(
968 old_precomputed_view, initial_precomputed_view, i, U_i);
970 Kokkos::Array<flux_contribution_type, stages> flux_iHs;
971 [[maybe_unused]] state_type S_iH;
973 for (
int s = 0; s < stages; ++s) {
974 const auto U_iHs = stage_U_view[s].template read_tensor<T>(i);
975 flux_iHs[s] = view.flux_contribution(
976 stage_precomputed_view[s], initial_precomputed_view, i, U_iHs);
978 if constexpr (View::have_source_terms) {
979 S_iH += stage_weight[s] *
980 view.nodal_source(stage_precomputed_view[s], i, U_iHs, tau);
984 [[maybe_unused]] state_type S_i;
987 if constexpr (View::have_source_terms) {
988 S_i = view.nodal_source(old_precomputed_view, i, U_i, tau);
989 S_iH += weight * S_i;
990 U_i_new += tau * S_i;
994 limiter_view.reset(old_precomputed_view, i, U_i, flux_i);
996 [[maybe_unused]] state_type affine_shift;
1004 const unsigned int *js = sparsity_simd_view.columns(i);
1005 if constexpr (shallow_water) {
1006 for (
unsigned int col_idx = 0; col_idx < row_length;
1007 ++col_idx, js += stride_size) {
1009 const auto U_j = old_U_view.template read_tensor<T>(js);
1010 const auto flux_j = view.flux_contribution(
1011 old_precomputed_view, initial_precomputed_view, js, U_j);
1014 dij_matrix_view.template read_entry<T>(i, col_idx);
1016 cij_matrix_view.template read_tensor<T>(i, col_idx);
1018 const auto B_ij = view.affine_shift(flux_i, flux_j, c_ij, d_ij);
1019 affine_shift += B_ij;
1022 affine_shift *= tau * m_i_inv;
1025 if constexpr (View::have_source_terms) {
1026 affine_shift += tau * S_i;
1029 js = sparsity_simd_view.columns(i);
1030 for (
unsigned int col_idx = 0; col_idx < row_length;
1031 ++col_idx, js += stride_size) {
1033 const auto U_j = old_U_view.template read_tensor<T>(js);
1035 const auto alpha_j = alpha_view.template read_entry<T>(js);
1037 const auto d_ij = dij_matrix_view.template read_entry<T>(i, col_idx);
1038 auto factor = (alpha_i + alpha_j) * Number(.5);
1040 if constexpr (have_discontinuous_ansatz) {
1041 const auto incidence_ij =
1042 incidence_matrix_view.template read_entry<T>(i, col_idx);
1043 factor = std::max(factor, incidence_ij);
1046 const auto d_ijH = d_ij * factor;
1048#ifdef DEBUG_SYMMETRY_CHECK
1056 dij_matrix_view.template read_transposed_entry<T>(i, col_idx);
1057 Assert(std::max(std::abs(d_ij - d_ji), T(1.0e-12)) == T(1.0e-12),
1059 "d_ij not symmetrized correctly over MPI ranks"));
1062 const auto c_ij = cij_matrix_view.template read_tensor<T>(i, col_idx);
1063 constexpr auto eps = std::numeric_limits<Number>::epsilon();
1066 ryujin::compare_and_apply_mask<dealii::SIMDComparison::less_than>(
1067 std::abs(d_ij), T(eps * eps), T(0.), T(1.) / d_ij);
1069 const auto scaled_c_ij = c_ij * scale;
1071 const auto flux_j = view.flux_contribution(
1072 old_precomputed_view, initial_precomputed_view, js, U_j);
1074 const auto m_ij = mass_matrix_view.template read_entry<T>(i, col_idx);
1080 const auto flux_ij = view.flux_divergence(flux_i, flux_j, c_ij);
1081 U_i_new += tau * m_i_inv * flux_ij;
1082 auto P_ij = -flux_ij;
1084 if constexpr (shallow_water) {
1089 const auto &[U_star_ij, U_star_ji] =
1090 view.equilibrated_states(flux_i, flux_j);
1092 U_i_new += tau * m_i_inv * d_ij * (U_star_ji - U_star_ij);
1093 F_iH += d_ijH * (U_star_ji - U_star_ij);
1094 P_ij += (d_ijH - d_ij) * (U_star_ji - U_star_ij);
1096 limiter_view.accumulate(old_precomputed_view,
1105 U_i_new += tau * m_i_inv * d_ij * (U_j - U_i);
1106 F_iH += d_ijH * (U_j - U_i);
1107 P_ij += (d_ijH - d_ij) * (U_j - U_i);
1109 limiter_view.accumulate(old_precomputed_view,
1117 if constexpr (View::have_source_terms) {
1118 F_iH -= m_ij * S_iH;
1126 if constexpr (View::have_high_order_flux) {
1127 const auto high_order_flux_ij =
1128 view.high_order_flux_divergence(flux_i, flux_j, c_ij);
1129 F_iH += weight * high_order_flux_ij;
1130 P_ij += weight * high_order_flux_ij;
1132 F_iH += weight * flux_ij;
1133 P_ij += weight * flux_ij;
1136 if constexpr (View::have_source_terms) {
1138 view.nodal_source(old_precomputed_view, js, U_j, tau);
1139 F_iH += weight * m_ij * S_j;
1140 P_ij += weight * m_ij * S_j;
1143 for (
int s = 0; s < stages; ++s) {
1144 const auto U_jHs = stage_U_view[s].template read_tensor<T>(js);
1145 const auto flux_jHs = view.flux_contribution(
1146 stage_precomputed_view[s], initial_precomputed_view, js, U_jHs);
1148 if constexpr (View::have_high_order_flux) {
1149 const auto high_order_flux_ij =
1150 view.high_order_flux_divergence(flux_iHs[s], flux_jHs, c_ij);
1151 F_iH += stage_weight[s] * high_order_flux_ij;
1152 P_ij += stage_weight[s] * high_order_flux_ij;
1154 const auto flux_ij =
1155 view.flux_divergence(flux_iHs[s], flux_jHs, c_ij);
1156 F_iH += stage_weight[s] * flux_ij;
1157 P_ij += stage_weight[s] * flux_ij;
1160 if constexpr (View::have_source_terms) {
1162 view.nodal_source(stage_precomputed_view[s], js, U_jHs, tau);
1163 F_iH += stage_weight[s] * m_ij * S_js;
1164 P_ij += stage_weight[s] * m_ij * S_js;
1168 pij_matrix_view.template write_tensor<T>(P_ij, i, col_idx,
true);
1171#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
1172 if (!view.is_admissible(U_i_new)) {
1173 atomic_store(restart_needed_view, 1);
1177 new_U_view.template write_tensor<T>(U_i_new, i);
1178 r_view.template write_tensor<T>(F_iH, i);
1180 const auto hd_i = m_i * measure_of_omega_inverse;
1181 const auto relaxed_bounds = limiter_view.bounds(hd_i);
1182 bounds_view.template write_tensor<T>(relaxed_bounds, i);
1191 if (have_discontinuous_ansatz) {
1192 loop<MemorySpace, Number>(
1193 loop_name(), body, 0, n_internal, n_owned, std::true_type{});
1195 loop<MemorySpace, Number>(
1196 loop_name(), body, 0, n_internal, n_owned, std::false_type{});
1199 r_view.update_ghost_values();
1200 if (have_discontinuous_ansatz) {
1206 bounds_view.update_ghost_values();
1216 if (n_limiter_iterations != 0) {
1217 ComputingTimer::Scope scope(scoped_name(
"compute p_ij, and l_ij"));
1219 const auto body = [=](
auto sentinel,
1220 auto have_discontinuous_ansatz,
1221 const unsigned int i) {
1222 using T =
decltype(sentinel);
1224 const unsigned int stride_size = sparsity_simd_view.stride_of_row(i);
1226 auto limiter_view = limiter_views.template view<T>();
1229 const unsigned int row_length = sparsity_simd_view.row_length(i);
1230 if (row_length == 1)
1234 bounds_view.template read_tensor<T, std::array<T, n_bounds>>(i);
1241 if constexpr (have_discontinuous_ansatz) {
1243 const unsigned int *js = sparsity_simd_view.columns(i) + stride_size;
1244 for (
unsigned int col_idx = 1; col_idx < row_length;
1245 ++col_idx, js += stride_size) {
1246 local_bounds = limiter_view.combine_bounds(
1248 bounds_view.template read_tensor<T, std::array<T, n_bounds>>(
1251 bounds_view.template write_tensor<T>(local_bounds, i);
1254 [[maybe_unused]] T m_i;
1255 if constexpr (have_discontinuous_ansatz)
1256 m_i = lumped_mass_matrix_view.template read_entry<T>(i);
1258 const auto m_i_inv =
1259 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
1261 const auto U_i_new = new_U_view.template read_tensor<T>(i);
1263 const auto F_iH = r_view.template read_tensor<T>(i);
1265 const auto lambda_inv = Number(row_length - 1);
1266 const auto factor = tau * m_i_inv * lambda_inv;
1276 auto P_ij = pij_matrix_view.template read_tensor<T>(i, 1);
1279 const unsigned int *js = sparsity_simd_view.columns(i) + stride_size;
1280 for (
unsigned int col_idx = 1; col_idx < row_length;
1281 ++col_idx, js += stride_size) {
1283 const auto P_ij_next = pij_matrix_view.template read_tensor<T>(
1284 i, col_idx + 1 < row_length ? col_idx + 1 : col_idx);
1285 const auto F_jH = r_view.template read_tensor<T>(js);
1291 const auto kronecker_ij = col_idx == 0 ? T(1.) : T(0.);
1293 if constexpr (have_discontinuous_ansatz) {
1296 const auto m_j = lumped_mass_matrix_view.template read_entry<T>(js);
1297 const auto m_ij_inv =
1298 mass_matrix_inverse_view.template read_entry<T>(i, col_idx);
1299 const auto b_ij = m_i * m_ij_inv - kronecker_ij;
1300 const auto b_ji = m_j * m_ij_inv - kronecker_ij;
1302 P_ij += b_ij * F_jH - b_ji * F_iH;
1307 const auto m_j_inv =
1308 lumped_mass_matrix_inverse_view.template read_entry<T>(js);
1310 mass_matrix_view.template read_entry<T>(i, col_idx);
1311 const auto b_ij = kronecker_ij - m_ij * m_j_inv;
1312 const auto b_ji = kronecker_ij - m_ij * m_i_inv;
1314 P_ij += b_ij * F_jH - b_ji * F_iH;
1318 pij_matrix_view.template write_tensor<T>(P_ij, i, col_idx);
1324 const auto &[l_ij, success] =
1325 limiter_view.limit(local_bounds, U_i_new, P_ij);
1326 lij_matrix_view.template write_entry<T>(l_ij, i, col_idx,
true);
1337 atomic_store(restart_needed_view, 1);
1349 if (have_discontinuous_ansatz) {
1350 loop<MemorySpace, Number>(
1351 loop_name(), body, 0, n_internal, n_owned, std::true_type{});
1353 loop<MemorySpace, Number>(
1354 loop_name(), body, 0, n_internal, n_owned, std::false_type{});
1357 lij_matrix_view.update_ghost_rows();
1370 for (
unsigned int pass = 0; pass < n_limiter_iterations; ++pass) {
1371 bool last_round = (pass + 1 == n_limiter_iterations);
1373 std::string additional_step = (last_round ?
"" :
", next l_ij");
1374 ComputingTimer::Scope scope(
1375 scoped_name(
"symmetrize l_ij, h.-o. update" + additional_step));
1377 const auto lij_view = (n_limiter_iterations == 2 && last_round)
1378 ? lij_matrix_next_view
1381 const auto body = [=](
auto sentinel,
const unsigned int i) {
1382 using T =
decltype(sentinel);
1384 auto limiter_view = limiter_views.template view<T>();
1387 const unsigned int row_length = sparsity_simd_view.row_length(i);
1388 if (row_length == 1)
1391 auto U_i_new = new_U_view.template read_tensor<T>(i);
1393 const Number lambda = Number(1.) / Number(row_length - 1);
1396 for (
unsigned int col_idx = 1; col_idx < row_length; ++col_idx) {
1399 std::min(lij_view.template read_entry<T>(i, col_idx),
1400 lij_view.template read_transposed_entry<T>(i, col_idx));
1402 const auto p_ij = pij_matrix_view.template read_tensor<T>(i, col_idx);
1404 U_i_new += l_ij * lambda * p_ij;
1407#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
1408 const auto view = hyperbolic_system_views.template view<T>();
1409 if (!view.is_admissible(U_i_new)) {
1410 atomic_store(restart_needed_view, 1);
1414 new_U_view.template write_tensor<T>(U_i_new, i);
1420 const auto local_bounds =
1421 bounds_view.template read_tensor<T, std::array<T, n_bounds>>(i);
1423 for (
unsigned int col_idx = 1; col_idx < row_length; ++col_idx) {
1425 const auto old_l_ij =
1426 std::min(lij_view.template read_entry<T>(i, col_idx),
1427 lij_view.template read_transposed_entry<T>(i, col_idx));
1429 const auto new_p_ij =
1430 (T(1.) - old_l_ij) *
1431 pij_matrix_view.template read_tensor<T>(i, col_idx);
1433 const auto &[new_l_ij, success] =
1434 limiter_view.limit(local_bounds, U_i_new, new_p_ij);
1446#ifdef DEBUG_EXPENSIVE_BOUNDS_CHECK
1448 atomic_store(restart_needed_view, 1);
1457 const auto entry = (T(1.) - old_l_ij) * new_l_ij;
1458 lij_matrix_next_view.write_entry(entry, i, col_idx,
true);
1462 loop<MemorySpace, Number>(loop_name(), body, 0, n_internal, n_owned);
1465 lij_matrix_next_view.update_ghost_rows();
1479 ComputingTimer::Scope scope(
"time step [X] _ - synchronization barriers");
1490 int &restart_flag = *restart_needed.view();
1491 restart_flag = Utilities::MPI::logical_or(
1492 restart_flag != 0, mpi_ensemble_.synchronization_communicator());
1495 if (*restart_needed.view()) {
1496 switch (this->id_violation_strategy_) {
1498 this->n_warnings_++;
1500 std::cout <<
" raised warning, CFL/IDP violation encountered "
1505 this->n_restarts_++;
1508 std::cout <<
" signalling restart (suggested_tau_max = "
1509 << tau_max <<
")" << std::endl;
1511 throw Restart{tau_max};
static dealii::Timer & timer(const std::string §ion)
typename Interface::HyperbolicModule< dim, Number >::StageWeights StageWeights
HyperbolicModule(const MPIEnsemble &mpi_ensemble, const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const InitialValues< HyperbolicDescription, dim, Number > &initial_values, const std::string &subsection="/HyperbolicModule")
typename HyperbolicDescription::HyperbolicSystem HyperbolicSystem
typename Interface::HyperbolicModule< dim, Number >::StageVectors StageVectors
void prepare_state_vector(StateVector< Number > &state_vector, Number t) const override
void reinit_state_vector(StateVector< Number > &state_vector) const override
void fill_precomputed_values(StateVector< Number > &state_vector) const override
Number step(const StateVector< Number > &old_state_vector, StageVectors stage_state_vectors, StageWeights stage_weights, StateVector< Number > &new_state_vector, Number tau=Number(0.), Number tau_max=std::numeric_limits< Number >::max()) const override
std::conditional_t< have_separate_memory_spaces, dealii::MemorySpace::Default, dealii::MemorySpace::Host > selected_memory_space_t
constexpr bool have_separate_memory_spaces
void debug_poison_invalid_values(StateVector< Number > &state_vector, const OfflineData &offline_data)
std::vector< ScalarVector< Number > > dynamic_state
MultiComponentVector< Number > state
MultiComponentVector< Number > precomputed