ryujin 2.5.0 revision c64172211cf21344cb9b9b0f3a1266aa6400d392
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 <ryujin/base/compile_time_options.h>
10#include <ryujin/base/gpu.h>
11#include <ryujin/base/loop.h>
13#include <ryujin/base/simd.h>
19
20#include <deal.II/base/memory_space.h>
21#include <deal.II/base/parameter_acceptor.h>
22#include <deal.II/base/tensor.h>
23
24#include <array>
25#include <memory>
26#include <string>
27#include <vector>
28
29namespace ryujin
30{
31 namespace ScalarConservation
32 {
33 template <int dim,
34 typename Number,
35 typename MemorySpace = dealii::MemorySpace::Host>
36 class HyperbolicSystemView;
37
45 {
46 public:
54
58 HyperbolicSystem(const std::string &subsection = "/HyperbolicSystem");
59
65 template <int dim,
66 typename Number = double,
67 typename MemorySpace = dealii::MemorySpace::Host>
69
77 template <int dim,
78 typename Number,
79 typename MemorySpace = dealii::MemorySpace::Host>
80 auto view() const
81 {
83 }
84
98 template <typename MemorySpace = dealii::MemorySpace::Host,
99 int dim,
100 typename ScalarNumber>
102 const OfflineData<dim, ScalarNumber> &offline_data,
103 StateVector<ScalarNumber> &state_vector,
104 const bool skip_constrained_dofs = true) const;
105
106 private:
111
116 void update_parameters();
117
118 Mirrored<Parameters> parameters_;
119
120 std::string flux_;
121
122 std::vector<std::unique_ptr<Flux>> flux_list_;
123
124 const Flux *selected_flux_ = nullptr;
125
126 template <int, typename, typename>
128
130 }; /* HyperbolicSystem */
131
132
143 template <int dim, typename Number, typename MemorySpace>
145 {
146 public:
147 static_assert(
148 std::is_same_v<MemorySpace, dealii::MemorySpace::Host> ||
149 std::is_same_v<MemorySpace, dealii::MemorySpace::Default>,
150 "Unexpected memory space");
151
156
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
186 static constexpr unsigned int n_precomputed_values = 2 * dim;
187
191 using precomputed_type = std::array<Number, n_precomputed_values>;
192
196 static constexpr unsigned int n_initial_precomputed_values = 0;
197
202 std::array<Number, n_initial_precomputed_values>;
203
204 template <int n_comp>
207
213
220
222
226
231 HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
232 : parameters_(
233 hyperbolic_system.parameters_.template view<MemorySpace>())
234 , flux_(hyperbolic_system.selected_flux_)
235 {
236 }
237
239
243
249 DEAL_II_ALWAYS_INLINE inline const std::string &flux() const
250 {
251 return flux_->name();
252 }
253
254 DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber
259
261
269
273 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
274 flux_function(const Number &u) const;
275
279 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
280 flux_gradient_function(const Number &u) const;
281
283
287
294 static DEAL_II_HOST_DEVICE Number state(const state_type &U);
295
302 DEAL_II_HOST_DEVICE Number square_entropy(const Number &u) const;
303
311 DEAL_II_HOST_DEVICE Number
312 square_entropy_derivative(const Number &u) const;
313
320 DEAL_II_HOST_DEVICE Number kruzkov_entropy(const Number &k,
321 const Number &u) const;
322
330 DEAL_II_HOST_DEVICE Number
331 kruzkov_entropy_derivative(const Number &k, const Number &u) const;
332
338 DEAL_II_HOST_DEVICE_ALWAYS_INLINE bool
339 is_admissible(const state_type & /*U*/) const
340 {
341 return true;
342 }
343
345
349
353 template <typename Lambda>
354 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type
355 apply_boundary_conditions(const dealii::types::boundary_id id,
356 const state_type &U,
357 const dealii::Tensor<1, dim, Number> &normal,
358 const Lambda &get_dirichlet_data) const;
359
361
365
370 DEAL_II_HOST_DEVICE dealii::Tensor<1, dim, Number>
371 construct_flux_tensor(const precomputed_type &precomputed_state) const;
372
378 DEAL_II_HOST_DEVICE dealii::Tensor<1, dim, Number>
380 const precomputed_type &precomputed_state) const;
381
401 DEAL_II_HOST_DEVICE
404 const InitialPrecomputedVectorView & /*piv*/,
405 const unsigned int i,
406 const state_type & /*U_i*/) const;
407
408 DEAL_II_HOST_DEVICE
411 const InitialPrecomputedVectorView & /*piv*/,
412 const unsigned int *js,
413 const state_type & /*U_j*/) const;
414
419 DEAL_II_HOST_DEVICE
422 const flux_contribution_type &flux_j,
423 const dealii::Tensor<1, dim, Number> &c_ij) const;
424
426 static constexpr bool have_high_order_flux = false;
427
431 const dealii::Tensor<1, dim, Number> &c_ij) const = delete;
432
434
438
440 static constexpr bool have_source_terms = false;
441
443 const unsigned int i,
444 const state_type &U_i,
445 const ScalarNumber tau) const = delete;
446
448 const unsigned int *js,
449 const state_type &U_j,
450 const ScalarNumber tau) const = delete;
451
453
457
468 template <typename ST>
469 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type
470 expand_state(const ST &state) const
471 {
472 return state;
473 }
474
479 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type
480 from_primitive_state(const state_type &primitive_state) const
481 {
482 return primitive_state;
483 }
484
489 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type
491 {
492 return state;
493 }
494
500 template <typename Lambda>
501 DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type apply_galilei_transform(
502 const state_type &state, const Lambda & /*lambda*/) const
503 {
504 return state;
505 }
506
507 private:
509
513
514 const HyperbolicSystem::Parameters *const parameters_;
515
516 /* Only valid (and dereferenced) on the host: */
517 const Flux *const flux_;
518
520 }; /* HyperbolicSystemView */
521
522
523 /*
524 * -------------------------------------------------------------------------
525 * Inline definitions
526 * -------------------------------------------------------------------------
527 */
528
529
530 inline HyperbolicSystem::HyperbolicSystem(const std::string &subsection)
531 : Interface::HyperbolicSystem(
532 "Scalar conservation equation",
533 {{{"u"}, {"u"}, {"u"}}},
534 {{{"u"}, {"u"}, {"u"}}},
535 {{{"f", "df"},
536 {"f_1", "f_2", "df_1", "df_2"},
537 {"f_1", "f_2", "f_3", "df_1", "df_2", "df_3"}}},
538 {},
539 subsection)
540 , parameters_("scalar_conservation_hyperbolic_system_parameters",
542 {
543 flux_list_ = FluxLibrary::create(subsection);
544
545 flux_ = "burgers";
546 add_parameter("flux",
547 flux_,
548 "The scalar flux. Valid names are given by any of the "
549 "subsections defined below",
550 this->prm,
551 FluxLibrary::selection(flux_list_));
552
553 /*
554 * The flux classes update their parameters in their own
555 * parse_parameters_call_back signal, which is invoked after ours.
556 * Thus, also connect to theirs:
557 */
558 ParameterAcceptor::parse_parameters_call_back.connect(
559 [this] { update_parameters(); });
560 for (auto &it : flux_list_)
561 it->parse_parameters_call_back.connect([this] { update_parameters(); });
562
563 update_parameters();
564 }
565
566
567 inline void HyperbolicSystem::update_parameters()
568 {
569 selected_flux_ = &FluxLibrary::select(flux_list_, flux_);
570 problem_name_ = "Scalar conservation equation (" +
571 selected_flux_->name() + ": " +
572 selected_flux_->flux_formula() + ")";
573
574 /* invalidates view on default memory space */
575 auto &parameters = *parameters_.view();
576
577 parameters.derivative_approximation_delta =
578 selected_flux_->derivative_approximation_delta();
579 }
580
581
582 template <typename MemorySpace, int dim, typename ScalarNumber>
584 const OfflineData<dim, ScalarNumber> &offline_data,
585 StateVector<ScalarNumber> &state_vector,
586 const bool skip_constrained_dofs) const
587 {
588 using HostSpace = dealii::MemorySpace::Host;
589
590 const unsigned int n_internal = offline_data.n_locally_internal();
591 const unsigned int n_owned = offline_data.n_locally_owned();
592
594
595 auto &U = state_vector.state;
596 auto &precomputed = state_vector.precomputed;
597
598 /*
599 * Compute the flux and its gradient. This requires calling into the
600 * selected flux, which is only possible on the host memory space.
601 * Thus, temporarily transfer the state vector and the precomputed
602 * values to the host memory space:
603 */
604
605 constexpr bool transfer =
607 !std::is_same_v<MemorySpace, dealii::MemorySpace::Host>;
608
609 [[maybe_unused]] const bool host_resident =
610 U.template is_resident<HostSpace>();
611
612 if constexpr (transfer) {
613 U.template copy_to_memory_space<HostSpace>();
614 precomputed.template move_to_memory_space<HostSpace>();
615 }
616
617 {
618 const auto sparsity_simd_view =
619 offline_data.sparsity_pattern_simd().template view<HostSpace>();
620
621 /* We only read the hyperbolic state vector: */
622 const auto U_view =
623 std::as_const(U)
624 .template view<ScalarView::problem_dimension, HostSpace>();
625 const auto precomputed_view =
627 .template view<ScalarView::n_precomputed_values, HostSpace>();
628
629 const auto hyperbolic_system_views =
630 make_select_view<dim, ScalarNumber, HostSpace>(*this);
631
632 const auto body = [=](auto sentinel, unsigned int i) {
633 using T = decltype(sentinel);
635 using precomputed_type = typename View::precomputed_type;
636
637 const unsigned int row_length = sparsity_simd_view.row_length(i);
638 if (skip_constrained_dofs && row_length == 1)
639 return;
640
641 const auto view = hyperbolic_system_views.template view<T>();
642
643 const auto U_i = U_view.template read_tensor<T>(i);
644 const auto u_i = view.state(U_i);
645
646 /* Calls into the selected flux: */
647 const auto f_i = view.flux_function(u_i);
648 const auto df_i = view.flux_gradient_function(u_i);
649
650 precomputed_type prec_i;
651 for (unsigned int k = 0; k < View::n_precomputed_values / 2; ++k) {
652 prec_i[k] = f_i[k];
653 prec_i[dim + k] = df_i[k];
654 }
655 precomputed_view.template write_tensor<T>(prec_i, i);
656 };
657
658 loop<HostSpace, ScalarNumber>(
659 "hyperbolic_kernel_01b", body, 0, n_internal, n_owned);
660 }
661
662 if constexpr (transfer) {
663 /* Drop the (now stale) host mirror unless it was resident before: */
664 if (!host_resident)
665 U.template move_to_memory_space<MemorySpace>();
666 precomputed.template move_to_memory_space<MemorySpace>();
667 }
668 }
669
670
671 template <int dim, typename Number, typename MemorySpace>
672 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
674 const Number &u) const
675 {
676 const auto &flux = flux_;
677 dealii::Tensor<1, dim, Number> result;
678
679 /* This access by calling into value() repeatedly is terrible: */
680 for (unsigned int k = 0; k < dim; ++k) {
681 if constexpr (std::is_same_v<ScalarNumber, Number>) {
682 result[k] = flux->value(u, k);
683 } else {
684 for (unsigned int s = 0; s < Number::size(); ++s) {
685 result[k][s] = flux->value(u[s], k);
686 }
687 }
688 }
689
690 return result;
691 }
692
693 template <int dim, typename Number, typename MemorySpace>
694 DEAL_II_ALWAYS_INLINE inline dealii::Tensor<1, dim, Number>
696 const Number &u) const
697 {
698 const auto &flux = flux_;
699 dealii::Tensor<1, dim, Number> result;
700
701 /* This access by calling into value() repeatedly is terrible: */
702 for (unsigned int k = 0; k < dim; ++k) {
703 if constexpr (std::is_same_v<ScalarNumber, Number>) {
704 result[k] = flux->gradient(u, k);
705 } else {
706 for (unsigned int s = 0; s < Number::size(); ++s) {
707 result[k][s] = flux->gradient(u[s], k);
708 }
709 }
710 }
711
712 return result;
713 }
714
715
716 template <int dim, typename Number, typename MemorySpace>
717 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
722
723
724 template <int dim, typename Number, typename MemorySpace>
725 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
727 const Number &u) const
728 {
729 return ScalarNumber(0.5) * u * u;
730 }
731
732
733 template <int dim, typename Number, typename MemorySpace>
734 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
736 const Number &u) const
737 {
738 return u;
739 }
740
741
742 template <int dim, typename Number, typename MemorySpace>
743 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
745 const Number &k, const Number &u) const
746 {
747 return std::abs(k - u);
748 }
749
750
751 template <int dim, typename Number, typename MemorySpace>
752 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number
754 const Number &k, const Number &u) const
755 {
756 constexpr auto gte = dealii::SIMDComparison::greater_than_or_equal;
757 // return sgn(u-k):
758 return ryujin::compare_and_apply_mask<gte>(u, k, Number(1.), Number(-1.));
759 }
760
761
762 template <int dim, typename Number, typename MemorySpace>
763 template <typename Lambda>
764 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
766 dealii::types::boundary_id id,
767 const state_type &U,
768 const dealii::Tensor<1, dim, Number> & /*normal*/,
769 const Lambda &get_dirichlet_data) const -> state_type
770 {
771 state_type result = U;
772
773 if (id == Boundary::dirichlet) {
774 result = get_dirichlet_data();
775
776 } else if (id == Boundary::dirichlet_momentum) {
777 Assert(false,
778 dealii::ExcMessage(
779 "Invalid boundary ID »Boundary::dirichlet_momentum«, "
780 "enforcing Dirichlet boundary conditions on a momentum "
781 "is not possible for scalar conservation equations."));
782
783 } else if (id == Boundary::dirichlet_velocity) {
784 Assert(false,
785 dealii::ExcMessage(
786 "Invalid boundary ID »Boundary::dirichlet_velocity«, "
787 "enforcing Dirichlet boundary conditions on a momentum "
788 "is not possible for scalar conservation equations."));
789
790 } else if (id == Boundary::slip) {
791 Assert(
792 false,
793 dealii::ExcMessage("Invalid boundary ID »Boundary::slip«, slip "
794 "boundary conditions are unavailable for scalar "
795 "conservation equations."));
796 __builtin_trap();
797
798 } else if (id == Boundary::no_slip) {
799 Assert(false,
800 dealii::ExcMessage("Invalid boundary ID »Boundary::no_slip«, "
801 "no-slip boundary conditions are unavailable "
802 "for scalar conservation equations."));
803 __builtin_trap();
804
805 } else if (id == Boundary::dynamic) {
806 Assert(false,
807 dealii::ExcMessage("Invalid boundary ID »Boundary::dynamic«, "
808 "dynamic boundary conditions are unavailable "
809 "for scalar conservation equations."));
810 __builtin_trap();
811
812 } else {
813 Assert(false, dealii::ExcNotImplemented());
814 }
815
816 return result;
817 }
818
819
820 template <int dim, typename Number, typename MemorySpace>
821 DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor<1, dim, Number>
823 const precomputed_type &precomputed) const
824 {
825 dealii::Tensor<1, dim, Number> result;
826 for (unsigned int k = 0; k < dim; ++k)
827 result[k] = precomputed[k];
828 return result;
829 }
830
831
832 template <int dim, typename Number, typename MemorySpace>
833 DEAL_II_HOST_DEVICE_ALWAYS_INLINE dealii::Tensor<1, dim, Number>
836 const precomputed_type &precomputed) const
837 {
838 dealii::Tensor<1, dim, Number> result;
839 for (unsigned int k = 0; k < dim; ++k)
840 result[k] = precomputed[dim + k];
841 return result;
842 }
843
844
845 template <int dim, typename Number, typename MemorySpace>
846 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
848 const PrecomputedVectorView &pv,
849 const InitialPrecomputedVectorView & /*piv*/,
850 const unsigned int i,
851 const state_type & /*U_i*/) const -> flux_contribution_type
852 {
853 /* The flux contribution is a rank 2 tensor, thus a little dance: */
855 result[0] = construct_flux_tensor(
856 pv.template read_tensor<Number, precomputed_type>(i));
857 return result;
858 }
859
860
861 template <int dim, typename Number, typename MemorySpace>
862 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
864 const PrecomputedVectorView &pv,
865 const InitialPrecomputedVectorView & /*piv*/,
866 const unsigned int *js,
867 const state_type & /*U_j*/) const -> flux_contribution_type
868 {
869 /* The flux contribution is a rank 2 tensor, thus a little dance: */
871 result[0] = construct_flux_tensor(
872 pv.template read_tensor<Number, precomputed_type>(js));
873 return result;
874 }
875
876
877 template <int dim, typename Number, typename MemorySpace>
878 DEAL_II_HOST_DEVICE_ALWAYS_INLINE auto
880 const flux_contribution_type &flux_i,
881 const flux_contribution_type &flux_j,
882 const dealii::Tensor<1, dim, Number> &c_ij) const -> state_type
883 {
884 return -contract(add(flux_i, flux_j), c_ij);
885 }
886 } // namespace ScalarConservation
887} // namespace ryujin
dealii::Tensor< 1, problem_dimension, Number > state_type
static Base & select(const std::vector< std::unique_ptr< Base > > &objects, const std::string &name)
Definition library.h:189
static std::vector< std::unique_ptr< Base > > create(Args... args)
Definition library.h:148
static dealii::Patterns::Selection selection(const std::vector< std::unique_ptr< Base > > &objects)
Definition library.h:178
DEAL_II_HOST_DEVICE dealii::Tensor< 1, dim, Number > construct_flux_gradient_tensor(const precomputed_type &precomputed_state) const
state_type nodal_source(const PrecomputedVectorView &pv, const unsigned int i, const state_type &U_i, const ScalarNumber tau) const =delete
DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type from_primitive_state(const state_type &primitive_state) const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE ScalarNumber derivative_approximation_delta() const
DEAL_II_HOST_DEVICE Number square_entropy_derivative(const Number &u) const
dealii::Tensor< 1, problem_dimension, Number > state_type
DEAL_II_HOST_DEVICE_ALWAYS_INLINE bool is_admissible(const state_type &) const
std::array< Number, n_precomputed_values > precomputed_type
DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type apply_galilei_transform(const state_type &state, const Lambda &) const
DEAL_II_HOST_DEVICE flux_contribution_type flux_contribution(const PrecomputedVectorView &pv, const InitialPrecomputedVectorView &, const unsigned int i, const state_type &) const
DEAL_II_HOST_DEVICE Number square_entropy(const Number &u) const
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, dim, Number > flux_gradient_function(const Number &u) const
std::array< Number, n_initial_precomputed_values > initial_precomputed_type
state_type nodal_source(const PrecomputedVectorView &pv, const unsigned int *js, const state_type &U_j, const ScalarNumber tau) const =delete
DEAL_II_ALWAYS_INLINE const std::string & flux() const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type expand_state(const ST &state) const
DEAL_II_HOST_DEVICE Number kruzkov_entropy(const Number &k, const Number &u) const
dealii::Tensor< 1, problem_dimension, dealii::Tensor< 1, dim, Number > > flux_type
static DEAL_II_HOST_DEVICE Number state(const state_type &U)
DEAL_II_HOST_DEVICE dealii::Tensor< 1, dim, Number > construct_flux_tensor(const precomputed_type &precomputed_state) const
DEAL_II_HOST_DEVICE_ALWAYS_INLINE state_type to_primitive_state(const state_type &state) const
DEAL_II_HOST_DEVICE 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_HOST_DEVICE_ALWAYS_INLINE 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
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, dim, Number > flux_function(const Number &u) const
static constexpr unsigned int n_initial_precomputed_values
state_type high_order_flux_divergence(const flux_contribution_type &, const flux_contribution_type &, const dealii::Tensor< 1, dim, Number > &c_ij) const =delete
HyperbolicSystemView(const HyperbolicSystem &hyperbolic_system)
DEAL_II_HOST_DEVICE Number kruzkov_entropy_derivative(const Number &k, const Number &u) const
typename get_value_type< Number >::type ScalarNumber
void fill_precomputed_values(const OfflineData< dim, ScalarNumber > &offline_data, StateVector< ScalarNumber > &state_vector, const bool skip_constrained_dofs=true) const
HyperbolicSystem(const std::string &subsection="/HyperbolicSystem")
constexpr bool have_separate_memory_spaces
Definition gpu.h:29
@ 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)
MultiComponentVector< Number > state
MultiComponentVector< Number > precomputed