ryujin 2.1.1 revision ee5cbcbf2346c1299c942d0e1f13b46449973c18
Loading...
Searching...
No Matches
hyperbolic_system.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2023 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include <compile_time_options.h>
9
10#include "flux_library.h"
11
12#include <convenience_macros.h>
13#include <discretization.h>
14#include <loop.h>
16#include <patterns_conversion.h>
17#include <simd.h>
18#include <state_vector.h>
19
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 ScalarConservation
28 {
29 template <int dim, typename Number>
30 class HyperbolicSystemView;
31
38 class HyperbolicSystem final : public dealii::ParameterAcceptor
39 {
40 public:
44 static inline std::string problem_name = "Scalar conservation equation";
45
49 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
50
55 template <int dim, typename Number = double>
57
64 template <int dim, typename Number>
65 auto view() const
66 {
67 return View<dim, Number>{*this};
68 }
69
78 template <int dim, typename ScalarNumber>
80 const OfflineData<dim, ScalarNumber> &offline_data,
82 &state_vector,
83 const bool skip_constrained_dofs = true) const;
84
85 private:
90
91 std::string flux_;
92
94
98
100
101 using Flux = FluxLibrary::Flux;
102 std::shared_ptr<Flux> selected_flux_;
103
104 template <int dim, typename Number>
106
108 }; /* HyperbolicSystem */
109
110
118 template <int dim, typename Number>
120 {
121 public:
126
131
135 static constexpr unsigned int problem_dimension = 1;
136
140 using state_type = dealii::Tensor<1, problem_dimension, Number>;
141
145 using flux_type =
146 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
147
152
157 static inline const auto component_names =
158 std::array<std::string, problem_dimension>{"u"};
159
164 static inline const auto primitive_component_names =
165 std::array<std::string, problem_dimension>{"u"};
166
170 static constexpr unsigned int n_precomputed_values = 2 * dim;
171
175 using precomputed_type = std::array<Number, n_precomputed_values>;
176
180 static inline const auto precomputed_names =
181 []() -> std::array<std::string, n_precomputed_values> {
182 if constexpr (dim == 1)
183 return {"f", "df"};
184 else if constexpr (dim == 2)
185 return {"f_1", "f_2", "df_1", "df_2"};
186 else if constexpr (dim == 3)
187 return {"f_1", "f_2", "f_3", "df_1", "df_2", "df_3"};
188 __builtin_trap();
189 }();
190
194 static constexpr unsigned int n_initial_precomputed_values = 0;
195
200 std::array<Number, n_initial_precomputed_values>;
201
205 static inline const auto initial_precomputed_names =
206 std::array<std::string, n_initial_precomputed_values>{};
207
211 using StateVector = Vectors::
212 StateVector<ScalarNumber, problem_dimension, n_precomputed_values>;
213
219
225
233 dealii::VectorizedArray<ScalarNumber>::size(),
234 dealii::MemorySpace::Host,
235 /*writable=*/false>;
236
244
252 dealii::VectorizedArray<ScalarNumber>::size(),
253 dealii::MemorySpace::Host,
254 /*writable=*/false>;
255
257
261
266 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
267 : hyperbolic_system_(hyperbolic_system)
268 {
269 }
270
272
276
277 DEAL_II_ALWAYS_INLINE inline const std::string &flux() const
278 {
279 return hyperbolic_system_.flux_;
280 }
281
282 DEAL_II_ALWAYS_INLINE inline ScalarNumber
284 {
285 const auto &flux = hyperbolic_system_.selected_flux_;
286 return ScalarNumber(flux->derivative_approximation_delta());
287 }
288
290
294
298 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
299 flux_function(const Number &u) const;
300
304 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
305 flux_gradient_function(const Number &u) const;
306
308
312
319 static Number state(const state_type &U);
320
327 Number square_entropy(const Number &u) const;
328
336 Number square_entropy_derivative(const Number &u) const;
337
344 Number kruzkov_entropy(const Number &k, const Number &u) const;
345
353 Number kruzkov_entropy_derivative(const Number &k, const Number &u) const;
354
360 bool is_admissible(const state_type & /*U*/) const
361 {
362 return true;
363 }
364
366
370
374 template <typename Lambda>
376 apply_boundary_conditions(const dealii::types::boundary_id id,
377 const state_type &U,
378 const dealii::Tensor<1, dim, Number> &normal,
379 const Lambda &get_dirichlet_data) const;
380
382
386
391 dealii::Tensor<1, dim, Number>
392 construct_flux_tensor(const precomputed_type &precomputed_state) const;
393
399 dealii::Tensor<1, dim, Number> construct_flux_gradient_tensor(
400 const precomputed_type &precomputed_state) const;
401
423 const InitialPrecomputedVectorView & /*piv*/,
424 const unsigned int i,
425 const state_type & /*U_i*/) const;
426
429 const InitialPrecomputedVectorView & /*piv*/,
430 const unsigned int *js,
431 const state_type & /*U_j*/) const;
432
439 const flux_contribution_type &flux_j,
440 const dealii::Tensor<1, dim, Number> &c_ij) const;
441
443 static constexpr bool have_high_order_flux = false;
444
448 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
449
451
455
457 static constexpr bool have_source_terms = false;
458
460 const unsigned int i,
461 const state_type &U_i,
462 const ScalarNumber tau) const = delete;
463
465 const unsigned int *js,
466 const state_type &U_j,
467 const ScalarNumber tau) const = delete;
468
470
474
485 template <typename ST>
487 {
488 return state;
489 }
490
495 state_type from_primitive_state(const state_type &primitive_state) const
496 {
497 return primitive_state;
498 }
499
505 {
506 return state;
507 }
508
514 template <typename Lambda>
516 const Lambda & /*lambda*/) const
517 {
518 return state;
519 }
520
521 private:
523
527
528 const HyperbolicSystem &hyperbolic_system_;
529
531 }; /* HyperbolicSystemView */
532
533
534 /*
535 * -------------------------------------------------------------------------
536 * Inline definitions
537 * -------------------------------------------------------------------------
538 */
539
540
541 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
542 : ParameterAcceptor(subsection)
543 {
544 flux_ = "burgers";
545 add_parameter("flux",
546 flux_,
547 "The scalar flux. Valid names are given by any of the "
548 "subsections defined below");
549
550 /*
551 * And finally populate the flux list with all flux configurations
552 * defined in the FluxLibrary namespace:
553 */
554 FluxLibrary::populate_flux_list(flux_list_, subsection);
555
556 const auto populate_functions = [this]() {
557 bool initialized = false;
558 for (auto &it : flux_list_)
559
560 /* Populate flux functions: */
561 if (it->name() == flux_) {
562 selected_flux_ = it;
563 it->parse_parameters_call_back();
564 problem_name = "Scalar conservation equation (" + it->name() +
565 ": " + it->flux_formula() + ")";
566 initialized = true;
567 break;
568 }
569
570 AssertThrow(initialized,
571 dealii::ExcMessage(
572 "Could not find a flux description with name \"" +
573 flux_ + "\""));
574 };
575
576 ParameterAcceptor::parse_parameters_call_back.connect(populate_functions);
577 populate_functions();
578 }
579
580
581 template <int dim, typename ScalarNumber>
583 const OfflineData<dim, ScalarNumber> &offline_data,
585 &state_vector,
586 const bool skip_constrained_dofs) const
587 {
588 const unsigned int n_internal = offline_data.n_locally_internal();
589 const unsigned int n_owned = offline_data.n_locally_owned();
590 const auto sparsity_simd_view =
591 offline_data.sparsity_pattern_simd().view();
592 using VA = dealii::VectorizedArray<ScalarNumber>;
593
594 const auto U_view = std::get<0>(state_vector).view();
595 const auto precomputed_view = std::get<1>(state_vector).view();
596
597 const auto body = [&](auto sentinel, unsigned int i) {
598 using T = decltype(sentinel);
600 using precomputed_type = typename View::precomputed_type;
601
602 const unsigned int row_length = sparsity_simd_view.row_length(i);
603 if (skip_constrained_dofs && row_length == 1)
604 return;
605
606 const auto U_i = U_view.template read_tensor<T>(i);
607 const auto view = this->view<dim, T>();
608 const auto u_i = view.state(U_i);
609 const auto f_i = view.flux_function(u_i);
610 const auto df_i = view.flux_gradient_function(u_i);
611
612 precomputed_type prec_i;
613 for (unsigned int k = 0; k < View::n_precomputed_values / 2; ++k) {
614 prec_i[k] = f_i[k];
615 prec_i[dim + k] = df_i[k];
616 }
617
618 precomputed_view.template write_tensor<T>(prec_i, i);
619 };
620
621 cpu_simd_loop<ScalarNumber>("time_step_1", body, 0, n_internal, n_owned);
622 }
623
624
625 template <int dim, typename Number>
626 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
628 {
629 const auto &flux = hyperbolic_system_.selected_flux_;
630 dealii::Tensor<1, dim, Number> result;
631
632 /* This access by calling into value() repeatedly is terrible: */
633 for (unsigned int k = 0; k < dim; ++k) {
634 if constexpr (std::is_same_v<ScalarNumber, Number>) {
635 result[k] = flux->value(u, k);
636 } else {
637 for (unsigned int s = 0; s < Number::size(); ++s) {
638 result[k][s] = flux->value(u[s], k);
639 }
640 }
641 }
642
643 return result;
644 }
645
646 template <int dim, typename Number>
647 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
649 const Number &u) const
650 {
651 const auto &flux = hyperbolic_system_.selected_flux_;
652 dealii::Tensor<1, dim, Number> result;
653
654 /* This access by calling into value() repeatedly is terrible: */
655 for (unsigned int k = 0; k < dim; ++k) {
656 if constexpr (std::is_same_v<ScalarNumber, Number>) {
657 result[k] = flux->gradient(u, k);
658 } else {
659 for (unsigned int s = 0; s < Number::size(); ++s) {
660 result[k][s] = flux->gradient(u[s], k);
661 }
662 }
663 }
664
665 return result;
666 }
667
668
669 template <int dim, typename Number>
670 DEAL_II_ALWAYS_INLINE inline Number
672 {
673 return U[0];
674 }
675
676
677 template <int dim, typename Number>
678 DEAL_II_ALWAYS_INLINE inline Number
680 {
681 return ScalarNumber(0.5) * u * u;
682 }
683
684
685 template <int dim, typename Number>
686 DEAL_II_ALWAYS_INLINE inline Number
688 const Number &u) const
689 {
690 return u;
691 }
692
693
694 template <int dim, typename Number>
695 DEAL_II_ALWAYS_INLINE inline Number
697 const Number &u) const
698 {
699 return std::abs(k - u);
700 }
701
702
703 template <int dim, typename Number>
704 DEAL_II_ALWAYS_INLINE inline Number
706 const Number &k, const Number &u) const
707 {
708 constexpr auto gte = dealii::SIMDComparison::greater_than_or_equal;
709 // return sgn(u-k):
710 return dealii::compare_and_apply_mask<gte>(u, k, Number(1.), Number(-1.));
711 }
712
713
714 template <int dim, typename Number>
715 template <typename Lambda>
716 DEAL_II_ALWAYS_INLINE inline auto
718 dealii::types::boundary_id id,
719 const state_type &U,
720 const dealii::Tensor<1, dim, Number> & /*normal*/,
721 const Lambda &get_dirichlet_data) const -> state_type
722 {
723 state_type result = U;
724
725 if (id == Boundary::dirichlet) {
726 result = get_dirichlet_data();
727
728 } else if (id == Boundary::dirichlet_momentum) {
729 AssertThrow(false,
730 dealii::ExcMessage(
731 "Invalid boundary ID »Boundary::dirichlet_momentum«, "
732 "enforcing Dirichlet boundary conditions on a momentum "
733 "is not possible for scalar conservation equations."));
734
735 } else if (id == Boundary::dirichlet_velocity) {
736 AssertThrow(false,
737 dealii::ExcMessage(
738 "Invalid boundary ID »Boundary::dirichlet_velocity«, "
739 "enforcing Dirichlet boundary conditions on a momentum "
740 "is not possible for scalar conservation equations."));
741
742 } else if (id == Boundary::slip) {
743 AssertThrow(
744 false,
745 dealii::ExcMessage("Invalid boundary ID »Boundary::slip«, slip "
746 "boundary conditions are unavailable for scalar "
747 "conservation equations."));
748 __builtin_trap();
749
750 } else if (id == Boundary::no_slip) {
751 AssertThrow(
752 false,
753 dealii::ExcMessage("Invalid boundary ID »Boundary::no_slip«, "
754 "no-slip boundary conditions are unavailable "
755 "for scalar conservation equations."));
756 __builtin_trap();
757
758 } else if (id == Boundary::dynamic) {
759 AssertThrow(
760 false,
761 dealii::ExcMessage("Invalid boundary ID »Boundary::dynamic«, "
762 "dynamic boundary conditions are unavailable "
763 "for scalar conservation equations."));
764 __builtin_trap();
765
766 } else {
767 AssertThrow(false, dealii::ExcNotImplemented());
768 }
769
770 return result;
771 }
772
773
774 template <int dim, typename Number>
775 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
777 const precomputed_type &precomputed) const
778 {
779 dealii::Tensor<1, dim, Number> result;
780
781 if constexpr (dim == 1) {
782 const auto &[f, df] = precomputed;
783 result[0] = f;
784
785 } else if constexpr (dim == 2) {
786 const auto &[f_1, f_2, df_1, df_2] = precomputed;
787 result[0] = f_1;
788 result[1] = f_2;
789
790 } else if constexpr (dim == 3) {
791 const auto &[f_1, f_2, f_3, df_1, df_2, df_3] = precomputed;
792 result[0] = f_1;
793 result[1] = f_2;
794 result[2] = f_3;
795 }
796
797 return result;
798 }
799
800
801 template <int dim, typename Number>
802 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
804 const precomputed_type &precomputed) const
805 {
806 dealii::Tensor<1, dim, Number> result;
807
808 if constexpr (dim == 1) {
809 const auto &[f, df] = precomputed;
810 result[0] = df;
811
812 } else if constexpr (dim == 2) {
813 const auto &[f_1, f_2, df_1, df_2] = precomputed;
814 result[0] = df_1;
815 result[1] = df_2;
816
817 } else if constexpr (dim == 3) {
818 const auto &[f_1, f_2, f_3, df_1, df_2, df_3] = precomputed;
819 result[0] = df_1;
820 result[1] = df_2;
821 result[2] = df_3;
822 }
823
824 return result;
825 }
826
827
828 template <int dim, typename Number>
829 DEAL_II_ALWAYS_INLINE inline auto
831 const PrecomputedVectorView &pv,
832 const InitialPrecomputedVectorView & /*piv*/,
833 const unsigned int i,
834 const state_type & /*U_i*/) const -> flux_contribution_type
835 {
836 /* The flux contribution is a rank 2 tensor, thus a little dance: */
838 result[0] = construct_flux_tensor(
839 pv.template read_tensor<Number, precomputed_type>(i));
840 return result;
841 }
842
843
844 template <int dim, typename Number>
845 DEAL_II_ALWAYS_INLINE inline auto
847 const PrecomputedVectorView &pv,
848 const InitialPrecomputedVectorView & /*piv*/,
849 const unsigned int *js,
850 const state_type & /*U_j*/) const -> flux_contribution_type
851 {
852 /* The flux contribution is a rank 2 tensor, thus a little dance: */
854 result[0] = construct_flux_tensor(
855 pv.template read_tensor<Number, precomputed_type>(js));
856 return result;
857 }
858
859
860 template <int dim, typename Number>
861 DEAL_II_ALWAYS_INLINE inline auto
863 const flux_contribution_type &flux_i,
864 const flux_contribution_type &flux_j,
865 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
866 {
867 return -contract(add(flux_i, flux_j), c_ij);
868 }
869
870 } // namespace ScalarConservation
871} // namespace ryujin
dealii::Tensor< 1, problem_dimension, Number > state_type
const auto & n_locally_owned() const
const auto & sparsity_pattern_simd() const
const auto & n_locally_internal() const
state_type apply_galilei_transform(const state_type &state, const Lambda &) const
Number kruzkov_entropy_derivative(const Number &k, const Number &u) const
DEAL_II_ALWAYS_INLINE const std::string & flux() const
HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, dim, Number > flux_function(const Number &u) const
state_type nodal_source(const PrecomputedVectorView &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
dealii::Tensor< 1, problem_dimension, dealii::Tensor< 1, dim, Number > > flux_type
std::array< Number, n_initial_precomputed_values > initial_precomputed_type
state_type from_primitive_state(const state_type &primitive_state) const
std::array< Number, n_precomputed_values > precomputed_type
Number square_entropy_derivative(const Number &u) const
dealii::Tensor< 1, dim, Number > construct_flux_gradient_tensor(const precomputed_type &precomputed_state) const
state_type to_primitive_state(const state_type &state) const
DEAL_II_ALWAYS_INLINE ScalarNumber derivative_approximation_delta() const
typename get_value_type< Number >::type ScalarNumber
Number kruzkov_entropy(const Number &k, const Number &u) const
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, dim, Number > flux_gradient_function(const Number &u) const
static constexpr unsigned int n_initial_precomputed_values
dealii::Tensor< 1, problem_dimension, Number > state_type
state_type expand_state(const ST &state) const
state_type high_order_flux_divergence(const flux_contribution_type &, const flux_contribution_type &, const dealii::Tensor< 1, dim, Number > &c_ij) const =delete
Vectors::StateVector< ScalarNumber, problem_dimension, n_precomputed_values > StateVector
dealii::Tensor< 1, dim, Number > construct_flux_tensor(const precomputed_type &precomputed_state) const
state_type apply_boundary_conditions(const dealii::types::boundary_id id, const state_type &U, const dealii::Tensor< 1, dim, Number > &normal, const Lambda &get_dirichlet_data) const
state_type nodal_source(const PrecomputedVectorView &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const =delete
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
flux_contribution_type flux_contribution(const PrecomputedVectorView &pv, const InitialPrecomputedVectorView &, const unsigned int i, const state_type &) const
void fill_precomputed_values(const OfflineData< dim, ScalarNumber > &offline_data, typename HyperbolicSystemView< dim, ScalarNumber >::StateVector &state_vector, const bool skip_constrained_dofs=true) const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
@ dirichlet_momentum
@ dirichlet_velocity
DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor< 1, problem_dim, T > contract(const FT &flux_ij, const TT &c_ij)
DEAL_II_HOST_DEVICE_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)
void populate_flux_list(flux_list_type &flux_list, const std::string &subsection)
std::set< std::shared_ptr< Flux > > flux_list_type