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