ryujin 2.1.1 revision 350e54cc11f3d21282bddcf3e6517944dbc508bf
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 - 2024 by the ryujin authors
4//
5
6#pragma once
7
8#include "flux_library.h"
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 ScalarConservation
27 {
28 template <int dim, typename Number>
29 class HyperbolicSystemView;
30
37 class HyperbolicSystem final : public dealii::ParameterAcceptor
38 {
39 public:
43 static inline std::string problem_name = "Scalar conservation equation";
44
48 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
49
56 template <int dim, typename Number>
57 auto view() const
58 {
60 }
61
62 private:
67 std::string flux_;
68
70 using Flux = FluxLibrary::Flux;
71 std::shared_ptr<Flux> selected_flux_;
72
73 template <int dim, typename Number>
76 }; /* HyperbolicSystem */
77
78
84 template <int dim, typename Number>
86 {
87 public:
92 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
93 : hyperbolic_system_(hyperbolic_system)
94 {
95 }
96
100 template <int dim2, typename Number2>
101 auto view() const
102 {
103 return HyperbolicSystemView<dim2, Number2>{hyperbolic_system_};
104 }
105
110
115
116 DEAL_II_ALWAYS_INLINE inline const std::string &flux() const
117 {
118 return hyperbolic_system_.flux_;
119 }
120
121 DEAL_II_ALWAYS_INLINE inline ScalarNumber
123 {
124 const auto &flux = hyperbolic_system_.selected_flux_;
125 return ScalarNumber(flux->derivative_approximation_delta());
126 }
127
129
133
137 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
138 flux_function(const Number &u) const;
139
143 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
144 flux_gradient_function(const Number &u) const;
145
147
151
152 private:
153 const HyperbolicSystem &hyperbolic_system_;
154
155 public:
157
161
165 static constexpr unsigned int problem_dimension = 1;
166
170 using state_type = dealii::Tensor<1, problem_dimension, Number>;
171
175 using flux_type =
176 dealii::Tensor<1, problem_dimension, dealii::Tensor<1, dim, Number>>;
177
182
187 static inline const auto component_names =
188 std::array<std::string, problem_dimension>{"u"};
189
194 static inline const auto primitive_component_names =
195 std::array<std::string, problem_dimension>{"u"};
196
200 static constexpr unsigned int n_precomputed_values = 2 * dim;
201
205 using precomputed_type = std::array<Number, n_precomputed_values>;
206
210 static inline const auto precomputed_names =
211 []() -> std::array<std::string, n_precomputed_values> {
212 if constexpr (dim == 1)
213 return {"f", "df"};
214 else if constexpr (dim == 2)
215 return {"f_1", "f_2", "df_1", "df_2"};
216 else if constexpr (dim == 3)
217 return {"f_1", "f_2", "f_3", "df_1", "df_2", "df_3"};
218 __builtin_trap();
219 }();
220
224 static constexpr unsigned int n_initial_precomputed_values = 0;
225
230 std::array<Number, n_initial_precomputed_values>;
231
235 static inline const auto initial_precomputed_names =
236 std::array<std::string, n_initial_precomputed_values>{};
237
241 using StateVector = Vectors::
242 StateVector<ScalarNumber, problem_dimension, n_precomputed_values>;
243
249
255
263
265
269
270
274 static constexpr unsigned int n_precomputation_cycles = 1;
275
280 template <typename DISPATCH, typename SPARSITY>
281 void precomputation_loop(unsigned int cycle,
282 const DISPATCH &dispatch_check,
283 const SPARSITY &sparsity_simd,
284 StateVector &state_vector,
285 unsigned int left,
286 unsigned int right,
287 const bool skip_constrained_dofs = true) const;
288
290
294
301 static Number state(const state_type &U);
302
309 Number square_entropy(const Number &u) const;
310
318 Number square_entropy_derivative(const Number &u) const;
319
326 Number kruzkov_entropy(const Number &k, const Number &u) const;
327
335 Number kruzkov_entropy_derivative(const Number &k, const Number &u) const;
336
342 bool is_admissible(const state_type & /*U*/) const
343 {
344 return true;
345 }
346
348
352
356 template <typename Lambda>
358 apply_boundary_conditions(const dealii::types::boundary_id id,
359 const state_type &U,
360 const dealii::Tensor<1, dim, Number> &normal,
361 const Lambda &get_dirichlet_data) const;
362
364
368
373 dealii::Tensor<1, dim, Number>
374 construct_flux_tensor(const precomputed_type &precomputed_state) const;
375
381 dealii::Tensor<1, dim, Number> construct_flux_gradient_tensor(
382 const precomputed_type &precomputed_state) const;
383
405 const InitialPrecomputedVector & /*piv*/,
406 const unsigned int i,
407 const state_type & /*U_i*/) const;
408
411 const InitialPrecomputedVector & /*piv*/,
412 const unsigned int *js,
413 const state_type & /*U_j*/) const;
414
421 const flux_contribution_type &flux_j,
422 const dealii::Tensor<1, dim, Number> &c_ij) const;
423
425 static constexpr bool have_high_order_flux = false;
426
430 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
431
433
437
439 static constexpr bool have_source_terms = false;
440
442 const unsigned int i,
443 const state_type &U_i,
444 const ScalarNumber tau) const = delete;
445
447 const unsigned int *js,
448 const state_type &U_j,
449 const ScalarNumber tau) const = delete;
450
452
456
467 template <typename ST>
469 {
470 return state;
471 }
472
477 state_type from_primitive_state(const state_type &primitive_state) const
478 {
479 return primitive_state;
480 }
481
487 {
488 return state;
489 }
490
496 template <typename Lambda>
498 const Lambda & /*lambda*/) const
499 {
500 return state;
501 }
502
503 }; /* HyperbolicSystemView */
504
505
506 /*
507 * -------------------------------------------------------------------------
508 * Inline definitions
509 * -------------------------------------------------------------------------
510 */
511
512
513 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
514 : ParameterAcceptor(subsection)
515 {
516 flux_ = "burgers";
517 add_parameter("flux",
518 flux_,
519 "The scalar flux. Valid names are given by any of the "
520 "subsections defined below");
521
522 /*
523 * And finally populate the flux list with all flux configurations
524 * defined in the FluxLibrary namespace:
525 */
526 FluxLibrary::populate_flux_list(flux_list_, subsection);
527
528 const auto populate_functions = [this]() {
529 bool initialized = false;
530 for (auto &it : flux_list_)
531
532 /* Populate flux functions: */
533 if (it->name() == flux_) {
534 selected_flux_ = it;
535 it->parse_parameters_call_back();
536 problem_name = "Scalar conservation equation (" + it->name() +
537 ": " + it->flux_formula() + ")";
538 initialized = true;
539 break;
540 }
541
542 AssertThrow(initialized,
543 dealii::ExcMessage(
544 "Could not find a flux description with name \"" +
545 flux_ + "\""));
546 };
547
548 ParameterAcceptor::parse_parameters_call_back.connect(populate_functions);
549 populate_functions();
550 }
551
552
553 template <int dim, typename Number>
554 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
556 {
557 const auto &flux = hyperbolic_system_.selected_flux_;
558 dealii::Tensor<1, dim, Number> result;
559
560 /* This access by calling into value() repeatedly is terrible: */
561 for (unsigned int k = 0; k < dim; ++k) {
562 if constexpr (std::is_same_v<ScalarNumber, Number>) {
563 result[k] = flux->value(u, k);
564 } else {
565 for (unsigned int s = 0; s < Number::size(); ++s) {
566 result[k][s] = flux->value(u[s], k);
567 }
568 }
569 }
570
571 return result;
572 }
573
574
575 template <int dim, typename Number>
576 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
578 const Number &u) const
579 {
580 const auto &flux = hyperbolic_system_.selected_flux_;
581 dealii::Tensor<1, dim, Number> result;
582
583 /* This access by calling into value() repeatedly is terrible: */
584 for (unsigned int k = 0; k < dim; ++k) {
585 if constexpr (std::is_same_v<ScalarNumber, Number>) {
586 result[k] = flux->gradient(u, k);
587 } else {
588 for (unsigned int s = 0; s < Number::size(); ++s) {
589 result[k][s] = flux->gradient(u[s], k);
590 }
591 }
592 }
593
594 return result;
595 }
596
597
598 template <int dim, typename Number>
599 template <typename DISPATCH, typename SPARSITY>
600 DEAL_II_ALWAYS_INLINE inline void
602 unsigned int cycle [[maybe_unused]],
603 const DISPATCH &dispatch_check,
604 const SPARSITY &sparsity_simd,
605 StateVector &state_vector,
606 unsigned int left,
607 unsigned int right,
608 const bool skip_constrained_dofs /*= true*/) const
609 {
610 Assert(cycle == 0, dealii::ExcInternalError());
611
612 const auto &U = std::get<0>(state_vector);
613 auto &precomputed = std::get<1>(state_vector);
614
615 /* We are inside a thread parallel context */
616
617 unsigned int stride_size = get_stride_size<Number>;
618
620 for (unsigned int i = left; i < right; i += stride_size) {
621
622 /* Skip constrained degrees of freedom: */
623 const unsigned int row_length = sparsity_simd.row_length(i);
624 if (skip_constrained_dofs && row_length == 1)
625 continue;
626
627 dispatch_check(i);
628
629 const auto U_i = U.template get_tensor<Number>(i);
630 const auto u_i = state(U_i);
631
632 const auto f_i = flux_function(u_i);
633 const auto df_i = flux_gradient_function(u_i);
634
635 precomputed_type prec_i;
636
637 for (unsigned int k = 0; k < n_precomputed_values / 2; ++k) {
638 prec_i[k] = f_i[k];
639 prec_i[dim + k] = df_i[k];
640 }
641
642 precomputed.template write_tensor<Number>(prec_i, i);
643 }
644 }
645
646
647 template <int dim, typename Number>
648 DEAL_II_ALWAYS_INLINE inline Number
650 {
651 return U[0];
652 }
653
654
655 template <int dim, typename Number>
656 DEAL_II_ALWAYS_INLINE inline Number
658 {
659 return ScalarNumber(0.5) * u * u;
660 }
661
662
663 template <int dim, typename Number>
664 DEAL_II_ALWAYS_INLINE inline Number
666 const Number &u) const
667 {
668 return u;
669 }
670
671
672 template <int dim, typename Number>
673 DEAL_II_ALWAYS_INLINE inline Number
675 const Number &u) const
676 {
677 return std::abs(k - u);
678 }
679
680
681 template <int dim, typename Number>
682 DEAL_II_ALWAYS_INLINE inline Number
684 const Number &k, const Number &u) const
685 {
686 constexpr auto gte = dealii::SIMDComparison::greater_than_or_equal;
687 // return sgn(u-k):
688 return dealii::compare_and_apply_mask<gte>(u, k, Number(1.), Number(-1.));
689 }
690
691
692 template <int dim, typename Number>
693 template <typename Lambda>
694 DEAL_II_ALWAYS_INLINE inline auto
696 dealii::types::boundary_id id,
697 const state_type &U,
698 const dealii::Tensor<1, dim, Number> & /*normal*/,
699 const Lambda &get_dirichlet_data) const -> state_type
700 {
701 state_type result = U;
702
703 if (id == Boundary::dirichlet) {
704 result = get_dirichlet_data();
705
706 } else if (id == Boundary::dirichlet_momentum) {
707 AssertThrow(false,
708 dealii::ExcMessage(
709 "Invalid boundary ID »Boundary::dirichlet_momentum«, "
710 "enforcing Dirichlet boundary conditions on a momentum "
711 "is not possible for scalar conservation equations."));
712
713 } else if (id == Boundary::slip) {
714 AssertThrow(
715 false,
716 dealii::ExcMessage("Invalid boundary ID »Boundary::slip«, slip "
717 "boundary conditions are unavailable for scalar "
718 "conservation equations."));
719 __builtin_trap();
720
721 } else if (id == Boundary::no_slip) {
722 AssertThrow(
723 false,
724 dealii::ExcMessage("Invalid boundary ID »Boundary::no_slip«, "
725 "no-slip boundary conditions are unavailable "
726 "for scalar conservation equations."));
727 __builtin_trap();
728
729 } else if (id == Boundary::dynamic) {
730 AssertThrow(
731 false,
732 dealii::ExcMessage("Invalid boundary ID »Boundary::dynamic«, "
733 "dynamic boundary conditions are unavailable "
734 "for scalar conservation equations."));
735 __builtin_trap();
736
737 } else {
738 AssertThrow(false, dealii::ExcNotImplemented());
739 }
740
741 return result;
742 }
743
744
745 template <int dim, typename Number>
746 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
748 const precomputed_type &precomputed) const
749 {
750 dealii::Tensor<1, dim, Number> result;
751
752 if constexpr (dim == 1) {
753 const auto &[f, df] = precomputed;
754 result[0] = f;
755
756 } else if constexpr (dim == 2) {
757 const auto &[f_1, f_2, df_1, df_2] = precomputed;
758 result[0] = f_1;
759 result[1] = f_2;
760
761 } else if constexpr (dim == 3) {
762 const auto &[f_1, f_2, f_3, df_1, df_2, df_3] = precomputed;
763 result[0] = f_1;
764 result[1] = f_2;
765 result[2] = f_3;
766 }
767
768 return result;
769 }
770
771
772 template <int dim, typename Number>
773 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
775 const precomputed_type &precomputed) const
776 {
777 dealii::Tensor<1, dim, Number> result;
778
779 if constexpr (dim == 1) {
780 const auto &[f, df] = precomputed;
781 result[0] = df;
782
783 } else if constexpr (dim == 2) {
784 const auto &[f_1, f_2, df_1, df_2] = precomputed;
785 result[0] = df_1;
786 result[1] = df_2;
787
788 } else if constexpr (dim == 3) {
789 const auto &[f_1, f_2, f_3, df_1, df_2, df_3] = precomputed;
790 result[0] = df_1;
791 result[1] = df_2;
792 result[2] = df_3;
793 }
794
795 return result;
796 }
797
798
799 template <int dim, typename Number>
800 DEAL_II_ALWAYS_INLINE inline auto
802 const PrecomputedVector &pv,
803 const InitialPrecomputedVector & /*piv*/,
804 const unsigned int i,
805 const state_type & /*U_i*/) const -> flux_contribution_type
806 {
807 /* The flux contribution is a rank 2 tensor, thus a little dance: */
809 result[0] = construct_flux_tensor(
810 pv.template get_tensor<Number, precomputed_type>(i));
811 return result;
812 }
813
814
815 template <int dim, typename Number>
816 DEAL_II_ALWAYS_INLINE inline auto
818 const PrecomputedVector &pv,
819 const InitialPrecomputedVector & /*piv*/,
820 const unsigned int *js,
821 const state_type & /*U_j*/) const -> flux_contribution_type
822 {
823 /* The flux contribution is a rank 2 tensor, thus a little dance: */
825 result[0] = construct_flux_tensor(
826 pv.template get_tensor<Number, precomputed_type>(js));
827 return result;
828 }
829
830
831 template <int dim, typename Number>
832 DEAL_II_ALWAYS_INLINE inline auto
834 const flux_contribution_type &flux_i,
835 const flux_contribution_type &flux_j,
836 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
837 {
838 return -contract(add(flux_i, flux_j), c_ij);
839 }
840
841 } // namespace ScalarConservation
842} // namespace ryujin
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
flux_contribution_type flux_contribution(const PrecomputedVector &pv, const InitialPrecomputedVector &, const unsigned int i, const state_type &) const
state_type apply_galilei_transform(const state_type &state, const Lambda &) const
static constexpr unsigned int n_precomputation_cycles
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
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
state_type nodal_source(const PrecomputedVector &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
void precomputation_loop(unsigned int cycle, const DISPATCH &dispatch_check, const SPARSITY &sparsity_simd, StateVector &state_vector, unsigned int left, unsigned int right, const bool skip_constrained_dofs=true) const
typename get_value_type< Number >::type ScalarNumber
static Number state(const state_type &U)
Number kruzkov_entropy(const Number &k, const Number &u) const
state_type nodal_source(const PrecomputedVector &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const =delete
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, dim, Number > flux_gradient_function(const Number &u) const
static constexpr unsigned int n_initial_precomputed_values
static constexpr unsigned int n_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 flux_divergence(const flux_contribution_type &flux_i, const flux_contribution_type &flux_j, const dealii::Tensor< 1, dim, Number > &c_ij) const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
@ dirichlet_momentum
#define RYUJIN_OMP_FOR
Definition: openmp.h:70
std::set< std::shared_ptr< Flux > > flux_list_type
Definition: flux_library.h:14
void populate_flux_list(flux_list_type &flux_list, const std::string &subsection)
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)