ryujin 2.1.1 revision 0348cbb53a3e4b1da2a4c037e81f88f2d21ce219
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) const;
287
289
293
300 static Number state(const state_type &U);
301
308 Number square_entropy(const Number &u) const;
309
317 Number square_entropy_derivative(const Number &u) const;
318
325 Number kruzkov_entropy(const Number &k, const Number &u) const;
326
334 Number kruzkov_entropy_derivative(const Number &k, const Number &u) const;
335
341 bool is_admissible(const state_type & /*U*/) const
342 {
343 return true;
344 }
345
347
351
355 template <typename Lambda>
357 apply_boundary_conditions(const dealii::types::boundary_id id,
358 const state_type &U,
359 const dealii::Tensor<1, dim, Number> &normal,
360 const Lambda &get_dirichlet_data) const;
361
363
367
372 dealii::Tensor<1, dim, Number>
373 construct_flux_tensor(const precomputed_type &precomputed_state) const;
374
380 dealii::Tensor<1, dim, Number> construct_flux_gradient_tensor(
381 const precomputed_type &precomputed_state) const;
382
404 const InitialPrecomputedVector & /*piv*/,
405 const unsigned int i,
406 const state_type & /*U_i*/) const;
407
410 const InitialPrecomputedVector & /*piv*/,
411 const unsigned int *js,
412 const state_type & /*U_j*/) const;
413
420 const flux_contribution_type &flux_j,
421 const dealii::Tensor<1, dim, Number> &c_ij) const;
422
424 static constexpr bool have_high_order_flux = false;
425
429 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
430
432
436
438 static constexpr bool have_source_terms = false;
439
441 const unsigned int i,
442 const state_type &U_i,
443 const ScalarNumber tau) const = delete;
444
446 const unsigned int *js,
447 const state_type &U_j,
448 const ScalarNumber tau) const = delete;
449
451
455
466 template <typename ST>
468 {
469 return state;
470 }
471
476 state_type from_primitive_state(const state_type &primitive_state) const
477 {
478 return primitive_state;
479 }
480
486 {
487 return state;
488 }
489
495 template <typename Lambda>
497 const Lambda & /*lambda*/) const
498 {
499 return state;
500 }
501
502 }; /* HyperbolicSystemView */
503
504
505 /*
506 * -------------------------------------------------------------------------
507 * Inline definitions
508 * -------------------------------------------------------------------------
509 */
510
511
512 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
513 : ParameterAcceptor(subsection)
514 {
515 flux_ = "burgers";
516 add_parameter("flux",
517 flux_,
518 "The scalar flux. Valid names are given by any of the "
519 "subsections defined below");
520
521 /*
522 * And finally populate the flux list with all flux configurations
523 * defined in the FluxLibrary namespace:
524 */
525 FluxLibrary::populate_flux_list(flux_list_, subsection);
526
527 const auto populate_functions = [this]() {
528 bool initialized = false;
529 for (auto &it : flux_list_)
530
531 /* Populate flux functions: */
532 if (it->name() == flux_) {
533 selected_flux_ = it;
534 it->parse_parameters_call_back();
535 problem_name = "Scalar conservation equation (" + it->name() +
536 ": " + it->flux_formula() + ")";
537 initialized = true;
538 break;
539 }
540
541 AssertThrow(initialized,
542 dealii::ExcMessage(
543 "Could not find a flux description with name \"" +
544 flux_ + "\""));
545 };
546
547 ParameterAcceptor::parse_parameters_call_back.connect(populate_functions);
548 populate_functions();
549 }
550
551
552 template <int dim, typename Number>
553 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
555 {
556 const auto &flux = hyperbolic_system_.selected_flux_;
557 dealii::Tensor<1, dim, Number> result;
558
559 /* This access by calling into value() repeatedly is terrible: */
560 for (unsigned int k = 0; k < dim; ++k) {
561 if constexpr (std::is_same_v<ScalarNumber, Number>) {
562 result[k] = flux->value(u, k);
563 } else {
564 for (unsigned int s = 0; s < Number::size(); ++s) {
565 result[k][s] = flux->value(u[s], k);
566 }
567 }
568 }
569
570 return result;
571 }
572
573
574 template <int dim, typename Number>
575 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
577 const Number &u) const
578 {
579 const auto &flux = hyperbolic_system_.selected_flux_;
580 dealii::Tensor<1, dim, Number> result;
581
582 /* This access by calling into value() repeatedly is terrible: */
583 for (unsigned int k = 0; k < dim; ++k) {
584 if constexpr (std::is_same_v<ScalarNumber, Number>) {
585 result[k] = flux->gradient(u, k);
586 } else {
587 for (unsigned int s = 0; s < Number::size(); ++s) {
588 result[k][s] = flux->gradient(u[s], k);
589 }
590 }
591 }
592
593 return result;
594 }
595
596
597 template <int dim, typename Number>
598 template <typename DISPATCH, typename SPARSITY>
599 DEAL_II_ALWAYS_INLINE inline void
601 unsigned int cycle [[maybe_unused]],
602 const DISPATCH &dispatch_check,
603 const SPARSITY &sparsity_simd,
604 StateVector &state_vector,
605 unsigned int left,
606 unsigned int right) const
607 {
608 Assert(cycle == 0, dealii::ExcInternalError());
609
610 const auto &U = std::get<0>(state_vector);
611 auto &precomputed = std::get<1>(state_vector);
612
613 /* We are inside a thread parallel context */
614
615 unsigned int stride_size = get_stride_size<Number>;
616
618 for (unsigned int i = left; i < right; i += stride_size) {
619
620 /* Skip constrained degrees of freedom: */
621 const unsigned int row_length = sparsity_simd.row_length(i);
622 if (row_length == 1)
623 continue;
624
625 dispatch_check(i);
626
627 const auto U_i = U.template get_tensor<Number>(i);
628 const auto u_i = state(U_i);
629
630 const auto f_i = flux_function(u_i);
631 const auto df_i = flux_gradient_function(u_i);
632
633 precomputed_type prec_i;
634
635 for (unsigned int k = 0; k < n_precomputed_values / 2; ++k) {
636 prec_i[k] = f_i[k];
637 prec_i[dim + k] = df_i[k];
638 }
639
640 precomputed.template write_tensor<Number>(prec_i, i);
641 }
642 }
643
644
645 template <int dim, typename Number>
646 DEAL_II_ALWAYS_INLINE inline Number
648 {
649 return U[0];
650 }
651
652
653 template <int dim, typename Number>
654 DEAL_II_ALWAYS_INLINE inline Number
656 {
657 return ScalarNumber(0.5) * u * u;
658 }
659
660
661 template <int dim, typename Number>
662 DEAL_II_ALWAYS_INLINE inline Number
664 const Number &u) const
665 {
666 return u;
667 }
668
669
670 template <int dim, typename Number>
671 DEAL_II_ALWAYS_INLINE inline Number
673 const Number &u) const
674 {
675 return std::abs(k - u);
676 }
677
678
679 template <int dim, typename Number>
680 DEAL_II_ALWAYS_INLINE inline Number
682 const Number &k, const Number &u) const
683 {
684 constexpr auto gte = dealii::SIMDComparison::greater_than_or_equal;
685 // return sgn(u-k):
686 return dealii::compare_and_apply_mask<gte>(u, k, Number(1.), Number(-1.));
687 }
688
689
690 template <int dim, typename Number>
691 template <typename Lambda>
692 DEAL_II_ALWAYS_INLINE inline auto
694 dealii::types::boundary_id id,
695 const state_type &U,
696 const dealii::Tensor<1, dim, Number> & /*normal*/,
697 const Lambda &get_dirichlet_data) const -> state_type
698 {
699 state_type result = U;
700
701 if (id == Boundary::dirichlet) {
702 result = get_dirichlet_data();
703
704 } else if (id == Boundary::dirichlet_momentum) {
705 AssertThrow(false,
706 dealii::ExcMessage(
707 "Invalid boundary ID »Boundary::dirichlet_momentum«, "
708 "enforcing Dirichlet boundary conditions on a momentum "
709 "is not possible for scalar conservation equations."));
710
711 } else if (id == Boundary::slip) {
712 AssertThrow(
713 false,
714 dealii::ExcMessage("Invalid boundary ID »Boundary::slip«, slip "
715 "boundary conditions are unavailable for scalar "
716 "conservation equations."));
717 __builtin_trap();
718
719 } else if (id == Boundary::no_slip) {
720 AssertThrow(
721 false,
722 dealii::ExcMessage("Invalid boundary ID »Boundary::no_slip«, "
723 "no-slip boundary conditions are unavailable "
724 "for scalar conservation equations."));
725 __builtin_trap();
726
727 } else if (id == Boundary::dynamic) {
728 AssertThrow(
729 false,
730 dealii::ExcMessage("Invalid boundary ID »Boundary::dynamic«, "
731 "dynamic boundary conditions are unavailable "
732 "for scalar conservation equations."));
733 __builtin_trap();
734
735 } else {
736 AssertThrow(false, dealii::ExcNotImplemented());
737 }
738
739 return result;
740 }
741
742
743 template <int dim, typename Number>
744 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
746 const precomputed_type &precomputed) const
747 {
748 dealii::Tensor<1, dim, Number> result;
749
750 if constexpr (dim == 1) {
751 const auto &[f, df] = precomputed;
752 result[0] = f;
753
754 } else if constexpr (dim == 2) {
755 const auto &[f_1, f_2, df_1, df_2] = precomputed;
756 result[0] = f_1;
757 result[1] = f_2;
758
759 } else if constexpr (dim == 3) {
760 const auto &[f_1, f_2, f_3, df_1, df_2, df_3] = precomputed;
761 result[0] = f_1;
762 result[1] = f_2;
763 result[2] = f_3;
764 }
765
766 return result;
767 }
768
769
770 template <int dim, typename Number>
771 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
773 const precomputed_type &precomputed) const
774 {
775 dealii::Tensor<1, dim, Number> result;
776
777 if constexpr (dim == 1) {
778 const auto &[f, df] = precomputed;
779 result[0] = df;
780
781 } else if constexpr (dim == 2) {
782 const auto &[f_1, f_2, df_1, df_2] = precomputed;
783 result[0] = df_1;
784 result[1] = df_2;
785
786 } else if constexpr (dim == 3) {
787 const auto &[f_1, f_2, f_3, df_1, df_2, df_3] = precomputed;
788 result[0] = df_1;
789 result[1] = df_2;
790 result[2] = df_3;
791 }
792
793 return result;
794 }
795
796
797 template <int dim, typename Number>
798 DEAL_II_ALWAYS_INLINE inline auto
800 const PrecomputedVector &pv,
801 const InitialPrecomputedVector & /*piv*/,
802 const unsigned int i,
803 const state_type & /*U_i*/) const -> flux_contribution_type
804 {
805 /* The flux contribution is a rank 2 tensor, thus a little dance: */
807 result[0] = construct_flux_tensor(
808 pv.template get_tensor<Number, precomputed_type>(i));
809 return result;
810 }
811
812
813 template <int dim, typename Number>
814 DEAL_II_ALWAYS_INLINE inline auto
816 const PrecomputedVector &pv,
817 const InitialPrecomputedVector & /*piv*/,
818 const unsigned int *js,
819 const state_type & /*U_j*/) const -> flux_contribution_type
820 {
821 /* The flux contribution is a rank 2 tensor, thus a little dance: */
823 result[0] = construct_flux_tensor(
824 pv.template get_tensor<Number, precomputed_type>(js));
825 return result;
826 }
827
828
829 template <int dim, typename Number>
830 DEAL_II_ALWAYS_INLINE inline auto
832 const flux_contribution_type &flux_i,
833 const flux_contribution_type &flux_j,
834 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
835 {
836 return -contract(add(flux_i, flux_j), c_ij);
837 }
838
839 } // namespace ScalarConservation
840} // 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
void precomputation_loop(unsigned int cycle, const DISPATCH &dispatch_check, const SPARSITY &sparsity_simd, StateVector &state_vector, unsigned int left, unsigned int right) const
state_type nodal_source(const PrecomputedVector &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
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)