Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <optional>
8 : #include <tuple>
9 : #include <utility>
10 :
11 : #include "DataStructures/DataBox/DataBox.hpp"
12 : #include "DataStructures/DataBox/MetavariablesTag.hpp"
13 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
14 : #include "DataStructures/DataBox/Prefixes.hpp"
15 : #include "DataStructures/TaggedTuple.hpp"
16 : #include "DataStructures/Tensor/Tensor.hpp"
17 : #include "DataStructures/Variables.hpp"
18 : #include "Domain/Structure/ElementId.hpp"
19 : #include "Domain/Tags.hpp"
20 : #include "Parallel/AlgorithmExecution.hpp"
21 : #include "Parallel/GlobalCache.hpp"
22 : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp"
23 : #include "ParallelAlgorithms/Initialization/MutateAssign.hpp"
24 : #include "PointwiseFunctions/AnalyticSolutions/Tags.hpp"
25 : #include "Utilities/CallWithDynamicType.hpp"
26 : #include "Utilities/TMPL.hpp"
27 :
28 : /// \cond
29 : namespace Frame {
30 : struct Inertial;
31 : } // namespace Frame
32 : /// \endcond
33 :
34 0 : namespace elliptic::Actions {
35 : /// @{
36 : /*!
37 : * \brief Place the analytic solution of the system fields in the DataBox.
38 : *
39 : * The `::Tags::AnalyticSolutions` tag retrieved from the DataBox will hold
40 : * a `std::optional`. The analytic solution is only evaluated and stored in the
41 : * DataBox if the `BackgroundTag` holds a type that inherits from the
42 : * `AnalyticSolutionType`.
43 : *
44 : * Uses:
45 : * - DataBox:
46 : * - `AnalyticSolutionTag` or `BackgroundTag`
47 : * - `domain::Tags::Mesh<Dim>`
48 : * - `Tags::Coordinates<Dim, Frame::Inertial>`
49 : * - `domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
50 : * Frame::Inertial>`
51 : *
52 : * DataBox:
53 : * - Adds:
54 : * - `::Tags::AnalyticSolutions<AnalyticSolutionFields>`
55 : */
56 : template <size_t Dim, typename BackgroundTag, typename AnalyticSolutionFields,
57 : typename AnalyticSolutionType>
58 1 : struct InitializeOptionalAnalyticSolution
59 : : tt::ConformsTo<::amr::protocols::Projector> {
60 : private:
61 0 : using analytic_fields_tag = ::Tags::AnalyticSolutions<AnalyticSolutionFields>;
62 :
63 : public: // Iterable action
64 0 : using simple_tags = tmpl::list<analytic_fields_tag>;
65 0 : using compute_tags = tmpl::list<>;
66 0 : using const_global_cache_tags = tmpl::list<BackgroundTag>;
67 :
68 : template <typename DbTagsList, typename... InboxTags, typename Metavariables,
69 : typename ActionList, typename ParallelComponent>
70 0 : static Parallel::iterable_action_return_t apply(
71 : db::DataBox<DbTagsList>& box,
72 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
73 : const Parallel::GlobalCache<Metavariables>& /*cache*/,
74 : const ElementId<Dim>& /*array_index*/, const ActionList /*meta*/,
75 : const ParallelComponent* const /*meta*/) {
76 : db::mutate_apply<InitializeOptionalAnalyticSolution>(make_not_null(&box));
77 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
78 : }
79 :
80 : public: // DataBox mutator, amr::protocols::Projector
81 0 : using return_tags = tmpl::list<analytic_fields_tag>;
82 0 : using argument_tags =
83 : tmpl::list<domain::Tags::Mesh<Dim>,
84 : domain::Tags::Coordinates<Dim, Frame::Inertial>,
85 : domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
86 : Frame::Inertial>,
87 : BackgroundTag, Parallel::Tags::Metavariables>;
88 :
89 : template <typename Background, typename Metavariables, typename... AmrData>
90 0 : static void apply(
91 : const gsl::not_null<typename analytic_fields_tag::type*>
92 : analytic_solution_fields,
93 : const Mesh<Dim>& mesh, const tnsr::I<DataVector, Dim> inertial_coords,
94 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
95 : Frame::Inertial>& inv_jacobian,
96 : const Background& background, const Metavariables& /*meta*/,
97 : const AmrData&... amr_data) {
98 : if constexpr (sizeof...(AmrData) == 1) {
99 : if constexpr (std::is_same_v<AmrData...,
100 : std::pair<Mesh<Dim>, Element<Dim>>>) {
101 : if (((mesh == amr_data.first) and ...)) {
102 : // This element hasn't changed during AMR. Nothing to do.
103 : return;
104 : }
105 : }
106 : }
107 :
108 : const auto analytic_solution =
109 : dynamic_cast<const AnalyticSolutionType*>(&background);
110 : if (analytic_solution != nullptr) {
111 : using factory_classes = typename std::decay_t<
112 : Metavariables>::factory_creation::factory_classes;
113 : *analytic_solution_fields = call_with_dynamic_type<
114 : Variables<AnalyticSolutionFields>,
115 : tmpl::at<factory_classes, AnalyticSolutionType>>(
116 : analytic_solution,
117 : [&inertial_coords, &mesh, &inv_jacobian](const auto* const derived) {
118 : return variables_from_tagged_tuple(derived->variables(
119 : inertial_coords, mesh, inv_jacobian, AnalyticSolutionFields{}));
120 : });
121 : } else {
122 : *analytic_solution_fields = std::nullopt;
123 : }
124 : }
125 : };
126 : /// @}
127 : } // namespace elliptic::Actions
|