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/TagName.hpp"
13 : #include "DataStructures/TaggedTuple.hpp"
14 : #include "DataStructures/Variables.hpp"
15 : #include "Domain/CoordinateMaps/Tags.hpp"
16 : #include "Domain/Tags.hpp"
17 : #include "Domain/TagsTimeDependent.hpp"
18 : #include "Evolution/DiscontinuousGalerkin/BoundaryEvolvedVariables.hpp"
19 : #include "Evolution/Initialization/InitialData.hpp"
20 : #include "Evolution/Initialization/Tags.hpp"
21 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
22 : #include "Parallel/AlgorithmExecution.hpp"
23 : #include "Parallel/GlobalCache.hpp"
24 : #include "PointwiseFunctions/AnalyticData/AnalyticData.hpp"
25 : #include "PointwiseFunctions/AnalyticData/Tags.hpp"
26 : #include "PointwiseFunctions/AnalyticSolutions/AnalyticSolution.hpp"
27 : #include "PointwiseFunctions/AnalyticSolutions/Tags.hpp"
28 : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp"
29 : #include "PointwiseFunctions/InitialDataUtilities/Tags/InitialData.hpp"
30 : #include "PointwiseFunctions/InitialDataUtilities/WithNoise.hpp"
31 : #include "Time/Tags/Time.hpp"
32 : #include "Utilities/Algorithm.hpp"
33 : #include "Utilities/CallWithDynamicType.hpp"
34 : #include "Utilities/ErrorHandling/Error.hpp"
35 : #include "Utilities/Gsl.hpp"
36 : #include "Utilities/TMPL.hpp"
37 :
38 : /// \cond
39 : namespace Parallel {
40 : template <typename Metavariables>
41 : class GlobalCache;
42 : } // namespace Parallel
43 : /// \endcond
44 :
45 0 : namespace evolution::Initialization::Actions {
46 : /// \ingroup InitializationGroup
47 : /// \brief Sets variables needed for evolution of hyperbolic systems
48 : ///
49 : /// Supports analytic solutions, analytic data, and
50 : /// `evolution::initial_data::WithNoise` wrappers. For `WithNoise`, the inner
51 : /// analytic solution sets variables normally, then uniform random noise is
52 : /// added to the requested evolution variables.
53 : ///
54 : /// Uses:
55 : /// - DataBox:
56 : /// * `CoordinatesTag`
57 : /// * `domain::CoordinateMaps::Tags::CoordinateMap` (for `WithNoise`)
58 : /// * `domain::Tags::ElementMap` (for `WithNoise`)
59 : /// * `domain::Tags::FunctionsOfTime` (for `WithNoise`)
60 : /// * `::Tags::Time`
61 : /// - GlobalCache:
62 : /// * `evolution::initial_data::Tags::InitialData`
63 : ///
64 : /// DataBox changes:
65 : /// - Adds: nothing
66 : /// - Removes: nothing
67 : /// - Modifies:
68 : /// * System::variables_tag (if system has no primitive variables)
69 : /// * System::primitive_variables_tag and the
70 : /// System::non_conservative_variables in System::variables_tag (if system
71 : /// has primitive variables)
72 : ///
73 : /// For a system with boundary-evolved variables, only the first entry of
74 : /// System::variables_tag, which holds the volume variables, is modified.
75 : template <typename LogicalCoordinatesTag>
76 1 : struct SetVariables {
77 0 : using simple_tags_from_options = tmpl::list<::Tags::Time>;
78 :
79 : template <typename DbTagsList, typename... InboxTags, typename Metavariables,
80 : typename ArrayIndex, typename ActionList,
81 : typename ParallelComponent>
82 0 : static Parallel::iterable_action_return_t apply(
83 : db::DataBox<DbTagsList>& box,
84 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
85 : const Parallel::GlobalCache<Metavariables>& /*cache*/,
86 : const ArrayIndex& /*array_index*/, ActionList /*meta*/,
87 : const ParallelComponent* const /*meta*/) {
88 : using derived_classes =
89 : tmpl::at<typename Metavariables::factory_creation::factory_classes,
90 : evolution::initial_data::InitialData>;
91 : call_with_dynamic_type<void, derived_classes>(
92 : &db::get<evolution::initial_data::Tags::InitialData>(box),
93 : [&box](const auto* const data_or_solution) {
94 : using initial_data_subclass =
95 : std::decay_t<decltype(*data_or_solution)>;
96 : if constexpr (is_analytic_data_v<initial_data_subclass> or
97 : is_analytic_solution_v<initial_data_subclass>) {
98 : impl<Metavariables>(make_not_null(&box), *data_or_solution);
99 : } else if constexpr (std::is_same_v<
100 : initial_data_subclass,
101 : evolution::initial_data::WithNoise>) {
102 : // For these systems the noise would be added to the conservative
103 : // variables, which are later recomputed from the (unperturbed)
104 : // primitives by `UpdateConservatives`, silently erasing it.
105 : static_assert(
106 : not Metavariables::system::has_primitive_and_conservative_vars,
107 : "WithNoise does not yet support systems with primitive "
108 : "variables: noise would be added to the conservative "
109 : "variables, which are overwritten when they are recomputed "
110 : "from the primitives.");
111 : // Dispatch on the inner solution to set variables normally.
112 : call_with_dynamic_type<void, derived_classes>(
113 : &data_or_solution->solution(), [&box](const auto* const inner) {
114 : using inner_type = std::decay_t<decltype(*inner)>;
115 : if constexpr (is_analytic_data_v<inner_type> or
116 : is_analytic_solution_v<inner_type>) {
117 : impl<Metavariables>(make_not_null(&box), *inner);
118 : } else {
119 : ERROR(
120 : "WithNoise: the inner Solution must be an analytic "
121 : "solution or analytic data. Numeric initial data "
122 : "cannot be wrapped by WithNoise.");
123 : }
124 : });
125 : // Compute inertial coordinates for per-element seed mixing.
126 : const double initial_time = db::get<::Tags::Time>(box);
127 : const auto inertial_coords =
128 : db::get<::domain::CoordinateMaps::Tags::CoordinateMap<
129 : Metavariables::volume_dim, Frame::Grid, Frame::Inertial>>(
130 : box)(db::get<::domain::Tags::ElementMap<
131 : Metavariables::volume_dim, Frame::Grid>>(box)(
132 : db::get<LogicalCoordinatesTag>(box)),
133 : initial_time,
134 : db::get<::domain::Tags::FunctionsOfTime>(box));
135 : const size_t element_seed =
136 : evolution::initial_data::make_element_seed(
137 : data_or_solution->seed(), inertial_coords);
138 : // Apply noise to each requested volume variable. For systems with
139 : // boundary-evolved variables, only the volume variables (the first
140 : // entry of variables_tag) receive noise.
141 : using system = typename Metavariables::system;
142 : using variables_tag = tmpl::conditional_t<
143 : evolution::dg::system_has_boundary_variables_v<system>,
144 : tmpl::front<typename system::variables_tag>,
145 : typename system::variables_tag>;
146 : const auto& targets = data_or_solution->variables();
147 : const bool noise_all = alg::found(targets, std::string{"All"});
148 : // Validate variable names against the actual tags list.
149 : if (not noise_all) {
150 : std::vector<std::string> valid_names{};
151 : tmpl::for_each<typename variables_tag::tags_list>(
152 : [&valid_names]<typename Tag>(tmpl::type_<Tag> /*meta*/) {
153 : valid_names.push_back(db::tag_name<Tag>());
154 : });
155 : for (const auto& target : targets) {
156 : if (not alg::found(valid_names, target)) {
157 : ERROR("WithNoise: unknown variable name '"
158 : << target
159 : << "'. Valid names for this system are: " << valid_names
160 : << ". Use [\"All\"] to noise every variable.");
161 : }
162 : }
163 : }
164 : size_t component_offset = 0;
165 : db::mutate<variables_tag>(
166 : [&targets, noise_all, &data_or_solution, element_seed,
167 : &component_offset](
168 : const gsl::not_null<typename variables_tag::type*> vars) {
169 : tmpl::for_each<typename variables_tag::tags_list>(
170 : [&]<typename Tag>(tmpl::type_<Tag> /*meta*/) {
171 : if (noise_all or
172 : alg::found(targets, db::tag_name<Tag>())) {
173 : evolution::initial_data::add_noise_to_tensor(
174 : make_not_null(&get<Tag>(*vars)),
175 : data_or_solution->amplitude(),
176 : data_or_solution->amplitude_type(), element_seed,
177 : component_offset);
178 : }
179 : component_offset +=
180 : std::decay_t<typename Tag::type>::size();
181 : });
182 : },
183 : make_not_null(&box));
184 : } else {
185 : ERROR(
186 : "Trying to use "
187 : "'evolution::Initialization::Actions::SetVariables' with a "
188 : "class that's not marked as analytic solution or analytic "
189 : "data. To support numeric initial data, add a "
190 : "system-specific initialization routine to your executable.");
191 : }
192 : });
193 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
194 : }
195 :
196 : private:
197 : template <typename Metavariables, typename DbTagsList, typename T>
198 0 : static void impl(const gsl::not_null<db::DataBox<DbTagsList>*> box,
199 : const T& solution_or_data) {
200 : const double initial_time = db::get<::Tags::Time>(*box);
201 : const auto inertial_coords =
202 : db::get<::domain::CoordinateMaps::Tags::CoordinateMap<
203 : Metavariables::volume_dim, Frame::Grid, Frame::Inertial>>(*box)(
204 : db::get<::domain::Tags::ElementMap<Metavariables::volume_dim,
205 : Frame::Grid>>(*box)(
206 : db::get<LogicalCoordinatesTag>(*box)),
207 : initial_time, db::get<::domain::Tags::FunctionsOfTime>(*box));
208 :
209 : using system = typename Metavariables::system;
210 : using variables_tag = tmpl::conditional_t<
211 : evolution::dg::system_has_boundary_variables_v<system>,
212 : tmpl::front<typename system::variables_tag>,
213 : typename system::variables_tag>;
214 :
215 : if constexpr (Metavariables::system::has_primitive_and_conservative_vars) {
216 : using primitives_tag = typename system::primitive_variables_tag;
217 : // Set initial data from analytic solution
218 : db::mutate<primitives_tag>(
219 : [&initial_time, &inertial_coords, &solution_or_data](
220 : const gsl::not_null<typename primitives_tag::type*>
221 : primitive_vars) {
222 : primitive_vars->assign_subset(
223 : evolution::Initialization::initial_data(
224 : solution_or_data, inertial_coords, initial_time,
225 : typename Metavariables::analytic_variables_tags{}));
226 : },
227 : box);
228 : using non_conservative_variables =
229 : typename system::non_conservative_variables;
230 : if constexpr (not std::is_same_v<non_conservative_variables,
231 : tmpl::list<>>) {
232 : db::mutate<variables_tag>(
233 : [&initial_time, &inertial_coords, &solution_or_data](
234 : const gsl::not_null<typename variables_tag::type*>
235 : evolved_vars) {
236 : evolved_vars->assign_subset(
237 : evolution::Initialization::initial_data(
238 : solution_or_data, inertial_coords, initial_time,
239 : non_conservative_variables{}));
240 : },
241 : box);
242 : }
243 : } else {
244 : // Set initial data from analytic solution
245 : if constexpr (not std::is_same_v<typename variables_tag::tags_list,
246 : tmpl::list<>>) {
247 : using Vars = typename variables_tag::type;
248 : db::mutate<variables_tag>(
249 : [&initial_time, &inertial_coords,
250 : &solution_or_data](const gsl::not_null<Vars*> vars) {
251 : vars->assign_subset(evolution::Initialization::initial_data(
252 : solution_or_data, inertial_coords, initial_time,
253 : typename Vars::tags_list{}));
254 : },
255 : box);
256 : }
257 : }
258 : }
259 : };
260 : } // namespace evolution::Initialization::Actions
|