Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <optional>
7 : #include <set>
8 : #include <sstream>
9 : #include <string>
10 : #include <type_traits>
11 :
12 : #include "DataStructures/LinkedMessageId.hpp"
13 : #include "DataStructures/Variables.hpp"
14 : #include "Domain/Creators/Tags/Domain.hpp"
15 : #include "Domain/FunctionsOfTime/Tags.hpp"
16 : #include "Domain/Structure/ElementId.hpp"
17 : #include "IO/Logging/Verbosity.hpp"
18 : #include "Parallel/ArrayComponentId.hpp"
19 : #include "Parallel/Callback.hpp"
20 : #include "Parallel/GlobalCache.hpp"
21 : #include "Parallel/Invoke.hpp"
22 : #include "Parallel/ParallelComponentHelpers.hpp"
23 : #include "Parallel/Printf/Printf.hpp"
24 : #include "ParallelAlgorithms/ApparentHorizonFinder/HorizonAliases.hpp"
25 : #include "ParallelAlgorithms/ApparentHorizonFinder/Storage.hpp"
26 : #include "Utilities/ErrorHandling/Assert.hpp"
27 : #include "Utilities/Gsl.hpp"
28 :
29 : /// \cond
30 : namespace ah {
31 : template <class Metavariables, typename HorizonMetavars>
32 : struct Component;
33 : template <typename HorizonMetavars>
34 : struct FindApparentHorizon;
35 : } // namespace ah
36 : /// \endcond
37 :
38 : namespace ah {
39 : /*!
40 : * \brief Determines what the current time should be.
41 : *
42 : * \details If there's already a current time, or there are no pending times
43 : * available, then there's nothing to do. Otherwise, checks if the first pending
44 : * time is the next to use. If so, sets it as the current time and removes it
45 : * from pending.
46 : */
47 : template <typename Fr>
48 1 : void set_current_time(
49 : gsl::not_null<std::optional<LinkedMessageId<double>>*> current_time,
50 : gsl::not_null<std::set<LinkedMessageId<double>>*> pending_times,
51 : const std::set<LinkedMessageId<double>>& completed_times,
52 : const std::unordered_map<LinkedMessageId<double>,
53 : ah::Storage::SingleTimeStorage<Fr>>& all_storage,
54 : const ::Verbosity& verbosity, const std::string& name);
55 :
56 : /*!
57 : * \brief Checks if the current time is ready.
58 : *
59 : * \details If the current time is after any expiration time, registers a
60 : * callback for the `ah::FindApparentHorizon` action (but doesn't send the
61 : * volume variables again because we already did that). Returns if the current
62 : * time is ready or not.
63 : */
64 : template <typename HorizonMetavars, typename Metavariables>
65 1 : bool check_if_current_time_is_ready(
66 : const LinkedMessageId<double>& current_time,
67 : Parallel::GlobalCache<Metavariables>& cache,
68 : const LinkedMessageId<double>& incoming_time,
69 : const ElementId<3>& incoming_element_id, const ::Mesh<3>& incoming_mesh,
70 : const std::optional<std::string>& dependency) {
71 : const auto& domain = get<domain::Tags::Domain<3>>(cache);
72 :
73 : // Now we need to check the functions of time for the current time
74 : if constexpr (Parallel::is_in_global_cache<Metavariables,
75 : domain::Tags::FunctionsOfTime>) {
76 : if (domain.is_time_dependent()) {
77 : auto& this_proxy = Parallel::get_parallel_component<
78 : Component<Metavariables, HorizonMetavars>>(cache);
79 : double min_expiration_time = std::numeric_limits<double>::max();
80 : const Parallel::ArrayComponentId array_component_id =
81 : Parallel::make_array_component_id<
82 : Component<Metavariables, HorizonMetavars>>(0);
83 : // If the functions of time aren't ready, this will set a callback to
84 : // FindApparentHorizon that will be called by the GlobalCache when
85 : // domain::Tags::FunctionsOfTime is updated.
86 : return ::Parallel::mutable_cache_item_is_ready<
87 : domain::Tags::FunctionsOfTime>(
88 : cache, array_component_id,
89 : [&](const std::unordered_map<
90 : std::string,
91 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
92 : functions_of_time) -> std::unique_ptr<Parallel::Callback> {
93 : min_expiration_time =
94 : std::min_element(functions_of_time.begin(),
95 : functions_of_time.end(),
96 : [](const auto& a, const auto& b) {
97 : return a.second->time_bounds()[1] <
98 : b.second->time_bounds()[1];
99 : })
100 : ->second->time_bounds()[1];
101 :
102 : // Success: the current time is ok.
103 : // Failure: the current time is not ok.
104 : using horizon_frame = typename HorizonMetavars::frame;
105 : return current_time.id <= min_expiration_time
106 : ? std::unique_ptr<Parallel::Callback>{}
107 : : std::unique_ptr<Parallel::Callback>(
108 : new Parallel::SimpleActionCallback<
109 : FindApparentHorizon<HorizonMetavars>,
110 : decltype(this_proxy), LinkedMessageId<double>,
111 : ElementId<3>, Mesh<3>,
112 : Variables<ah::vars_to_interpolate_to_target<
113 : 3, horizon_frame>>,
114 : std::optional<std::string>, bool>(
115 : this_proxy, incoming_time, incoming_element_id,
116 : incoming_mesh,
117 : Variables<ah::vars_to_interpolate_to_target<
118 : 3, horizon_frame>>{},
119 : dependency,
120 : /* vars_have_already_been_received */ true));
121 : });
122 : } // if (domain.is_time_dependent())
123 : } else {
124 : if (domain.is_time_dependent()) {
125 : // We error here because the maps are time-dependent, yet
126 : // the cache does not contain FunctionsOfTime. It would be
127 : // nice to make this a compile-time error; however, we want
128 : // the code to compile for the completely time-independent
129 : // case where there are no FunctionsOfTime in the cache at
130 : // all. Unfortunately, checking whether the maps are
131 : // time-dependent is currently not constexpr.
132 : ERROR(
133 : "There is a time-dependent CoordinateMap in at least one "
134 : "of the Blocks, but FunctionsOfTime are not in the "
135 : "GlobalCache. If you intend to use a time-dependent "
136 : "CoordinateMap, please add FunctionsOfTime to the GlobalCache.");
137 : }
138 : }
139 :
140 : // The current time is ready
141 : return true;
142 : }
143 : } // namespace ah
|