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