Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cstddef> 7 : #include <limits> 8 : #include <optional> 9 : #include <string> 10 : 11 : #include "ControlSystem/Averager.hpp" 12 : #include "ControlSystem/ControlErrors/Size.hpp" 13 : #include "ControlSystem/TimescaleTuner.hpp" 14 : #include "DataStructures/DataVector.hpp" 15 : #include "Domain/Structure/ObjectLabel.hpp" 16 : #include "IO/Logging/Verbosity.hpp" 17 : #include "Parallel/GlobalCache.hpp" 18 : #include "Parallel/Printf/Printf.hpp" 19 : #include "Utilities/Gsl.hpp" 20 : 21 : namespace control_system::size { 22 : /*! 23 : * \brief Updates the Averager with information from the \link 24 : * control_system::ControlErrors::Size Size control error \endlink. 25 : * 26 : * \details After we calculate the control error, we check if a discontinuous 27 : * change has occurred (the internal `control_system::size::State` changed). If 28 : * no discontinuous change has occurred, then we do nothing. If one did occur, 29 : * we get a history of control errors from the \link 30 : * control_system::ControlErrors::Size Size control error \endlink and use that 31 : * to repopulate the Averager history. 32 : * 33 : * \note See `control_system::Tags::Averager` for why the Averager is templated 34 : * on `DerivOrder - 1`. 35 : */ 36 : template <size_t DerivOrder, ::domain::ObjectLabel Horizon, 37 : typename Metavariables> 38 1 : void update_averager( 39 : const gsl::not_null<Averager<DerivOrder - 1>*> averager, 40 : const gsl::not_null<ControlErrors::Size<DerivOrder, Horizon>*> 41 : control_error, 42 : const Parallel::GlobalCache<Metavariables>& cache, const double time, 43 : const DataVector& current_timescale, 44 : const std::string& function_of_time_name, const int current_measurement) { 45 : if (control_error->discontinuous_change_has_occurred()) { 46 : control_error->reset(); 47 : averager->clear(); 48 : 49 : const std::deque<std::pair<double, double>> control_error_history = 50 : control_error->control_error_history(); 51 : 52 : if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Verbose) { 53 : std::vector<double> history_times{}; 54 : for (const auto& history : control_error_history) { 55 : history_times.push_back(history.first); 56 : } 57 : Parallel::printf( 58 : "%s, time = %.16f: current measurement = %d, Discontinuous " 59 : "change has occurred. Repopulating averager with control error " 60 : "history from times: %s\n", 61 : function_of_time_name, time, current_measurement, history_times); 62 : } 63 : 64 : for (const auto& [stored_time, stored_control_error] : 65 : control_error_history) { 66 : // Size 1 because it's size control 67 : averager->update(stored_time, DataVector{1, stored_control_error}, 68 : current_timescale); 69 : } 70 : } 71 : } 72 : 73 : /*! 74 : * \brief Updates the TimescaleTuner with information from the \link 75 : * control_system::ControlErrors::Size Size control error \endlink. 76 : * 77 : * \details We check for a suggested timescale from the \link 78 : * control_system::ControlErrors::Size Size control error \endlink. If one is 79 : * suggested and it is smaller than the current damping timescale, we set the 80 : * timescale in the TimescaleTuner to this suggested value. Otherwise, we let 81 : * the TimescaleTuner adjust the timescale. Regardless of whether a timescale 82 : * was suggested or not, we always reset the size control error. 83 : */ 84 : template <size_t DerivOrder, ::domain::ObjectLabel Horizon, 85 : typename Metavariables> 86 1 : void update_tuner(const gsl::not_null<TimescaleTuner<false>*> tuner, 87 : const gsl::not_null<ControlErrors::Size<DerivOrder, Horizon>*> 88 : control_error, 89 : const Parallel::GlobalCache<Metavariables>& cache, 90 : const double time, const std::string& function_of_time_name) { 91 : const std::optional<double>& suggested_timescale = 92 : control_error->get_suggested_timescale(); 93 : const double old_timescale = min(tuner->current_timescale()); 94 : 95 : if (suggested_timescale.value_or(std::numeric_limits<double>::infinity()) < 96 : old_timescale) { 97 : tuner->set_timescale_if_in_allowable_range(suggested_timescale.value()); 98 : } 99 : 100 : if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Verbose) { 101 : using ::operator<<; 102 : Parallel::printf( 103 : "%s, time = %.16f:\n" 104 : " old_timescale = %.16f\n" 105 : " suggested_timescale = %s\n" 106 : " new_timescale = %.16f\n", 107 : function_of_time_name, time, old_timescale, 108 : MakeString{} << suggested_timescale, min(tuner->current_timescale())); 109 : } 110 : 111 : // This reset call is ok because if there was a discontinuous change 112 : // above after calculating the control error, the control error class was 113 : // already reset so this reset won't do anything. If there wasn't a 114 : // discontinuous change, then this will only affect the suggested 115 : // timescale, which we always want to reset. 116 : control_error->reset(); 117 : } 118 : } // namespace control_system::size