Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <array>
7 : #include <cstddef>
8 : #include <memory>
9 : #include <optional>
10 : #include <string>
11 : #include <tuple>
12 : #include <unordered_map>
13 : #include <unordered_set>
14 : #include <utility>
15 :
16 : #include "DataStructures/DataBox/DataBox.hpp"
17 : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
18 : #include "Parallel/AlgorithmExecution.hpp"
19 : #include "Parallel/ArrayComponentId.hpp"
20 : #include "Parallel/Callback.hpp"
21 : #include "Parallel/GlobalCache.hpp"
22 : #include "Parallel/ParallelComponentHelpers.hpp"
23 : #include "Utilities/Algorithm.hpp"
24 : #include "Utilities/ErrorHandling/Assert.hpp"
25 : #include "Utilities/StdHelpers.hpp"
26 :
27 : /// \cond
28 : namespace Tags {
29 : struct Time;
30 : } // namespace Tags
31 : namespace domain::Tags {
32 : struct FunctionsOfTime;
33 : } // namespace domain::Tags
34 : namespace tuples {
35 : template <class... Tags>
36 : class TaggedTuple;
37 : } // namespace tuples
38 : /// \endcond
39 :
40 : namespace domain {
41 : namespace detail {
42 : template <typename CacheTag, typename Callback, typename Metavariables,
43 : typename ArrayIndex, typename Component, typename... Args>
44 : bool functions_of_time_are_ready_impl(
45 : Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
46 : const Component* /*meta*/, const double time,
47 : const std::optional<std::unordered_set<std::string>>& functions_to_check,
48 : Args&&... args) {
49 : if constexpr (Parallel::is_in_mutable_global_cache<Metavariables, CacheTag>) {
50 : const auto& proxy =
51 : ::Parallel::get_parallel_component<Component>(cache)[array_index];
52 : const Parallel::ArrayComponentId array_component_id =
53 : Parallel::make_array_component_id<Component>(array_index);
54 :
55 : return Parallel::mutable_cache_item_is_ready<CacheTag>(
56 : cache, array_component_id,
57 : [&functions_to_check, &proxy, &time,
58 : &args...](const std::unordered_map<
59 : std::string,
60 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
61 : functions_of_time) {
62 : using ::operator<<;
63 : ASSERT(
64 : alg::all_of(
65 : functions_to_check.value_or(
66 : std::unordered_set<std::string>{}),
67 : [&functions_of_time](const std::string& function_to_check) {
68 : return functions_of_time.count(function_to_check) == 1;
69 : }),
70 : "Not all functions to check ("
71 : << functions_to_check.value() << ") are in the global cache ("
72 : << keys_of(functions_of_time) << ")");
73 : for (const auto& [name, f_of_t] : functions_of_time) {
74 : if (functions_to_check.has_value() and
75 : functions_to_check->count(name) == 0) {
76 : continue;
77 : }
78 : const double expiration_time = f_of_t->time_bounds()[1];
79 : if (time > expiration_time) {
80 : return std::unique_ptr<Parallel::Callback>(
81 : new Callback(proxy, std::forward<Args>(args)...));
82 : }
83 : }
84 : return std::unique_ptr<Parallel::Callback>{};
85 : });
86 : } else {
87 : (void)cache;
88 : (void)array_index;
89 : (void)time;
90 : (void)functions_to_check;
91 : EXPAND_PACK_LEFT_TO_RIGHT((void)args);
92 : return true;
93 : }
94 : }
95 : } // namespace detail
96 :
97 : /// \ingroup ComputationalDomainGroup
98 : /// Check that functions of time are up-to-date.
99 : ///
100 : /// Check that functions of time in \p CacheTag with names in \p
101 : /// functions_to_check are ready at time \p time. If \p functions_to_check is
102 : /// a `std::nullopt`, checks all functions in \p CacheTag. If any function is
103 : /// not ready, schedules a `Parallel::PerformAlgorithmCallback` with the
104 : /// GlobalCache..
105 : template <typename CacheTag, typename Metavariables, typename ArrayIndex,
106 : typename Component>
107 1 : bool functions_of_time_are_ready_algorithm_callback(
108 : Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
109 : const Component* component_p, const double time,
110 : const std::optional<std::unordered_set<std::string>>& functions_to_check =
111 : std::nullopt) {
112 : using ProxyType =
113 : std::decay_t<decltype(::Parallel::get_parallel_component<Component>(
114 : cache)[array_index])>;
115 : return detail::functions_of_time_are_ready_impl<
116 : CacheTag, Parallel::PerformAlgorithmCallback<ProxyType>>(
117 : cache, array_index, component_p, time, functions_to_check);
118 : }
119 :
120 : /// \ingroup ComputationalDomainGroup
121 : /// Check that functions of time are up-to-date.
122 : ///
123 : /// Check that functions of time in \p CacheTag with names in \p
124 : /// functions_to_check are ready at time \p time. If \p functions_to_check is
125 : /// a `std::nullopt`, checks all functions in \p CacheTag. If any function is
126 : /// ready, schedules a `Parallel::SimpleActionCallback` with the GlobalCache
127 : /// which calls the simple action passed in as a template parameter. The `Args`
128 : /// are moved into the callback.
129 : template <typename CacheTag, typename SimpleAction, typename Metavariables,
130 : typename ArrayIndex, typename Component, typename... Args>
131 1 : bool functions_of_time_are_ready_simple_action_callback(
132 : Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
133 : const Component* component_p, const double time,
134 : const std::optional<std::unordered_set<std::string>>& functions_to_check,
135 : Args&&... args) {
136 : using ProxyType =
137 : std::decay_t<decltype(::Parallel::get_parallel_component<Component>(
138 : cache)[array_index])>;
139 : return detail::functions_of_time_are_ready_impl<
140 : CacheTag,
141 : Parallel::SimpleActionCallback<SimpleAction, ProxyType, Args...>>(
142 : cache, array_index, component_p, time, functions_to_check,
143 : std::forward<Args>(args)...);
144 : }
145 :
146 0 : namespace Actions {
147 : /// \ingroup ComputationalDomainGroup
148 : /// Check that functions of time are up-to-date.
149 : ///
150 : /// Wait for all functions of time in `domain::Tags::FunctionsOfTime`
151 : /// to be ready at `::Tags::Time`. This ensures that the coordinates
152 : /// can be safely accessed in later actions without first verifying
153 : /// the state of the time-dependent maps.
154 1 : struct CheckFunctionsOfTimeAreReady {
155 : template <typename DbTags, typename... InboxTags, typename Metavariables,
156 : typename ArrayIndex, typename ActionList,
157 : typename ParallelComponent>
158 0 : static Parallel::iterable_action_return_t apply(
159 : db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
160 : Parallel::GlobalCache<Metavariables>& cache,
161 : const ArrayIndex& array_index, ActionList /*meta*/,
162 : const ParallelComponent* component) {
163 : const bool ready = functions_of_time_are_ready_algorithm_callback<
164 : domain::Tags::FunctionsOfTime>(cache, array_index, component,
165 : db::get<::Tags::Time>(box));
166 : return {ready ? Parallel::AlgorithmExecution::Continue
167 : : Parallel::AlgorithmExecution::Retry,
168 : std::nullopt};
169 : }
170 : };
171 : } // namespace Actions
172 :
173 : /// \ingroup ComputationalDomainGroup Dense-output postprocessor to
174 : /// check that functions of time are up-to-date.
175 : ///
176 : /// Check that all functions of time in
177 : /// `domain::Tags::FunctionsOfTime` are ready at `::Tags::Time`. This
178 : /// ensures that the coordinates can be safely accessed in later
179 : /// actions without first verifying the state of the time-dependent
180 : /// maps. This postprocessor does not actually modify anything.
181 1 : struct CheckFunctionsOfTimeAreReadyPostprocessor {
182 0 : using return_tags = tmpl::list<>;
183 0 : using argument_tags = tmpl::list<>;
184 0 : static void apply() {}
185 :
186 : template <typename DbTagsList, typename... InboxTags, typename Metavariables,
187 : typename ArrayIndex, typename ParallelComponent>
188 0 : static bool is_ready(
189 : const gsl::not_null<db::DataBox<DbTagsList>*> box,
190 : const gsl::not_null<tuples::TaggedTuple<InboxTags...>*> /*inboxes*/,
191 : Parallel::GlobalCache<Metavariables>& cache,
192 : const ArrayIndex& array_index, const ParallelComponent* component) {
193 : return functions_of_time_are_ready_algorithm_callback<
194 : domain::Tags::FunctionsOfTime>(cache, array_index, component,
195 : db::get<::Tags::Time>(*box));
196 : }
197 : };
198 : } // namespace domain
|