From 7f0a994529a01ce22578ba8b33f99d110e7a4752 Mon Sep 17 00:00:00 2001 From: Kyle Nelli Date: Sat, 21 Oct 2023 16:32:22 -0700 Subject: [PATCH] Allow timescale tuner to not decrease timescale --- .../CalculateMeasurementTimescales.cpp | 26 +- .../CalculateMeasurementTimescales.hpp | 6 +- src/ControlSystem/ControlErrors/Expansion.hpp | 2 +- src/ControlSystem/ControlErrors/Rotation.hpp | 2 +- src/ControlSystem/ControlErrors/Shape.hpp | 2 +- src/ControlSystem/ControlErrors/Size.cpp | 2 +- src/ControlSystem/ControlErrors/Size.hpp | 8 +- .../ControlErrors/Size/Update.hpp | 2 +- .../ControlErrors/Translation.hpp | 2 +- src/ControlSystem/IsSize.hpp | 10 +- src/ControlSystem/Protocols/ControlError.hpp | 34 +- .../Tags/MeasurementTimescales.hpp | 5 +- src/ControlSystem/Tags/OptionTags.hpp | 12 +- src/ControlSystem/Tags/SystemTags.cpp | 12 +- src/ControlSystem/Tags/SystemTags.hpp | 14 +- src/ControlSystem/TimescaleTuner.cpp | 56 ++- src/ControlSystem/TimescaleTuner.hpp | 34 +- support/Pipelines/Bbh/Inspiral.yaml | 2 - support/Pipelines/Bbh/Ringdown.yaml | 2 - .../GeneralizedHarmonic/BinaryBlackHole.yaml | 2 - .../CylindricalBinaryBlackHole.yaml | 2 - .../GeneralizedHarmonic/KerrSchild.yaml | 2 - .../Actions/Test_Initialization.cpp | 4 +- .../ControlErrors/Test_Expansion.cpp | 4 +- .../ControlErrors/Test_Rotation.cpp | 2 +- .../ControlErrors/Test_Shape.cpp | 2 +- .../ControlErrors/Test_SizeError.cpp | 4 +- .../ControlErrors/Test_Translation.cpp | 4 +- .../Tags/Test_FunctionsOfTimeInitialize.cpp | 16 +- .../Tags/Test_MeasurementTimescales.cpp | 26 +- tests/Unit/ControlSystem/Test_Controller.cpp | 24 +- .../ControlSystem/Test_ExpirationTimes.cpp | 6 +- tests/Unit/ControlSystem/Test_Tags.cpp | 26 +- .../ControlSystem/Test_TimescaleTuner.cpp | 455 ++++++++++-------- tests/Unit/Helpers/ControlSystem/Examples.hpp | 2 +- .../Helpers/ControlSystem/TestStructs.hpp | 2 +- 36 files changed, 465 insertions(+), 351 deletions(-) diff --git a/src/ControlSystem/CalculateMeasurementTimescales.cpp b/src/ControlSystem/CalculateMeasurementTimescales.cpp index 6e23f6f90558..c05d487ce4c3 100644 --- a/src/ControlSystem/CalculateMeasurementTimescales.cpp +++ b/src/ControlSystem/CalculateMeasurementTimescales.cpp @@ -6,21 +6,31 @@ #include "ControlSystem/Controller.hpp" #include "ControlSystem/TimescaleTuner.hpp" #include "DataStructures/DataVector.hpp" +#include "Utilities/GenerateInstantiations.hpp" namespace control_system { -template +template DataVector calculate_measurement_timescales( - const ::Controller& controller, const ::TimescaleTuner& tuner, + const ::Controller& controller, + const ::TimescaleTuner& tuner, const int measurements_per_update) { return tuner.current_timescale() * controller.get_update_fraction() / static_cast(measurements_per_update); } -template DataVector calculate_measurement_timescales<2>( - const ::Controller<2>& controller, const ::TimescaleTuner& tuner, - const int measurements_per_update); -template DataVector calculate_measurement_timescales<3>( - const ::Controller<3>& controller, const ::TimescaleTuner& tuner, - const int measurements_per_update); +#define DIM(data) BOOST_PP_TUPLE_ELEM(0, data) +#define ALLOWDECREASE(data) BOOST_PP_TUPLE_ELEM(1, data) + +#define INSTANTIATE(_, data) \ + template DataVector calculate_measurement_timescales( \ + const ::Controller& controller, \ + const ::TimescaleTuner& tuner, \ + const int measurements_per_update); + +GENERATE_INSTANTIATIONS(INSTANTIATE, (1, 2, 3), (true, false)) + +#undef INSTANTIATE +#undef DIM +#undef ALLOWDECREASE } // namespace control_system diff --git a/src/ControlSystem/CalculateMeasurementTimescales.hpp b/src/ControlSystem/CalculateMeasurementTimescales.hpp index a45a0cc23641..7d73768a51f5 100644 --- a/src/ControlSystem/CalculateMeasurementTimescales.hpp +++ b/src/ControlSystem/CalculateMeasurementTimescales.hpp @@ -9,6 +9,7 @@ template class Controller; class DataVector; +template class TimescaleTuner; /// \endcond @@ -29,8 +30,9 @@ namespace control_system { * we calculate the measurement timescales as \f$\tau_\mathrm{m} = * \tau_\mathrm{update} / N\f$ where \f$N\f$ is `measurements_per_update`. */ -template +template DataVector calculate_measurement_timescales( - const ::Controller& controller, const ::TimescaleTuner& tuner, + const ::Controller& controller, + const ::TimescaleTuner& tuner, const int measurements_per_update); } // namespace control_system diff --git a/src/ControlSystem/ControlErrors/Expansion.hpp b/src/ControlSystem/ControlErrors/Expansion.hpp index bf08fffbc76a..e59af3fbf441 100644 --- a/src/ControlSystem/ControlErrors/Expansion.hpp +++ b/src/ControlSystem/ControlErrors/Expansion.hpp @@ -75,7 +75,7 @@ struct Expansion : tt::ConformsTo { void pup(PUP::er& /*p*/) {} template - DataVector operator()(const ::TimescaleTuner& /*unused*/, + DataVector operator()(const ::TimescaleTuner& /*unused*/, const Parallel::GlobalCache& cache, const double time, const std::string& function_of_time_name, diff --git a/src/ControlSystem/ControlErrors/Rotation.hpp b/src/ControlSystem/ControlErrors/Rotation.hpp index 9e259c502cfb..932a56030f14 100644 --- a/src/ControlSystem/ControlErrors/Rotation.hpp +++ b/src/ControlSystem/ControlErrors/Rotation.hpp @@ -71,7 +71,7 @@ struct Rotation : tt::ConformsTo { void pup(PUP::er& /*p*/) {} template - DataVector operator()(const ::TimescaleTuner& /*unused*/, + DataVector operator()(const ::TimescaleTuner& /*unused*/, const Parallel::GlobalCache& cache, const double /*time*/, const std::string& /*function_of_time_name*/, diff --git a/src/ControlSystem/ControlErrors/Shape.hpp b/src/ControlSystem/ControlErrors/Shape.hpp index 5db75952565c..898e6e84c6fb 100644 --- a/src/ControlSystem/ControlErrors/Shape.hpp +++ b/src/ControlSystem/ControlErrors/Shape.hpp @@ -105,7 +105,7 @@ struct Shape : tt::ConformsTo { void pup(PUP::er& /*p*/) {} template - DataVector operator()(const ::TimescaleTuner& /*unused*/, + DataVector operator()(const ::TimescaleTuner& /*unused*/, const Parallel::GlobalCache& cache, const double time, const std::string& function_of_time_name, diff --git a/src/ControlSystem/ControlErrors/Size.cpp b/src/ControlSystem/ControlErrors/Size.cpp index 1d28f56337be..7212e3abab7a 100644 --- a/src/ControlSystem/ControlErrors/Size.cpp +++ b/src/ControlSystem/ControlErrors/Size.cpp @@ -36,7 +36,7 @@ namespace ControlErrors { template Size::Size( const int max_times, const double smooth_avg_timescale_frac, - TimescaleTuner smoother_tuner, + TimescaleTuner smoother_tuner, std::optional delta_r_drift_outward_options) : smoother_tuner_(std::move(smoother_tuner)), delta_r_drift_outward_options_(delta_r_drift_outward_options) { diff --git a/src/ControlSystem/ControlErrors/Size.hpp b/src/ControlSystem/ControlErrors/Size.hpp index c3d6bd159885..548b36a18608 100644 --- a/src/ControlSystem/ControlErrors/Size.hpp +++ b/src/ControlSystem/ControlErrors/Size.hpp @@ -185,7 +185,7 @@ struct Size : tt::ConformsTo { }; struct SmootherTuner { - using type = TimescaleTuner; + using type = TimescaleTuner; static constexpr Options::String help{ "TimescaleTuner for smoothing horizon measurements."}; }; @@ -250,7 +250,7 @@ struct Size : tt::ConformsTo { * is moved inside this class. */ Size(const int max_times, const double smooth_avg_timescale_frac, - TimescaleTuner smoother_tuner, + TimescaleTuner smoother_tuner, std::optional delta_r_drift_outward_options); /// Returns the internal `control_system::size::Info::suggested_time_scale`. A @@ -299,7 +299,7 @@ struct Size : tt::ConformsTo { * \return DataVector should be of size 1 */ template - DataVector operator()(const ::TimescaleTuner& tuner, + DataVector operator()(const ::TimescaleTuner& tuner, const Parallel::GlobalCache& cache, const double time, const std::string& function_of_time_name, @@ -471,7 +471,7 @@ struct Size : tt::ConformsTo { } private: - TimescaleTuner smoother_tuner_{}; + TimescaleTuner smoother_tuner_{}; Averager horizon_coef_averager_{}; size::Info info_{}; intrp::ZeroCrossingPredictor char_speed_predictor_{}; diff --git a/src/ControlSystem/ControlErrors/Size/Update.hpp b/src/ControlSystem/ControlErrors/Size/Update.hpp index 5a12b622a6d1..38dcb53710a3 100644 --- a/src/ControlSystem/ControlErrors/Size/Update.hpp +++ b/src/ControlSystem/ControlErrors/Size/Update.hpp @@ -83,7 +83,7 @@ void update_averager( */ template -void update_tuner(const gsl::not_null tuner, +void update_tuner(const gsl::not_null*> tuner, const gsl::not_null*> control_error, const Parallel::GlobalCache& cache, diff --git a/src/ControlSystem/ControlErrors/Translation.hpp b/src/ControlSystem/ControlErrors/Translation.hpp index c6ef3b196129..93ebb9d4f792 100644 --- a/src/ControlSystem/ControlErrors/Translation.hpp +++ b/src/ControlSystem/ControlErrors/Translation.hpp @@ -84,7 +84,7 @@ struct Translation : tt::ConformsTo { void pup(PUP::er& /*p*/) {} template - DataVector operator()(const ::TimescaleTuner& tuner, + DataVector operator()(const ::TimescaleTuner& tuner, const Parallel::GlobalCache& cache, const double time, const std::string& /*function_of_time_name*/, diff --git a/src/ControlSystem/IsSize.hpp b/src/ControlSystem/IsSize.hpp index c5f8d0bccacc..482192fa69e5 100644 --- a/src/ControlSystem/IsSize.hpp +++ b/src/ControlSystem/IsSize.hpp @@ -3,9 +3,17 @@ #pragma once -#include "ControlSystem/Systems/Size.hpp" +#include + #include "Domain/Structure/ObjectLabel.hpp" +/// \cond +namespace control_system::Systems { +template <::domain::ObjectLabel Horizon, size_t DerivOrder> +struct Size; +} // namespace control_system::Systems +/// \endcond + namespace control_system::size { // tt::is_a doesn't work because of domain::ObjectLabel and size_t template diff --git a/src/ControlSystem/Protocols/ControlError.hpp b/src/ControlSystem/Protocols/ControlError.hpp index a8df138c0823..c5acfe85fc76 100644 --- a/src/ControlSystem/Protocols/ControlError.hpp +++ b/src/ControlSystem/Protocols/ControlError.hpp @@ -12,9 +12,26 @@ #include "Utilities/TMPL.hpp" #include "Utilities/TaggedTuple.hpp" +template struct TimescaleTuner; namespace control_system::protocols { +namespace detail { + +struct DummyMetavariables { + using component_list = tmpl::list<>; +}; +struct DummyTupleTags { + using type = int; +}; + +template +struct has_signature + : std::is_invocable_r&, + const Parallel::GlobalCache&, + const double, const std::string&, + const tuples::TaggedTuple&> {}; +} // namespace detail /// \brief Definition of a control error /// /// A control error is used within a control system to compute how far off the @@ -31,29 +48,20 @@ namespace control_system::protocols { /// `domain::Tags::ObjectCenter`s tags to be in the GlobalCache for this /// control system to work. /// +/// \note The TimescaleTuner can have it's template parameter be either `true` +/// or `false`. /// /// \snippet Helpers/ControlSystem/Examples.hpp ControlError struct ControlError { template struct test { - struct DummyMetavariables; - struct DummyTupleTags; - static constexpr size_t expected_number_of_excisions = ConformingType::expected_number_of_excisions; using object_centers = typename ConformingType::object_centers; - static_assert( - std::is_same_v< - DataVector, - decltype(ConformingType{}( - std::declval(), - std::declval< - const Parallel::GlobalCache&>(), - std::declval(), - std::declval(), - std::declval&>()))>); + static_assert(detail::has_signature::value or + detail::has_signature::value); }; }; } // namespace control_system::protocols diff --git a/src/ControlSystem/Tags/MeasurementTimescales.hpp b/src/ControlSystem/Tags/MeasurementTimescales.hpp index 7e6e238062c1..83451fa0f149 100644 --- a/src/ControlSystem/Tags/MeasurementTimescales.hpp +++ b/src/ControlSystem/Tags/MeasurementTimescales.hpp @@ -126,8 +126,9 @@ struct MeasurementTimescales : db::SimpleTag { const std::string& combined_name = map_of_names[control_system_name]; auto tuner = option_holder.tuner; - Tags::detail::initialize_tuner(make_not_null(&tuner), domain_creator, - initial_time, control_system_name); + ::control_system::Tags::detail::initialize_tuner( + make_not_null(&tuner), domain_creator, initial_time, + control_system_name); const auto& controller = option_holder.controller; DataVector measurement_timescales = calculate_measurement_timescales( diff --git a/src/ControlSystem/Tags/OptionTags.hpp b/src/ControlSystem/Tags/OptionTags.hpp index 074c9aa83b6b..c6023230f9cf 100644 --- a/src/ControlSystem/Tags/OptionTags.hpp +++ b/src/ControlSystem/Tags/OptionTags.hpp @@ -8,6 +8,7 @@ #include "ControlSystem/Averager.hpp" #include "ControlSystem/Controller.hpp" +#include "ControlSystem/IsSize.hpp" #include "ControlSystem/Protocols/ControlSystem.hpp" #include "ControlSystem/TimescaleTuner.hpp" #include "IO/Logging/Verbosity.hpp" @@ -24,6 +25,11 @@ namespace control_system { /// their public member names and assigned to their corresponding DataBox tags. template struct OptionHolder { + private: + static constexpr bool is_size = + ::control_system::size::is_size_v; + + public: static_assert(tt::assert_conforms_to_v< ControlSystem, control_system::protocols::ControlSystem>); using control_system = ControlSystem; @@ -51,7 +57,7 @@ struct OptionHolder { }; struct TimescaleTuner { - using type = ::TimescaleTuner; + using type = ::TimescaleTuner; static constexpr Options::String help = { "Keeps track of the damping timescales for the control system upon " "which other timescales are based of off."}; @@ -71,7 +77,7 @@ struct OptionHolder { OptionHolder(const bool input_is_active, ::Averager input_averager, ::Controller input_controller, - ::TimescaleTuner input_tuner, + ::TimescaleTuner input_tuner, typename ControlSystem::control_error input_control_error) : is_active(input_is_active), averager(std::move(input_averager)), @@ -100,7 +106,7 @@ struct OptionHolder { bool is_active{true}; ::Averager averager{}; ::Controller controller{}; - ::TimescaleTuner tuner{}; + ::TimescaleTuner tuner{}; typename ControlSystem::control_error control_error{}; }; diff --git a/src/ControlSystem/Tags/SystemTags.cpp b/src/ControlSystem/Tags/SystemTags.cpp index 6140d224daf1..2c2b409f0418 100644 --- a/src/ControlSystem/Tags/SystemTags.cpp +++ b/src/ControlSystem/Tags/SystemTags.cpp @@ -7,9 +7,9 @@ #include "Utilities/GenerateInstantiations.hpp" namespace control_system::Tags::detail { -template +template void initialize_tuner( - const gsl::not_null<::TimescaleTuner*> tuner, + const gsl::not_null<::TimescaleTuner*> tuner, const std::unique_ptr<::DomainCreator>& domain_creator, const double initial_time, const std::string& name) { // We get the functions of time in order to get the number of components @@ -51,17 +51,19 @@ void initialize_tuner( } } -#define DIM(data) BOOST_PP_TUPLE_ELEM(0, data) +#define ALLOWDECREASE(data) BOOST_PP_TUPLE_ELEM(0, data) +#define DIM(data) BOOST_PP_TUPLE_ELEM(1, data) #define INSTANTIATE(_, data) \ template void initialize_tuner( \ - const gsl::not_null<::TimescaleTuner*> tuner, \ + const gsl::not_null<::TimescaleTuner*> tuner, \ const std::unique_ptr<::DomainCreator>& domain_creator, \ const double initial_time, const std::string& name); -GENERATE_INSTANTIATIONS(INSTANTIATE, (1, 2, 3)) +GENERATE_INSTANTIATIONS(INSTANTIATE, (true, false), (1, 2, 3)) #undef INSTANTIATE +#undef ALLOWDECREASE #undef DIM } // namespace control_system::Tags::detail diff --git a/src/ControlSystem/Tags/SystemTags.hpp b/src/ControlSystem/Tags/SystemTags.hpp index d83cc7b4a652..b0cd47f66fa8 100644 --- a/src/ControlSystem/Tags/SystemTags.hpp +++ b/src/ControlSystem/Tags/SystemTags.hpp @@ -14,6 +14,7 @@ #include "ControlSystem/Averager.hpp" #include "ControlSystem/CombinedName.hpp" #include "ControlSystem/Controller.hpp" +#include "ControlSystem/IsSize.hpp" #include "ControlSystem/Metafunctions.hpp" #include "ControlSystem/Protocols/ControlSystem.hpp" #include "ControlSystem/Tags/OptionTags.hpp" @@ -95,9 +96,9 @@ struct Averager : db::SimpleTag { }; namespace detail { -template +template void initialize_tuner( - const gsl::not_null<::TimescaleTuner*> tuner, + gsl::not_null<::TimescaleTuner*> tuner, const std::unique_ptr<::DomainCreator>& domain_creator, const double initial_time, const std::string& name); } // namespace detail @@ -107,7 +108,12 @@ void initialize_tuner( /// DataBox tag for the timescale tuner template struct TimescaleTuner : db::SimpleTag { - using type = ::TimescaleTuner; + private: + static constexpr bool is_size = + control_system::size::is_size_v; + + public: + using type = ::TimescaleTuner; template using option_tags = @@ -150,7 +156,7 @@ struct Controller : db::SimpleTag { domain_creator, const double initial_time) { type controller = option_holder.controller; - ::TimescaleTuner tuner = option_holder.tuner; + auto tuner = option_holder.tuner; detail::initialize_tuner(make_not_null(&tuner), domain_creator, initial_time, ControlSystem::name()); diff --git a/src/ControlSystem/TimescaleTuner.cpp b/src/ControlSystem/TimescaleTuner.cpp index 70fa9ed1c0f3..acb243bea5d3 100644 --- a/src/ControlSystem/TimescaleTuner.cpp +++ b/src/ControlSystem/TimescaleTuner.cpp @@ -14,6 +14,7 @@ #include "Utilities/ConstantExpressions.hpp" #include "Utilities/ErrorHandling/Assert.hpp" #include "Utilities/ErrorHandling/Error.hpp" +#include "Utilities/GenerateInstantiations.hpp" #include "Utilities/Gsl.hpp" namespace { @@ -33,12 +34,12 @@ struct TimescaleCreator { }; } // namespace -TimescaleTuner::TimescaleTuner( +template +TimescaleTuner::TimescaleTuner( const typename InitialTimescales::type& initial_timescale, const double max_timescale, const double min_timescale, - const double decrease_timescale_threshold, const double increase_timescale_threshold, const double increase_factor, - const double decrease_factor) + const double decrease_timescale_threshold, const double decrease_factor) : max_timescale_{max_timescale}, min_timescale_{min_timescale}, decrease_timescale_threshold_{decrease_timescale_threshold}, @@ -61,6 +62,12 @@ TimescaleTuner::TimescaleTuner( } } + if (not AllowDecrease and decrease_factor_ != 1.0) { + ERROR( + "If 'AllowDecrease' is false, then the specified decrease_factor must " + "be 1.0"); + } + if (decrease_factor_ > 1.0 or decrease_factor <= 0.0) { ERROR("The specified decrease_factor " << decrease_factor_ << " must satisfy 0 < decrease_factor <= 1"); @@ -91,12 +98,14 @@ TimescaleTuner::TimescaleTuner( } } -const DataVector& TimescaleTuner::current_timescale() const { +template +const DataVector& TimescaleTuner::current_timescale() const { check_if_timescales_have_been_set(); return timescale_; } -void TimescaleTuner::resize_timescales( +template +void TimescaleTuner::resize_timescales( const size_t num_timescales, const std::optional& fill_value) { ASSERT(num_timescales > 0, "Damping timescales must have a non-zero number of components."); @@ -105,7 +114,8 @@ void TimescaleTuner::resize_timescales( set_timescale_if_in_allowable_range(fill_value.value_or(initial_timescale_)); } -void TimescaleTuner::set_timescale_if_in_allowable_range( +template +void TimescaleTuner::set_timescale_if_in_allowable_range( const double suggested_timescale) { for (auto& t_scale : timescale_) { t_scale = std::clamp(suggested_timescale, min_timescale_, max_timescale_); @@ -114,7 +124,8 @@ void TimescaleTuner::set_timescale_if_in_allowable_range( timescales_have_been_set_ = true; } -void TimescaleTuner::update_timescale( +template +void TimescaleTuner::update_timescale( const std::array& q_and_dtq) { check_if_timescales_have_been_set(); ASSERT(q_and_dtq[0].size() == timescale_.size() and @@ -129,7 +140,8 @@ void TimescaleTuner::update_timescale( for (size_t i = 0; i < q.size(); i++) { // check whether we need to decrease the timescale: - if ((fabs(q[i]) > decrease_timescale_threshold_ or + if (AllowDecrease and + (fabs(q[i]) > decrease_timescale_threshold_ or fabs(dtq[i] * timescale_[i]) > decrease_timescale_threshold_) and (dtq[i] * q[i] > 0.0 or fabs(dtq[i]) * timescale_[i] < 0.5 * fabs(q[i]))) { @@ -153,12 +165,14 @@ void TimescaleTuner::update_timescale( } } -void TimescaleTuner::check_if_timescales_have_been_set() const { +template +void TimescaleTuner::check_if_timescales_have_been_set() const { ASSERT(timescales_have_been_set_, "Damping timescales in the TimescaleTuner have not been set yet."); } -void TimescaleTuner::pup(PUP::er& p) { +template +void TimescaleTuner::pup(PUP::er& p) { p | timescale_; p | timescales_have_been_set_; p | initial_timescale_; @@ -170,7 +184,9 @@ void TimescaleTuner::pup(PUP::er& p) { p | decrease_factor_; } -bool operator==(const TimescaleTuner& lhs, const TimescaleTuner& rhs) { +template +bool operator==(const TimescaleTuner& lhs, + const TimescaleTuner& rhs) { return (lhs.timescale_ == rhs.timescale_) and (lhs.max_timescale_ == rhs.max_timescale_) and (lhs.min_timescale_ == rhs.min_timescale_) and @@ -184,6 +200,22 @@ bool operator==(const TimescaleTuner& lhs, const TimescaleTuner& rhs) { (lhs.decrease_factor_ == rhs.decrease_factor_); } -bool operator!=(const TimescaleTuner& lhs, const TimescaleTuner& rhs) { +template +bool operator!=(const TimescaleTuner& lhs, + const TimescaleTuner& rhs) { return not(lhs == rhs); } + +#define ALLOWDECREASE(data) BOOST_PP_TUPLE_ELEM(0, data) + +#define INSTANTIATE(_, data) \ + template class TimescaleTuner; \ + template bool operator==(const TimescaleTuner& lhs, \ + const TimescaleTuner& rhs); \ + template bool operator!=(const TimescaleTuner& lhs, \ + const TimescaleTuner& rhs); + +GENERATE_INSTANTIATIONS(INSTANTIATE, (true, false)) + +#undef INSTANTIATE +#undef ALLOWDECREASE diff --git a/src/ControlSystem/TimescaleTuner.hpp b/src/ControlSystem/TimescaleTuner.hpp index 1d58056abccf..bd746bc064bc 100644 --- a/src/ControlSystem/TimescaleTuner.hpp +++ b/src/ControlSystem/TimescaleTuner.hpp @@ -46,8 +46,12 @@ class er; * AND \n * - the expected change in \f$Q\f$ is less than the threshold: * \f$|\dot{Q}|\tau < \f$ `increase_timescale_threshold` + * + * If the template bool \p AllowDecrease is false, then the check for decreasing + * the timescale will be ignored. This can be used if something else will be + * controlling the decrease of the timescale. */ - +template class TimescaleTuner { public: static constexpr Options::String help{ @@ -91,15 +95,19 @@ class TimescaleTuner { static constexpr Options::String help = {"Factor to decrease timescale"}; }; - using options = tmpl::list; + using options = tmpl::append< + tmpl::list, + tmpl::conditional_t, + tmpl::list<>>>; - TimescaleTuner(const typename InitialTimescales::type& initial_timescale, - double max_timescale, double min_timescale, - double decrease_timescale_threshold, - double increase_timescale_threshold, double increase_factor, - double decrease_factor); + TimescaleTuner( + const typename InitialTimescales::type& initial_timescale, + double max_timescale, double min_timescale, + double increase_timescale_threshold, double increase_factor, + double decrease_timescale_threshold = std::numeric_limits::max(), + double decrease_factor = 1.0); TimescaleTuner() = default; TimescaleTuner(TimescaleTuner&&) = default; @@ -134,7 +142,9 @@ class TimescaleTuner { void pup(PUP::er& p); - friend bool operator==(const TimescaleTuner& lhs, const TimescaleTuner& rhs); + template + friend bool operator==(const TimescaleTuner& lhs, + const TimescaleTuner& rhs); private: void check_if_timescales_have_been_set() const; @@ -150,4 +160,6 @@ class TimescaleTuner { double decrease_factor_; }; -bool operator!=(const TimescaleTuner& lhs, const TimescaleTuner& rhs); +template +bool operator!=(const TimescaleTuner& lhs, + const TimescaleTuner& rhs); diff --git a/support/Pipelines/Bbh/Inspiral.yaml b/support/Pipelines/Bbh/Inspiral.yaml index 79bdf944d422..7418f8d53f54 100644 --- a/support/Pipelines/Bbh/Inspiral.yaml +++ b/support/Pipelines/Bbh/Inspiral.yaml @@ -358,9 +358,7 @@ ControlSystems: MinTimescale: 1.0e-4 MaxTimescale: 20.0 IncreaseThreshold: 2.5e-4 - DecreaseThreshold: 1.0e-3 IncreaseFactor: 1.01 - DecreaseFactor: 1.0 ControlError: MaxNumTimesForZeroCrossingPredictor: 4 SmoothAvgTimescaleFraction: 0.25 diff --git a/support/Pipelines/Bbh/Ringdown.yaml b/support/Pipelines/Bbh/Ringdown.yaml index 91d736a93c41..bb322d291cbb 100644 --- a/support/Pipelines/Bbh/Ringdown.yaml +++ b/support/Pipelines/Bbh/Ringdown.yaml @@ -220,9 +220,7 @@ ControlSystems: MinTimescale: 1.0e-4 MaxTimescale: 20.0 IncreaseThreshold: 2.5e-4 - DecreaseThreshold: 1.0e-3 IncreaseFactor: 1.01 - DecreaseFactor: 1.0 ControlError: MaxNumTimesForZeroCrossingPredictor: 4 SmoothAvgTimescaleFraction: 0.25 diff --git a/tests/InputFiles/GeneralizedHarmonic/BinaryBlackHole.yaml b/tests/InputFiles/GeneralizedHarmonic/BinaryBlackHole.yaml index 89a6ff749b73..ba25e030919a 100644 --- a/tests/InputFiles/GeneralizedHarmonic/BinaryBlackHole.yaml +++ b/tests/InputFiles/GeneralizedHarmonic/BinaryBlackHole.yaml @@ -363,9 +363,7 @@ ControlSystems: MinTimescale: 1.0e-4 MaxTimescale: 20.0 IncreaseThreshold: 2.5e-4 - DecreaseThreshold: 1.0e-3 IncreaseFactor: 1.01 - DecreaseFactor: 1.0 ControlError: MaxNumTimesForZeroCrossingPredictor: 4 SmoothAvgTimescaleFraction: 0.25 diff --git a/tests/InputFiles/GeneralizedHarmonic/CylindricalBinaryBlackHole.yaml b/tests/InputFiles/GeneralizedHarmonic/CylindricalBinaryBlackHole.yaml index 063dbb92cd9c..2321e0205280 100644 --- a/tests/InputFiles/GeneralizedHarmonic/CylindricalBinaryBlackHole.yaml +++ b/tests/InputFiles/GeneralizedHarmonic/CylindricalBinaryBlackHole.yaml @@ -344,9 +344,7 @@ ControlSystems: MinTimescale: 1.0e-4 MaxTimescale: 20.0 IncreaseThreshold: 2.5e-4 - DecreaseThreshold: 1.0e-3 IncreaseFactor: 1.01 - DecreaseFactor: 1.0 ControlError: MaxNumTimesForZeroCrossingPredictor: 4 SmoothAvgTimescaleFraction: 0.25 diff --git a/tests/InputFiles/GeneralizedHarmonic/KerrSchild.yaml b/tests/InputFiles/GeneralizedHarmonic/KerrSchild.yaml index 23d7da79ba2d..3186574c1e86 100644 --- a/tests/InputFiles/GeneralizedHarmonic/KerrSchild.yaml +++ b/tests/InputFiles/GeneralizedHarmonic/KerrSchild.yaml @@ -248,9 +248,7 @@ ControlSystems: MinTimescale: 1.0e-4 MaxTimescale: 20.0 IncreaseThreshold: 2.5e-4 - DecreaseThreshold: 1.0e-3 IncreaseFactor: 1.01 - DecreaseFactor: 1.0 ControlError: MaxNumTimesForZeroCrossingPredictor: 4 SmoothAvgTimescaleFraction: 0.25 diff --git a/tests/Unit/ControlSystem/Actions/Test_Initialization.cpp b/tests/Unit/ControlSystem/Actions/Test_Initialization.cpp index d93eb9f038a0..a5f12486bd56 100644 --- a/tests/Unit/ControlSystem/Actions/Test_Initialization.cpp +++ b/tests/Unit/ControlSystem/Actions/Test_Initialization.cpp @@ -98,8 +98,8 @@ SPECTRE_TEST_CASE("Unit.ControlSystem.Initialization", int current_measurement{}; const double damping_time = 1.0; - TimescaleTuner tuner{ - std::vector{damping_time}, 10.0, 0.1, 2.0, 0.1, 1.01, 0.99}; + TimescaleTuner tuner{ + std::vector{damping_time}, 10.0, 0.1, 0.1, 1.01, 2.0, 0.99}; Controller controller{0.3}; std::unordered_map{}, cache, check_time, + expansion_name, fake_measurement_tuple); const auto& expansion_f_of_t = dynamic_cast&>( diff --git a/tests/Unit/ControlSystem/ControlErrors/Test_Rotation.cpp b/tests/Unit/ControlSystem/ControlErrors/Test_Rotation.cpp index cace93e4df46..115f4e2785b0 100644 --- a/tests/Unit/ControlSystem/ControlErrors/Test_Rotation.cpp +++ b/tests/Unit/ControlSystem/ControlErrors/Test_Rotation.cpp @@ -114,7 +114,7 @@ void test_rotation_control_error() { // This is before the first expiration time const double check_time = 0.1; const DataVector control_error = - ControlError{}(::TimescaleTuner{}, cache, check_time, rotation_name, + ControlError{}(::TimescaleTuner{}, cache, check_time, rotation_name, fake_measurement_tuple); // Calculated error = (grid_diff cross pos_diff) / (grid_diff dot pos_diff) by diff --git a/tests/Unit/ControlSystem/ControlErrors/Test_Shape.cpp b/tests/Unit/ControlSystem/ControlErrors/Test_Shape.cpp index ef3067ee3220..0b758fcff443 100644 --- a/tests/Unit/ControlSystem/ControlErrors/Test_Shape.cpp +++ b/tests/Unit/ControlSystem/ControlErrors/Test_Shape.cpp @@ -176,7 +176,7 @@ void test_shape_control_error() { QueueTuple fake_measurement_tuple{fake_ah}; const DataVector control_error = - ControlError{}(::TimescaleTuner{}, cache, check_time, shape_name, + ControlError{}(::TimescaleTuner{}, cache, check_time, shape_name, fake_measurement_tuple); const auto lambda_00_coef = diff --git a/tests/Unit/ControlSystem/ControlErrors/Test_SizeError.cpp b/tests/Unit/ControlSystem/ControlErrors/Test_SizeError.cpp index b5d46302380f..300c8e455376 100644 --- a/tests/Unit/ControlSystem/ControlErrors/Test_SizeError.cpp +++ b/tests/Unit/ControlSystem/ControlErrors/Test_SizeError.cpp @@ -216,8 +216,8 @@ void test_size_error_one_step( CHECK_FALSE(error_class.get_suggested_timescale().has_value()); CHECK_FALSE(error_class.discontinuous_change_has_occurred()); - TimescaleTuner tuner{ - std::vector{0.1}, 1.0, 0.01, 1.0e-3, 1.0e-4, 1.01, 0.98}; + TimescaleTuner tuner{std::vector{0.1}, 1.0, 0.01, 1.0e-4, + 1.01}; std::unordered_map> functions_of_time{}; diff --git a/tests/Unit/ControlSystem/ControlErrors/Test_Translation.cpp b/tests/Unit/ControlSystem/ControlErrors/Test_Translation.cpp index 00e04721a357..4063d8a6d687 100644 --- a/tests/Unit/ControlSystem/ControlErrors/Test_Translation.cpp +++ b/tests/Unit/ControlSystem/ControlErrors/Test_Translation.cpp @@ -117,8 +117,8 @@ void test_translation_control_error() { // This is before the first expiration time const double check_time = 0.1; const DataVector control_error = - ControlError{}(::TimescaleTuner{}, cache, check_time, translation_name, - fake_measurement_tuple); + ControlError{}(::TimescaleTuner{}, cache, check_time, + translation_name, fake_measurement_tuple); // Calculated errors from other basic control systems const DataVector rotation_control_error = diff --git a/tests/Unit/ControlSystem/Tags/Test_FunctionsOfTimeInitialize.cpp b/tests/Unit/ControlSystem/Tags/Test_FunctionsOfTimeInitialize.cpp index ab96e24ebe20..dd3b2a491be6 100644 --- a/tests/Unit/ControlSystem/Tags/Test_FunctionsOfTimeInitialize.cpp +++ b/tests/Unit/ControlSystem/Tags/Test_FunctionsOfTimeInitialize.cpp @@ -207,10 +207,10 @@ void test_functions_of_time_tag() { // time between the two expiration times used above in the TestCreator const double timescale = 27.0; const double timescale2 = 0.1; - const TimescaleTuner tuner1(std::vector{timescale}, 10.0, 1.0e-3, - 1.0e-2, 1.0e-4, 1.01, 0.99); - const TimescaleTuner tuner2(timescale2, 10.0, 1.0e-3, 1.0e-2, 1.0e-4, 1.01, - 0.99); + const TimescaleTuner tuner1(std::vector{timescale}, 10.0, + 1.0e-3, 1.0e-4, 1.01, 1.0e-2, 0.99); + const TimescaleTuner tuner2(timescale2, 10.0, 1.0e-3, 1.0e-4, 1.01, + 1.0e-2, 0.99); const Averager<1> averager(0.25, true); const double update_fraction = 0.3; const Controller<2> controller(update_fraction); @@ -280,8 +280,8 @@ using Creator = std::unique_ptr<::DomainCreator<1>>; void not_controlling(const bool is_active) { const Creator creator = std::make_unique(true); - const TimescaleTuner tuner(std::vector{1.0}, 10.0, 1.0e-3, 1.0e-2, - 1.0e-4, 1.01, 0.99); + const TimescaleTuner tuner(std::vector{1.0}, 10.0, 1.0e-3, + 1.0e-4, 1.01, 1.0e-2, 0.99); const Averager<1> averager(0.25, true); const double update_fraction = 0.3; const Controller<2> controller(update_fraction); @@ -305,8 +305,8 @@ void not_controlling(const bool is_active) { void incompatible(const bool is_active) { const Creator creator = std::make_unique(); - const TimescaleTuner tuner(std::vector{1.0}, 10.0, 1.0e-3, 1.0e-2, - 1.0e-4, 1.01, 0.99); + const TimescaleTuner tuner(std::vector{1.0}, 10.0, 1.0e-3, + 1.0e-4, 1.01, 1.0e-2, 0.99); const Averager<1> averager(0.25, true); const double update_fraction = 0.3; const Controller<2> controller(update_fraction); diff --git a/tests/Unit/ControlSystem/Tags/Test_MeasurementTimescales.cpp b/tests/Unit/ControlSystem/Tags/Test_MeasurementTimescales.cpp index 4c20891c19ac..20ba5427e28d 100644 --- a/tests/Unit/ControlSystem/Tags/Test_MeasurementTimescales.cpp +++ b/tests/Unit/ControlSystem/Tags/Test_MeasurementTimescales.cpp @@ -71,8 +71,8 @@ template void test_calculate_measurement_timescales() { INFO("Test calculate measurement timescales"); const double timescale = 20.0; - const TimescaleTuner tuner(std::vector{timescale}, 10.0, 1.0e-3, - 1.0e-2, 1.0e-4, 1.01, 0.99); + const TimescaleTuner tuner(std::vector{timescale}, 10.0, 1.0e-3, + 1.0e-4, 1.01, 1.0e-2, 0.99); const double update_fraction = 0.25; const Controller controller(update_fraction); @@ -108,16 +108,16 @@ void test_measurement_tag() { const control_system::TestHelpers::ControlError<1> control_error{}; const double timescale_long = 27.0; - const TimescaleTuner tuner1( + const TimescaleTuner tuner1( std::vector{timescale_long, timescale_long * 2.0}, 10.0, 1.0e-3, - 1.0e-2, 1.0e-4, 1.01, 0.99); + 1.0e-4, 1.01, 1.0e-2, 0.99); const double timescale_short = 0.5; - TimescaleTuner tuner2(timescale_short, 10.0, 1.0e-3, 1.0e-2, 1.0e-4, 1.01, - 0.99); + TimescaleTuner tuner2(timescale_short, 10.0, 1.0e-3, 1.0e-4, 1.01, + 1.0e-2, 0.99); tuner2.resize_timescales(2); - const TimescaleTuner tuner4 = tuner2; - const TimescaleTuner& tuner5 = tuner1; - const TimescaleTuner& tuner6 = tuner1; + const TimescaleTuner tuner4 = tuner2; + const TimescaleTuner& tuner5 = tuner1; + const TimescaleTuner& tuner6 = tuner1; OptionHolder<1> option_holder1(true, averager, controller, tuner1, control_error); @@ -201,10 +201,10 @@ void test_measurement_tag() { CHECK_THROWS_WITH( ([]() { - const TimescaleTuner tuner1(std::vector{27.0}, 10.0, 1.0e-3, - 1.0e-2, 1.0e-4, 1.01, 0.99); - const TimescaleTuner tuner2(std::vector{0.1}, 10.0, 1.0e-3, - 1.0e-2, 1.0e-4, 1.01, 0.99); + const TimescaleTuner tuner1(std::vector{27.0}, 10.0, + 1.0e-3, 1.0e-4, 1.01, 1.0e-2, 0.99); + const TimescaleTuner tuner2(std::vector{0.1}, 10.0, + 1.0e-3, 1.0e-4, 1.01, 1.0e-2, 0.99); const Averager<1> averager(0.25, true); const Controller<2> controller(0.3); const control_system::TestHelpers::ControlError<1> control_error{}; diff --git a/tests/Unit/ControlSystem/Test_Controller.cpp b/tests/Unit/ControlSystem/Test_Controller.cpp index f87baa5fe1aa..ea4b4341ef69 100644 --- a/tests/Unit/ControlSystem/Test_Controller.cpp +++ b/tests/Unit/ControlSystem/Test_Controller.cpp @@ -29,10 +29,10 @@ void test_controller() { const double min_timescale = 1.0e-3; const double initial_timescale = 1.0e-2; - TimescaleTuner tst(std::vector{initial_timescale}, max_timescale, - min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst(std::vector{initial_timescale}, + max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); // test following a sinusoidal target function double t = 0.1; @@ -101,10 +101,10 @@ void test_timeoffsets() { const double min_timescale = 1.0e-3; const double initial_timescale = 1.0e-2; - TimescaleTuner tst(std::vector{initial_timescale}, max_timescale, - min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst(std::vector{initial_timescale}, + max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); // test following a sinusoidal target function double t = 0.1; @@ -193,10 +193,10 @@ void test_timeoffsets_noaverageq() { const double min_timescale = 1.0e-3; const double initial_timescale = 1.0e-2; - TimescaleTuner tst(std::vector{initial_timescale}, max_timescale, - min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst(std::vector{initial_timescale}, + max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); // test following a sinusoidal target function double t = 0.1; diff --git a/tests/Unit/ControlSystem/Test_ExpirationTimes.cpp b/tests/Unit/ControlSystem/Test_ExpirationTimes.cpp index 4987b716bcb5..80e7b6557ff2 100644 --- a/tests/Unit/ControlSystem/Test_ExpirationTimes.cpp +++ b/tests/Unit/ControlSystem/Test_ExpirationTimes.cpp @@ -65,9 +65,9 @@ void test_expiration_time_construction() { constexpr int measurements_per_update = 4; const double timescale = 2.0; - const TimescaleTuner tuner1(std::vector{timescale}, 10.0, 1.0e-3, - 1.0e-2, 1.0e-4, 1.01, 0.99); - TimescaleTuner tuner2(0.1, 10.0, 1.0e-3, 1.0e-2, 1.0e-4, 1.01, 0.99); + const TimescaleTuner tuner1(std::vector{timescale}, 10.0, + 1.0e-3, 1.0e-4, 1.01, 1.0e-2, 0.99); + TimescaleTuner tuner2(0.1, 10.0, 1.0e-3, 1.0e-4, 1.01, 1.0e-2, 0.99); tuner2.resize_timescales(2); const Averager<1> averager(0.25, true); const double update_fraction = 0.3; diff --git a/tests/Unit/ControlSystem/Test_Tags.cpp b/tests/Unit/ControlSystem/Test_Tags.cpp index 880986313490..f7ce1b6e43c6 100644 --- a/tests/Unit/ControlSystem/Test_Tags.cpp +++ b/tests/Unit/ControlSystem/Test_Tags.cpp @@ -94,10 +94,10 @@ void test_control_sys_inputs() { const double decrease_factor = 0.99; const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - const TimescaleTuner expected_tuner( + const TimescaleTuner expected_tuner( std::vector{1.}, max_timescale, min_timescale, - decrease_timescale_threshold, increase_timescale_threshold, - increase_factor, decrease_factor); + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); const Averager<1> expected_averager(0.25, true); const Controller<2> expected_controller(0.3); const std::string expected_name{"LabelA"}; @@ -143,13 +143,13 @@ void test_individual_tags() { const double decrease_factor = 0.99; const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - return TimescaleTuner{std::vector(num_components, 1.0), - max_timescale, - min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, - decrease_factor}; + return TimescaleTuner{std::vector(num_components, 1.0), + max_timescale, + min_timescale, + increase_timescale_threshold, + increase_factor, + decrease_timescale_threshold, + decrease_factor}; }; const auto tuner_str = [](const bool is_active) -> std::string { @@ -195,12 +195,12 @@ void test_individual_tags() { std::make_unique(std::unordered_map{}, 1); - const TimescaleTuner created_tuner = + const TimescaleTuner created_tuner = tuner_tag::create_from_options(holder, creator, 0.0); - const TimescaleTuner quat_created_tuner = + const TimescaleTuner quat_created_tuner = quat_tuner_tag::create_from_options(quat_holder, creator, 0.0); - const TimescaleTuner inactive_created_tuner = + const TimescaleTuner inactive_created_tuner = tuner_tag::create_from_options(inactive_holder, creator_empty, 0.0); diff --git a/tests/Unit/ControlSystem/Test_TimescaleTuner.cpp b/tests/Unit/ControlSystem/Test_TimescaleTuner.cpp index 9a2f87593e2e..f5517357b979 100644 --- a/tests/Unit/ControlSystem/Test_TimescaleTuner.cpp +++ b/tests/Unit/ControlSystem/Test_TimescaleTuner.cpp @@ -12,19 +12,22 @@ #include "Framework/TestHelpers.hpp" #include "Utilities/ErrorHandling/Error.hpp" #include "Utilities/MakeWithValue.hpp" +#include "Utilities/TMPL.hpp" namespace { +template void test_increase_or_decrease() { - const double decrease_timescale_threshold = 1.0e-2; + const double decrease_timescale_threshold = + AllowDecrease ? 1.0e-2 : std::numeric_limits::max(); const double increase_timescale_threshold = 1.0e-4; const double increase_factor = 1.01; - const double decrease_factor = 0.99; + const double decrease_factor = AllowDecrease ? 0.99 : 1.0; const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - TimescaleTuner tst(1.0, max_timescale, min_timescale, - decrease_timescale_threshold, increase_timescale_threshold, - increase_factor, decrease_factor); + TimescaleTuner tst( + 1.0, max_timescale, min_timescale, increase_timescale_threshold, + increase_factor, decrease_timescale_threshold, decrease_factor); const DataVector timescale{1.0}; @@ -66,103 +69,112 @@ void test_increase_or_decrease() { // in timescale are numbered, while the nested conditional choices for each // associated outer case are suffixed with letters - // (1) |Q| > decrease_timescale_threshold - // |\dot{Q}| <= decrease_timescale_threshold/timescale - DataVector q{sign_of_q * greater_than_one * decrease_timescale_threshold}; - DataVector qdot{sign_of_q * less_than_one * decrease_timescale_threshold / - tscale}; - - // (1a) Q\dot{Q} > 0 - // |\dot{Q}| >= 0.5*|Q|/timescale - // the error is large and growing: decrease timescale - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (1b) Q\dot{Q} <= 0 - // |\dot{Q}| < 0.5*|Q|/timescale - // the error is not decreasing quickly enough: decrease timescale - qdot = -less_than_one * 0.5 * q / tscale; - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (1c) Q\dot{Q} > 0 - // |\dot{Q}| < 0.5*|Q|/timescale - // the error is large and growing quickly: decrease timescale - qdot *= -1.0; - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (2) |Q| <= decrease_timescale_threshold - // |\dot{Q}| > decrease_timescale_threshold/timescale - q = sign_of_q * less_than_one * decrease_timescale_threshold; - qdot = sign_of_q * greater_than_one * decrease_timescale_threshold / tscale; - - // (2a) Q\dot{Q} > 0 - // |\dot{Q}| >= 0.5*|Q|/timescale - // the error is growing quickly: decrease timescale - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (2b) Q\dot{Q} <= 0 - // |\dot{Q}| < 0.5*|Q|/timescale - // NOTE: the second piece is unachievable, given the conditions of (2). - // This check is included in the do nothing test. - - // (2c) Q\dot{Q} > 0 - // |\dot{Q}| < 0.5*|Q|/timescale - // NOTE: the second piece is unachievable, given the conditions of (2), - // however, Q\dot{Q} > 0 is sufficient to trigger a decrease. - // the error is growing quickly: decrease timescale - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (3) |Q| > decrease_timescale_threshold - // |\dot{Q}| > decrease_timescale_threshold/timescale - q = sign_of_q * greater_than_one * decrease_timescale_threshold; - qdot = sign_of_q * greater_than_one * decrease_timescale_threshold / tscale; - - // (3a) Q\dot{Q} > 0 - // |\dot{Q}| >= 0.5*|Q|/timescale - // the error is large and growing quickly: decrease timescale - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (3b) Q\dot{Q} <= 0 - // |\dot{Q}| < 0.5*|Q|/timescale - // the error is large and not decreasing quickly enough: decrease timescale - qdot *= -1.0; - q = sign_of_q * greater_than_one * 2.0 * greater_than_one * - decrease_timescale_threshold; - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); - - // (3c) Q\dot{Q} > 0 - // |\dot{Q}| < 0.5*|Q|/timescale - // the error is large and growing quickly: decrease timescale - qdot *= -1.0; - tscale *= decrease_factor; - tst.update_timescale({{q, qdot}}); - CHECK(tst.current_timescale() == - make_with_value(timescale, tscale)); + DataVector q{1, 0.0}; + DataVector qdot{1, 0.0}; + + if constexpr (AllowDecrease) { + // (1) |Q| > decrease_timescale_threshold + // |\dot{Q}| <= decrease_timescale_threshold/timescale + q = sign_of_q * greater_than_one * decrease_timescale_threshold; + qdot = sign_of_q * less_than_one * decrease_timescale_threshold / tscale; + + // (1a) Q\dot{Q} > 0 + // |\dot{Q}| >= 0.5*|Q|/timescale + // the error is large and growing: decrease timescale + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (1b) Q\dot{Q} <= 0 + // |\dot{Q}| < 0.5*|Q|/timescale + // the error is not decreasing quickly enough: decrease timescale + qdot = -less_than_one * 0.5 * q / tscale; + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (1c) Q\dot{Q} > 0 + // |\dot{Q}| < 0.5*|Q|/timescale + // the error is large and growing quickly: decrease timescale + qdot *= -1.0; + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (2) |Q| <= decrease_timescale_threshold + // |\dot{Q}| > decrease_timescale_threshold/timescale + q = sign_of_q * less_than_one * decrease_timescale_threshold; + qdot = + sign_of_q * greater_than_one * decrease_timescale_threshold / tscale; + + // (2a) Q\dot{Q} > 0 + // |\dot{Q}| >= 0.5*|Q|/timescale + // the error is growing quickly: decrease timescale + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (2b) Q\dot{Q} <= 0 + // |\dot{Q}| < 0.5*|Q|/timescale + // NOTE: the second piece is unachievable, given the conditions of (2). + // This check is included in the do nothing test. + + // (2c) Q\dot{Q} > 0 + // |\dot{Q}| < 0.5*|Q|/timescale + // NOTE: the second piece is unachievable, given the conditions of (2), + // however, Q\dot{Q} > 0 is sufficient to trigger a decrease. + // the error is growing quickly: decrease timescale + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (3) |Q| > decrease_timescale_threshold + // |\dot{Q}| > decrease_timescale_threshold/timescale + q = sign_of_q * greater_than_one * decrease_timescale_threshold; + qdot = + sign_of_q * greater_than_one * decrease_timescale_threshold / tscale; + + // (3a) Q\dot{Q} > 0 + // |\dot{Q}| >= 0.5*|Q|/timescale + // the error is large and growing quickly: decrease timescale + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (3b) Q\dot{Q} <= 0 + // |\dot{Q}| < 0.5*|Q|/timescale + // the error is large and not decreasing quickly enough: decrease + // timescale + qdot *= -1.0; + q = sign_of_q * greater_than_one * 2.0 * greater_than_one * + decrease_timescale_threshold; + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + + // (3c) Q\dot{Q} > 0 + // |\dot{Q}| < 0.5*|Q|/timescale + // the error is large and growing quickly: decrease timescale + qdot *= -1.0; + tscale *= decrease_factor; + tst.update_timescale({{q, qdot}}); + CHECK(tst.current_timescale() == + make_with_value(timescale, tscale)); + } // There is only one case which triggers an increase in the timescale // (4) |Q| < increase_timescale_threshold // |\dot{Q}| < increase_timescale_threshold/timescale // the error and time derivative are sufficiently small: increase timescale + tscale *= 0.5; + tst.set_timescale_if_in_allowable_range(tscale); q = sign_of_q * less_than_one * increase_timescale_threshold; qdot = sign_of_q * less_than_one * increase_timescale_threshold / tscale; tscale *= increase_factor; @@ -175,17 +187,20 @@ void test_increase_or_decrease() { run_tests(-1.0); } +template void test_no_change_to_timescale() { - const double decrease_timescale_threshold = 1.0e-2; + const double decrease_timescale_threshold = + AllowDecrease ? 1.0e-2 : std::numeric_limits::max(); const double increase_timescale_threshold = 1.0e-4; const double increase_factor = 1.01; - const double decrease_factor = 0.99; + const double decrease_factor = AllowDecrease ? 0.99 : 1.0; const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - TimescaleTuner tst(std::vector{1.0}, max_timescale, min_timescale, - decrease_timescale_threshold, increase_timescale_threshold, - increase_factor, decrease_factor); + TimescaleTuner tst( + std::vector{1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); const DataVector timescale{1.0}; CHECK(tst.current_timescale() == timescale); @@ -284,63 +299,66 @@ void test_no_change_to_timescale() { run_tests(-1.0); // test negative Q } +template void test_create_from_options() { - const double decrease_timescale_threshold = 1.0e-2; + const double decrease_timescale_threshold = + AllowDecrease ? 1.0e-2 : std::numeric_limits::max(); const double increase_timescale_threshold = 1.0e-4; const double increase_factor = 1.01; - const double decrease_factor = 0.99; + const double decrease_factor = AllowDecrease ? 0.99 : 1.0; const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - const TimescaleTuner expected{std::vector{1.}, - max_timescale, - min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, - decrease_factor}; + const TimescaleTuner expected{ + std::vector{1.}, max_timescale, + min_timescale, increase_timescale_threshold, + increase_factor, decrease_timescale_threshold, + decrease_factor}; - const auto tst = TestHelpers::test_creation( + const auto tst = TestHelpers::test_creation>( "InitialTimescales: [1.]\n" "MinTimescale: 1e-3\n" "MaxTimescale: 10.\n" - "DecreaseThreshold: 1e-2\n" "IncreaseThreshold: 1e-4\n" - "IncreaseFactor: 1.01\n" - "DecreaseFactor: 0.99\n"); + "IncreaseFactor: 1.01\n" + + (AllowDecrease ? "DecreaseThreshold: 1e-2\n" + "DecreaseFactor: 0.99\n"s + : ""s)); CHECK(tst == expected); - TimescaleTuner tst2 = TestHelpers::test_creation( + auto tst2 = TestHelpers::test_creation>( "InitialTimescales: 1.\n" "MinTimescale: 1e-3\n" "MaxTimescale: 10.\n" - "DecreaseThreshold: 1e-2\n" "IncreaseThreshold: 1e-4\n" - "IncreaseFactor: 1.01\n" - "DecreaseFactor: 0.99\n"); + "IncreaseFactor: 1.01\n" + + (AllowDecrease ? "DecreaseThreshold: 1e-2\n" + "DecreaseFactor: 0.99\n"s + : ""s)); CHECK_FALSE(tst2 == expected); tst2.resize_timescales(1); CHECK(tst2 == expected); } +template void test_equality_and_serialization() { const double decrease_timescale_threshold = 1.0e-2; const double increase_timescale_threshold = 1.0e-4; const double increase_factor = 1.01; - const double decrease_factor = 0.99; + const double decrease_factor = AllowDecrease ? 0.99 : 1.0; const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - TimescaleTuner tst1(std::vector{0.3}, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst1( + std::vector{0.3}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); - TimescaleTuner tst2(std::vector{0.4}, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst2( + std::vector{0.4}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); CHECK(tst1 == tst1); CHECK(tst1 != tst2); @@ -348,23 +366,38 @@ void test_equality_and_serialization() { } void test_errors() { - CHECK_THROWS_WITH(([]() { - const double decrease_timescale_threshold = 1.0e-2; - const double increase_timescale_threshold = 1.0e-4; - const double increase_factor = 1.01; - const double decrease_factor = 0.99; - const double max_timescale = 10.0; - const double min_timescale = 1.0e-3; + CHECK_THROWS_WITH( + ([]() { + const double decrease_timescale_threshold = 1.0e-2; + const double increase_timescale_threshold = 1.0e-4; + const double increase_factor = 1.01; + const double decrease_factor = 0.99; + const double max_timescale = 10.0; + const double min_timescale = 1.0e-3; - const std::vector init_timescale{0.0}; - TimescaleTuner tst(init_timescale, max_timescale, - min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, decrease_factor); - }()), - Catch::Matchers::ContainsSubstring( - "Initial timescale must be > 0")); + const std::vector init_timescale{0.0}; + TimescaleTuner tst(init_timescale, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); + }()), + Catch::Matchers::ContainsSubstring("Initial timescale must be > 0")); + + CHECK_THROWS_WITH( + ([]() { + const double decrease_timescale_threshold = 1.0e-2; + const double increase_timescale_threshold = 1.0e-4; + const double increase_factor = 1.01; + const double decrease_factor = 0.99; + const double max_timescale = 10.0; + const double min_timescale = 1.0e-3; + + TimescaleTuner tst( + {0.1}, max_timescale, min_timescale, increase_timescale_threshold, + increase_factor, decrease_timescale_threshold, decrease_factor); + }()), + Catch::Matchers::ContainsSubstring("If 'AllowDecrease' is false, then " + "the specified decrease_factor must " + "be 1.0")); CHECK_THROWS_WITH(([]() { const double decrease_timescale_threshold = 1.0e-2; @@ -375,10 +408,10 @@ void test_errors() { const double increase_factor = 1.1; const double decrease_factor = -0.99; - TimescaleTuner tst({1.0}, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, decrease_factor); + TimescaleTuner tst( + {1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); }()), Catch::Matchers::ContainsSubstring( "must satisfy 0 < decrease_factor <= 1")); @@ -392,10 +425,10 @@ void test_errors() { const double increase_factor = 1.1; const double decrease_factor = 1.01; - TimescaleTuner tst({1.0}, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, decrease_factor); + TimescaleTuner tst( + {1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); }()), Catch::Matchers::ContainsSubstring( "must satisfy 0 < decrease_factor <= 1")); @@ -409,10 +442,10 @@ void test_errors() { const double increase_factor = 0.99; const double decrease_factor = 0.8; - TimescaleTuner tst({1.0}, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, decrease_factor); + TimescaleTuner tst( + {1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); }()), Catch::Matchers::ContainsSubstring("must be >= 1")); @@ -425,46 +458,46 @@ void test_errors() { const double max_timescale = 10.0; const double min_timescale = 0.0; - TimescaleTuner tst({1.0}, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, - increase_factor, decrease_factor); + TimescaleTuner tst( + {1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); }()), Catch::Matchers::ContainsSubstring("must be > 0")); - CHECK_THROWS_WITH( - ([]() { - const double decrease_timescale_threshold = 1.0e-2; - const double increase_timescale_threshold = 1.0e-4; - const double increase_factor = 1.01; - const double decrease_factor = 0.99; + CHECK_THROWS_WITH(([]() { + const double decrease_timescale_threshold = 1.0e-2; + const double increase_timescale_threshold = 1.0e-4; + const double increase_factor = 1.01; + const double decrease_factor = 0.99; - const double max_timescale = 1.0e-4; - const double min_timescale = 1.0e-3; + const double max_timescale = 1.0e-4; + const double min_timescale = 1.0e-3; - TimescaleTuner tst( - {1.0}, max_timescale, min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, decrease_factor); - }()), - Catch::Matchers::ContainsSubstring( - "must be > than the specified minimum timescale")); + TimescaleTuner tst( + {1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); + }()), + Catch::Matchers::ContainsSubstring( + "must be > than the specified minimum timescale")); - CHECK_THROWS_WITH( - ([]() { - const double increase_factor = 1.01; - const double decrease_factor = 0.99; - const double max_timescale = 10.0; - const double min_timescale = 1.0e-3; + CHECK_THROWS_WITH(([]() { + const double increase_factor = 1.01; + const double decrease_factor = 0.99; + const double max_timescale = 10.0; + const double min_timescale = 1.0e-3; - const double decrease_timescale_threshold = 1.0e-2; - const double increase_timescale_threshold = 0.0; + const double decrease_timescale_threshold = 1.0e-2; + const double increase_timescale_threshold = 0.0; - TimescaleTuner tst( - {1.0}, max_timescale, min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, decrease_factor); - }()), - Catch::Matchers::ContainsSubstring( - "The specified increase-timescale threshold")); + TimescaleTuner tst( + {1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); + }()), + Catch::Matchers::ContainsSubstring( + "The specified increase-timescale threshold")); CHECK_THROWS_WITH( ([]() { @@ -476,9 +509,9 @@ void test_errors() { const double decrease_timescale_threshold = 1.0e-4; const double increase_timescale_threshold = 1.0e-3; - TimescaleTuner tst( - {1.0}, max_timescale, min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, decrease_factor); + TimescaleTuner tst({1.0}, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); }()), Catch::Matchers::ContainsSubstring( "must be > than the specified increase-timescale threshold")); @@ -494,10 +527,9 @@ void test_errors() { const double min_timescale = 1.0e-3; const std::vector init_timescale{{1.0, 2.0}}; - TimescaleTuner tst(init_timescale, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst(init_timescale, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); const std::array qs{{{2.0}, {3.0}}}; tst.update_timescale(qs); @@ -513,9 +545,9 @@ void test_errors() { const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - TimescaleTuner tst( - 1.0, max_timescale, min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, decrease_factor); + TimescaleTuner tst(1.0, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); const std::array qs{{{2.0}}}; tst.update_timescale(qs); @@ -531,9 +563,9 @@ void test_errors() { const double max_timescale = 10.0; const double min_timescale = 1.0e-3; - TimescaleTuner tst( - 1.0, max_timescale, min_timescale, decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, decrease_factor); + TimescaleTuner tst(1.0, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); tst.current_timescale(); }()), @@ -549,10 +581,9 @@ void test_errors() { const double min_timescale = 1.0e-3; const std::vector init_timescale{{1.0, 2.0}}; - TimescaleTuner tst(init_timescale, max_timescale, min_timescale, - decrease_timescale_threshold, - increase_timescale_threshold, increase_factor, - decrease_factor); + TimescaleTuner tst(init_timescale, max_timescale, min_timescale, + increase_timescale_threshold, increase_factor, + decrease_timescale_threshold, decrease_factor); tst.resize_timescales(0); }()), @@ -564,9 +595,15 @@ void test_errors() { SPECTRE_TEST_CASE("Unit.ControlSystem.TimescaleTuner", "[ControlSystem][Unit]") { - test_increase_or_decrease(); - test_no_change_to_timescale(); - test_create_from_options(); - test_equality_and_serialization(); + tmpl::for_each>( + [](const auto bool_v) { + constexpr bool allow_decrease = + tmpl::type_from::value; + CAPTURE(allow_decrease); + test_increase_or_decrease(); + test_no_change_to_timescale(); + test_create_from_options(); + test_equality_and_serialization(); + }); test_errors(); } diff --git a/tests/Unit/Helpers/ControlSystem/Examples.hpp b/tests/Unit/Helpers/ControlSystem/Examples.hpp index 51768d039db0..fe9756099910 100644 --- a/tests/Unit/Helpers/ControlSystem/Examples.hpp +++ b/tests/Unit/Helpers/ControlSystem/Examples.hpp @@ -122,7 +122,7 @@ struct ExampleControlError void pup(PUP::er& /*p*/) {} template - DataVector operator()(const ::TimescaleTuner& tuner, + DataVector operator()(const ::TimescaleTuner& tuner, const Parallel::GlobalCache& cache, const double time, const std::string& function_of_time_name, diff --git a/tests/Unit/Helpers/ControlSystem/TestStructs.hpp b/tests/Unit/Helpers/ControlSystem/TestStructs.hpp index f667d41bb537..aa3246a742f5 100644 --- a/tests/Unit/Helpers/ControlSystem/TestStructs.hpp +++ b/tests/Unit/Helpers/ControlSystem/TestStructs.hpp @@ -43,7 +43,7 @@ struct ControlError : tt::ConformsTo { template DataVector operator()( - const ::TimescaleTuner& /*tuner*/, + const ::TimescaleTuner& /*tuner*/, const Parallel::GlobalCache& /*cache*/, const double /*time*/, const std::string& /*function_of_time_name*/, const tuples::TaggedTuple& /*measurements*/) {