Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <algorithm>
7 : #include <cstddef>
8 : #include <limits>
9 : #include <memory>
10 : #include <optional>
11 : #include <tuple>
12 : #include <utility>
13 :
14 : #include "ControlSystem/CombinedName.hpp"
15 : #include "ControlSystem/FutureMeasurements.hpp"
16 : #include "ControlSystem/Metafunctions.hpp"
17 : #include "ControlSystem/Tags/FutureMeasurements.hpp"
18 : #include "ControlSystem/Tags/MeasurementTimescales.hpp"
19 : #include "ControlSystem/Tags/SystemTags.hpp"
20 : #include "ControlSystem/Trigger.hpp"
21 : #include "DataStructures/DataBox/DataBox.hpp"
22 : #include "Parallel/AlgorithmExecution.hpp"
23 : #include "Parallel/GlobalCache.hpp"
24 : #include "ParallelAlgorithms/EventsAndDenseTriggers/DenseTrigger.hpp"
25 : #include "ParallelAlgorithms/EventsAndDenseTriggers/EventsAndDenseTriggers.hpp"
26 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
27 : #include "Time/ChooseLtsStepSize.hpp"
28 : #include "Time/LtsMode.hpp"
29 : #include "Time/Slab.hpp"
30 : #include "Time/Time.hpp"
31 : #include "Utilities/ErrorHandling/Error.hpp"
32 : #include "Utilities/Gsl.hpp"
33 : #include "Utilities/MakeVector.hpp"
34 : #include "Utilities/TMPL.hpp"
35 :
36 : /// \cond
37 : class TimeStepper;
38 : namespace Tags {
39 : struct EventsAndDenseTriggers;
40 : struct LtsMode;
41 : struct TimeStep;
42 : template <typename StepperInterface>
43 : struct TimeStepper;
44 : } // namespace Tags
45 : namespace domain::Tags {
46 : struct FunctionsOfTime;
47 : } // namespace domain::Tags
48 : namespace tuples {
49 : template <typename... Tags>
50 : class TaggedTuple;
51 : } // namespace tuples
52 : /// \endcond
53 :
54 : namespace control_system::Actions {
55 : /// \ingroup ControlSystemGroup
56 : /// \brief Set up the element component for control-system measurements.
57 : template <typename ControlSystems>
58 1 : struct InitializeMeasurements {
59 0 : using control_system_groups =
60 : tmpl::transform<metafunctions::measurements_t<ControlSystems>,
61 : metafunctions::control_systems_with_measurement<
62 : tmpl::pin<ControlSystems>, tmpl::_1>>;
63 :
64 0 : using simple_tags =
65 : tmpl::transform<control_system_groups,
66 : tmpl::bind<Tags::FutureMeasurements, tmpl::_1>>;
67 0 : using const_global_cache_tags =
68 : tmpl::list<Tags::MeasurementsPerUpdate, Tags::DelayUpdate>;
69 0 : using mutable_global_cache_tags =
70 : tmpl::list<control_system::Tags::MeasurementTimescales>;
71 :
72 : template <typename DbTagsList, typename... InboxTags, typename Metavariables,
73 : typename ArrayIndex, typename ActionList,
74 : typename ParallelComponent>
75 0 : static Parallel::iterable_action_return_t apply(
76 : db::DataBox<DbTagsList>& box,
77 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
78 : const Parallel::GlobalCache<Metavariables>& cache,
79 : const ArrayIndex& /*array_index*/, ActionList /*meta*/,
80 : const ParallelComponent* const /*meta*/) {
81 : if (not db::get<Tags::DelayUpdate>(box) and
82 : not db::get<::Tags::TimeStepper<TimeStepper>>(box).monotonic()) {
83 : ERROR_NO_TRACE(
84 : "Chosen TimeStepper requires DelayUpdate: true to avoid deadlocks");
85 : }
86 :
87 : const double initial_time = db::get<::Tags::Time>(box);
88 : const int measurements_per_update =
89 : db::get<Tags::MeasurementsPerUpdate>(box);
90 : const auto& timescales = Parallel::get<Tags::MeasurementTimescales>(cache);
91 : tmpl::for_each<control_system_groups>([&](auto group_v) {
92 : using group = tmpl::type_from<decltype(group_v)>;
93 : const bool active =
94 : timescales.at(combined_name<group>())->func(initial_time)[0][0] !=
95 : std::numeric_limits<double>::infinity();
96 : db::mutate<Tags::FutureMeasurements<group>>(
97 : [&](const gsl::not_null<FutureMeasurements*> measurements) {
98 : if (active) {
99 : *measurements = FutureMeasurements(
100 : static_cast<size_t>(measurements_per_update), initial_time);
101 : } else {
102 : *measurements = FutureMeasurements(
103 : 1, std::numeric_limits<double>::infinity());
104 : }
105 : },
106 : make_not_null(&box));
107 : });
108 :
109 : db::mutate<::Tags::EventsAndDenseTriggers>(
110 : [](const gsl::not_null<EventsAndDenseTriggers*>
111 : events_and_dense_triggers) {
112 : tmpl::for_each<metafunctions::measurements_t<ControlSystems>>(
113 : [&events_and_dense_triggers](auto measurement_v) {
114 : using measurement = tmpl::type_from<decltype(measurement_v)>;
115 : using control_system_group =
116 : metafunctions::control_systems_with_measurement_t<
117 : ControlSystems, measurement>;
118 : using events = tmpl::transform<
119 : typename measurement::submeasurements,
120 : metafunctions::event_from_submeasurement<
121 : tmpl::pin<control_system_group>, tmpl::_1>>;
122 : std::vector<std::unique_ptr<::Event>> vector_of_events =
123 : tmpl::as_pack<events>([](auto... events_v) {
124 : return make_vector<std::unique_ptr<::Event>>(
125 : std::make_unique<
126 : tmpl::type_from<decltype(events_v)>>()...);
127 : });
128 : events_and_dense_triggers->add_trigger_and_events(
129 : std::make_unique<
130 : control_system::Trigger<control_system_group>>(),
131 : std::move(vector_of_events));
132 : });
133 : },
134 : make_not_null(&box));
135 :
136 : // Ensure that the initial time step is small enough that we don't
137 : // need to perform any measurements to complete it. This is only
138 : // necessary for TimeSteppers that use the self-start procedure,
139 : // because they cannot adjust their step size on the first step
140 : // after self-start, but it isn't harmful to do it in other cases.
141 : //
142 : // Unlike in the steady-state step-limiting code, we don't do
143 : // anything clever looking at measurement times or planning ahead
144 : // for future steps. Avoiding a single non-ideal step isn't worth
145 : // the added complexity.
146 : const auto lts_mode = db::get<::Tags::LtsMode>(box);
147 : double earliest_expiration = std::numeric_limits<double>::infinity();
148 : for (const auto& fot :
149 : Parallel::get<domain::Tags::FunctionsOfTime>(cache)) {
150 : earliest_expiration =
151 : std::min(earliest_expiration, fot.second->time_bounds()[1]);
152 : }
153 : const auto& time_step = db::get<::Tags::TimeStep>(box);
154 : const auto start_time = time_step.slab().start();
155 : if ((start_time + time_step).value() > earliest_expiration) {
156 : db::mutate<::Tags::TimeStep>(
157 : [&](const gsl::not_null<TimeDelta*> step) {
158 : if (lts_mode != LtsMode::Off) {
159 : *step = choose_lts_step_size(
160 : start_time,
161 : 0.99 * (earliest_expiration - start_time.value()));
162 : } else {
163 : *step = Slab(start_time.value(), earliest_expiration).duration();
164 : }
165 : },
166 : make_not_null(&box));
167 : }
168 :
169 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
170 : }
171 : };
172 : } // namespace control_system::Actions
|