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