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