From 1ec80330daa78537e296aae8273258d8f07f1fbf Mon Sep 17 00:00:00 2001 From: William Throwe Date: Sun, 29 Sep 2024 13:59:58 -0400 Subject: [PATCH 1/4] Add doc notes on how to use debugging StepChoosers --- src/Time/StepChoosers/ByBlock.hpp | 4 ++++ src/Time/StepChoosers/Random.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Time/StepChoosers/ByBlock.hpp b/src/Time/StepChoosers/ByBlock.hpp index 5f2ac2c4d7a5..533e1a35d7ac 100644 --- a/src/Time/StepChoosers/ByBlock.hpp +++ b/src/Time/StepChoosers/ByBlock.hpp @@ -29,6 +29,10 @@ class er; namespace StepChoosers { /// Sets a goal specified per-block. +/// +/// \note This debugging StepChooser is not included in the +/// `standard_step_choosers` list, but can be added to the +/// `factory_creation` struct in the metavariables. template class ByBlock : public StepChooser, public StepChooser { diff --git a/src/Time/StepChoosers/Random.hpp b/src/Time/StepChoosers/Random.hpp index b655993c354b..a83d5ac45d64 100644 --- a/src/Time/StepChoosers/Random.hpp +++ b/src/Time/StepChoosers/Random.hpp @@ -31,6 +31,10 @@ struct Element; namespace StepChoosers { /// Changes the step size pseudo-randomly. Values are distributed /// uniformly in $\log(dt)$. The current step is always accepted. +/// +/// \note This debugging StepChooser is not included in the +/// `standard_step_choosers` list, but can be added to the +/// `factory_creation` struct in the metavariables. template class Random : public StepChooser, public StepChooser { From 6b770b1bcd3ec67f0b3489e3a3da45e79797c776 Mon Sep 17 00:00:00 2001 From: William Throwe Date: Sat, 28 Sep 2024 11:57:45 -0400 Subject: [PATCH 2/4] Add FixedLtsRatio tag --- src/Time/Tags/CMakeLists.txt | 1 + src/Time/Tags/FixedLtsRatio.hpp | 17 +++++++++++++++++ tests/Unit/Time/Tags/CMakeLists.txt | 1 + tests/Unit/Time/Tags/Test_FixedLtsRatio.cpp | 13 +++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 src/Time/Tags/FixedLtsRatio.hpp create mode 100644 tests/Unit/Time/Tags/Test_FixedLtsRatio.cpp diff --git a/src/Time/Tags/CMakeLists.txt b/src/Time/Tags/CMakeLists.txt index e8f13a03a389..1ca8a9a28c22 100644 --- a/src/Time/Tags/CMakeLists.txt +++ b/src/Time/Tags/CMakeLists.txt @@ -6,6 +6,7 @@ spectre_target_headers( INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/src HEADERS AdaptiveSteppingDiagnostics.hpp + FixedLtsRatio.hpp HistoryEvolvedVariables.hpp IsUsingTimeSteppingErrorControl.hpp MinimumTimeStep.hpp diff --git a/src/Time/Tags/FixedLtsRatio.hpp b/src/Time/Tags/FixedLtsRatio.hpp new file mode 100644 index 000000000000..a7deab8e4dd3 --- /dev/null +++ b/src/Time/Tags/FixedLtsRatio.hpp @@ -0,0 +1,17 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +#include +#include + +#include "DataStructures/DataBox/Tag.hpp" + +namespace Tags { +/// \ingroup TimeGroup +/// \brief Tag forcing a constant step size over a region in an LTS evolution. +struct FixedLtsRatio : db::SimpleTag { + using type = std::optional; +}; +} // namespace Tags diff --git a/tests/Unit/Time/Tags/CMakeLists.txt b/tests/Unit/Time/Tags/CMakeLists.txt index df836aa3f9af..383b331d8cb9 100644 --- a/tests/Unit/Time/Tags/CMakeLists.txt +++ b/tests/Unit/Time/Tags/CMakeLists.txt @@ -4,6 +4,7 @@ set(LIBRARY_SOURCES ${LIBRARY_SOURCES} Tags/Test_AdaptiveSteppingDiagnostics.cpp + Tags/Test_FixedLtsRatio.cpp Tags/Test_HistoryEvolvedVariables.cpp Tags/Test_IsUsingTimeSteppingErrorControl.cpp Tags/Test_MinimumTimeStep.cpp diff --git a/tests/Unit/Time/Tags/Test_FixedLtsRatio.cpp b/tests/Unit/Time/Tags/Test_FixedLtsRatio.cpp new file mode 100644 index 000000000000..bb269edb779e --- /dev/null +++ b/tests/Unit/Time/Tags/Test_FixedLtsRatio.cpp @@ -0,0 +1,13 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Framework/TestingFramework.hpp" + +#include + +#include "Helpers/DataStructures/DataBox/TestHelpers.hpp" +#include "Time/Tags/FixedLtsRatio.hpp" + +SPECTRE_TEST_CASE("Unit.Time.Tags.FixedLtsRatio", "[Unit][Time]") { + TestHelpers::db::test_simple_tag("FixedLtsRatio"); +} From 72254b8bbf1a298b0f8d4bcb5777149b5477cddd Mon Sep 17 00:00:00 2001 From: William Throwe Date: Sat, 28 Sep 2024 12:00:05 -0400 Subject: [PATCH 3/4] Use FixedLtsRatio to choose step size if present --- src/Time/Actions/ChangeStepSize.hpp | 60 ++++++++++++++----- .../Unit/Time/Actions/Test_ChangeStepSize.cpp | 58 ++++++++++++++++++ 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/src/Time/Actions/ChangeStepSize.hpp b/src/Time/Actions/ChangeStepSize.hpp index 7004b19c4dea..d67d639acd4c 100644 --- a/src/Time/Actions/ChangeStepSize.hpp +++ b/src/Time/Actions/ChangeStepSize.hpp @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include @@ -16,6 +17,7 @@ #include "Time/Tags/AdaptiveSteppingDiagnostics.hpp" #include "Time/Tags/HistoryEvolvedVariables.hpp" #include "Time/Tags/MinimumTimeStep.hpp" +#include "Time/TimeStepRequest.hpp" #include "Time/TimeStepRequestProcessor.hpp" #include "Time/TimeSteppers/LtsTimeStepper.hpp" #include "Utilities/ErrorHandling/Assert.hpp" @@ -36,6 +38,7 @@ namespace StepChooserUse { struct LtsStep; } // namespace StepChooserUse namespace Tags { +struct FixedLtsRatio; template struct Next; struct StepChoosers; @@ -50,7 +53,21 @@ struct TimeStepper; /// \brief Adjust the step size for local time stepping, returning true if the /// step just completed is accepted, and false if it is rejected. /// -/// \details The optional template parameter `StepChoosersToUse` may be used to +/// \details +/// Usually, the new step size is chosen by calling the StepChoosers from +/// `Tags::StepChoosers`, restricted based on the allowed step sizes at the +/// current (if rejected) or next (if not rejected) time, and limits from +/// history initialization. +/// +/// If `Tags::FixedLtsRatio` is present in the DataBox and not empty, the +/// StepChoosers are not called and instead the desired step is taken to be the +/// slab size over that value, without rejecting the step. Early in the +/// evolution, the actual chosen step may differ from this because of +/// restrictions on the allowed step, but all such restrictions are global and +/// will not result in different decisions for different elements with the same +/// desired fixed ratio. +/// +/// The optional template parameter `StepChoosersToUse` may be used to /// indicate a subset of the constructable step choosers to use for the current /// application of `ChangeStepSize`. Passing `AllStepChoosers` (default) /// indicates that any constructible step chooser may be used. This option is @@ -65,19 +82,6 @@ bool change_step_size(const gsl::not_null*> box) { const auto& time_step_id = db::get(*box); ASSERT(time_step_id.substep() == 0, "Can't change step size on a substep."); - const auto current_step = db::get(*box); - const double last_step_size = current_step.value(); - - TimeStepRequestProcessor step_requests(time_step_id.time_runs_forward()); - bool step_accepted = true; - for (const auto& step_chooser : step_choosers) { - const auto [step_request, step_choice_accepted] = - step_chooser->template desired_step(last_step_size, - *box); - step_requests.process(step_request); - step_accepted = step_accepted and step_choice_accepted; - } - using history_tags = ::Tags::get_all_history_tags; bool can_change_step_size = true; tmpl::for_each([&box, &can_change_step_size, &time_stepper, @@ -90,6 +94,34 @@ bool change_step_size(const gsl::not_null*> box) { can_change_step_size = time_stepper.can_change_step_size(time_step_id, history); }); + + const auto current_step = db::get(*box); + + std::optional fixed_lts_ratio{}; + if constexpr (db::tag_is_retrievable_v>) { + fixed_lts_ratio = db::get(*box); + } + + TimeStepRequestProcessor step_requests(time_step_id.time_runs_forward()); + bool step_accepted = true; + if (fixed_lts_ratio.has_value()) { + ASSERT(std::popcount(*fixed_lts_ratio) == 1, + "fixed_lts_ratio must be a power of 2, not " << *fixed_lts_ratio); + step_requests.process(TimeStepRequest{ + .size_goal = + (current_step.slab().duration() / *fixed_lts_ratio).value()}); + } else { + const double last_step_size = current_step.value(); + for (const auto& step_chooser : step_choosers) { + const auto [step_request, step_choice_accepted] = + step_chooser->template desired_step(last_step_size, + *box); + step_requests.process(step_request); + step_accepted = step_accepted and step_choice_accepted; + } + } + if (not can_change_step_size) { step_requests.error_on_hard_limit( current_step.value(), diff --git a/tests/Unit/Time/Actions/Test_ChangeStepSize.cpp b/tests/Unit/Time/Actions/Test_ChangeStepSize.cpp index ce11dfc7a04e..36eac4a43071 100644 --- a/tests/Unit/Time/Actions/Test_ChangeStepSize.cpp +++ b/tests/Unit/Time/Actions/Test_ChangeStepSize.cpp @@ -16,6 +16,7 @@ #include "Options/Protocols/FactoryCreation.hpp" #include "Parallel/Phase.hpp" #include "Parallel/PhaseDependentActionList.hpp" +#include "Parallel/Tags/Metavariables.hpp" #include "ParallelAlgorithms/Actions/Goto.hpp" #include "Time/Actions/ChangeStepSize.hpp" #include "Time/AdaptiveSteppingDiagnostics.hpp" @@ -24,6 +25,7 @@ #include "Time/StepChoosers/Constant.hpp" #include "Time/StepChoosers/StepChooser.hpp" #include "Time/Tags/AdaptiveSteppingDiagnostics.hpp" +#include "Time/Tags/FixedLtsRatio.hpp" #include "Time/Tags/HistoryEvolvedVariables.hpp" #include "Time/Tags/IsUsingTimeSteppingErrorControl.hpp" #include "Time/Tags/StepChoosers.hpp" @@ -178,6 +180,60 @@ void check(const bool time_runs_forward, } CHECK(db::get>(box) == expected_step); } + +struct FixedRatioMetavariables { + struct factory_creation + : tt::ConformsTo { + using factory_classes = + tmpl::map, + tmpl::list>>; + }; +}; + +void test_fixed_lts_ratio() { + std::unique_ptr time_stepper = + std::make_unique(3); + const Slab slab(2.3, 4.5); + const TimeStepId initial_id(true, 0, slab.start()); + const auto initial_step = slab.duration() / 4; + const auto next_id = time_stepper->next_time_id(initial_id, initial_step); + TimeSteppers::History history(3); + history.insert(TimeStepId(true, -1, slab.start() + initial_step), 0.0, 0.0); + history.insert(TimeStepId(true, -1, slab.start() + 2 * initial_step), 0.0, + 0.0); + history.insert(initial_id, 0.0, 0.0); + + auto box = db::create< + db::AddSimpleTags< + Parallel::Tags::MetavariablesImpl, + Tags::ConcreteTimeStepper, Tags::StepChoosers, + Tags::MinimumTimeStep, Tags::FixedLtsRatio, Tags::TimeStepId, + Tags::TimeStep, Tags::Next, + Tags::Next, Tags::HistoryEvolvedVariables>, + db::AddComputeTags>>( + FixedRatioMetavariables{}, std::move(time_stepper), + Tags::StepChoosers::type{}, 1e-10, std::optional(8), initial_id, + initial_step, next_id, initial_step, std::move(history)); + + change_step_size(make_not_null(&box)); + // Step size change forbidden after self-start + CHECK(db::get>(box) == initial_step); + + db::mutate>( + [&](const gsl::not_null*> local_history) { + const auto old_step = initial_step.with_slab(slab.retreat()); + local_history->clear(); + local_history->insert(TimeStepId(true, -1, slab.start() - 2 * old_step), + 0.0, 0.0); + local_history->insert(TimeStepId(true, -1, slab.start() - old_step), + 0.0, 0.0); + local_history->insert(initial_id, 0.0, 0.0); + }, + make_not_null(&box)); + + change_step_size(make_not_null(&box)); + CHECK(db::get>(box).fraction() == Rational(1, 8)); +} } // namespace SPECTRE_TEST_CASE("Unit.Time.Actions.ChangeStepSize", "[Unit][Time][Actions]") { @@ -254,4 +310,6 @@ SPECTRE_TEST_CASE("Unit.Time.Actions.ChangeStepSize", "[Unit][Time][Actions]") { slab.start() + slab.duration() / 4, 1e-9, slab.duration() / 4, std::nullopt), Catch::Matchers::ContainsSubstring("smaller than the MinimumTimeStep")); + + test_fixed_lts_ratio(); } From 552751b699c0abf316c28dad1b393e49c018bc80 Mon Sep 17 00:00:00 2001 From: William Throwe Date: Sat, 28 Sep 2024 12:01:02 -0400 Subject: [PATCH 4/4] Add FixedLtsRatio StepChooser to set slab size --- src/Time/StepChoosers/CMakeLists.txt | 2 + src/Time/StepChoosers/FixedLtsRatio.cpp | 29 ++++ src/Time/StepChoosers/FixedLtsRatio.hpp | 129 ++++++++++++++++ tests/Unit/Time/StepChoosers/CMakeLists.txt | 1 + .../Time/StepChoosers/Test_FixedLtsRatio.cpp | 143 ++++++++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 src/Time/StepChoosers/FixedLtsRatio.cpp create mode 100644 src/Time/StepChoosers/FixedLtsRatio.hpp create mode 100644 tests/Unit/Time/StepChoosers/Test_FixedLtsRatio.cpp diff --git a/src/Time/StepChoosers/CMakeLists.txt b/src/Time/StepChoosers/CMakeLists.txt index 88ce0d654112..faa25aa14ff0 100644 --- a/src/Time/StepChoosers/CMakeLists.txt +++ b/src/Time/StepChoosers/CMakeLists.txt @@ -6,6 +6,7 @@ spectre_target_sources( PRIVATE ByBlock.cpp Constant.cpp + FixedLtsRatio.cpp LimitIncrease.cpp Maximum.cpp PreventRapidIncrease.cpp @@ -23,6 +24,7 @@ spectre_target_headers( ElementSizeCfl.hpp ErrorControl.hpp Factory.hpp + FixedLtsRatio.hpp LimitIncrease.hpp Maximum.hpp PreventRapidIncrease.hpp diff --git a/src/Time/StepChoosers/FixedLtsRatio.cpp b/src/Time/StepChoosers/FixedLtsRatio.cpp new file mode 100644 index 000000000000..7f0d3e3d1bad --- /dev/null +++ b/src/Time/StepChoosers/FixedLtsRatio.cpp @@ -0,0 +1,29 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Time/StepChoosers/FixedLtsRatio.hpp" + +#include +#include +#include +#include +#include + +#include "Time/StepChoosers/StepChooser.hpp" + +namespace StepChoosers { +FixedLtsRatio::FixedLtsRatio( + std::vector>> + step_choosers) + : step_choosers_(std::move(step_choosers)) {} + +bool FixedLtsRatio::uses_local_data() const { return true; } +bool FixedLtsRatio::can_be_delayed() const { return true; } + +void FixedLtsRatio::pup(PUP::er& p) { + StepChooser::pup(p); + p | step_choosers_; +} + +PUP::able::PUP_ID FixedLtsRatio::my_PUP_ID = 0; // NOLINT +} // namespace StepChoosers diff --git a/src/Time/StepChoosers/FixedLtsRatio.hpp b/src/Time/StepChoosers/FixedLtsRatio.hpp new file mode 100644 index 000000000000..c024e5189046 --- /dev/null +++ b/src/Time/StepChoosers/FixedLtsRatio.hpp @@ -0,0 +1,129 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +#include +#include +#include +#include +#include + +#include "DataStructures/DataBox/DataBox.hpp" +#include "Options/String.hpp" +#include "Time/EvolutionOrdering.hpp" +#include "Time/StepChoosers/StepChooser.hpp" +#include "Time/TimeStepRequest.hpp" +#include "Utilities/ErrorHandling/Assert.hpp" +#include "Utilities/Serialization/CharmPupable.hpp" +#include "Utilities/TMPL.hpp" + +/// \cond +namespace PUP { +class er; +} // namespace PUP +namespace Tags { +struct FixedLtsRatio; +struct TimeStep; +} // namespace Tags +/// \endcond + +namespace StepChoosers { +/// Requests a slab size based on the desired step in regions with a +/// fixed slab fraction. +/// +/// \note This StepChooser is not included in the +/// `standard_step_choosers` list. Executables using the feature must +/// include it explicitly in the `factory_creation` struct and add the +/// `::Tags::FixedLtsRatio` tag to the element DataBox. +class FixedLtsRatio : public StepChooser { + public: + /// \cond + FixedLtsRatio() = default; + explicit FixedLtsRatio(CkMigrateMessage* /*unused*/) {} + using PUP::able::register_constructor; + WRAPPED_PUPable_decl_template(FixedLtsRatio); // NOLINT + /// \endcond + + struct StepChoosers { + using type = + std::vector>>; + static constexpr Options::String help{"LTS step choosers to test"}; + }; + + static constexpr Options::String help{ + "Requests a slab size based on the desired step in regions with a fixed " + "slab fraction."}; + using options = tmpl::list; + + explicit FixedLtsRatio( + std::vector>> + step_choosers); + + using argument_tags = tmpl::list<::Tags::DataBox>; + + template + std::pair operator()( + const db::DataBox& box, const double /*last_step*/) const { + const auto& step_ratio = db::get<::Tags::FixedLtsRatio>(box); + if (not step_ratio.has_value()) { + return {{}, true}; + } + + const auto& current_step = db::get<::Tags::TimeStep>(box); + const evolution_less less{current_step.is_positive()}; + + std::optional size_goal{}; + std::optional size{}; + for (const auto& step_chooser : step_choosers_) { + const auto step_request = + step_chooser->desired_step(current_step.value(), box).first; + + if (step_request.size_goal.has_value()) { + if (size_goal.has_value()) { + *size_goal = std::min(*size_goal, *step_request.size_goal, less); + } else { + size_goal = step_request.size_goal; + } + } + if (step_request.size.has_value()) { + if (size.has_value()) { + *size = std::min(*size, *step_request.size, less); + } else { + size = step_request.size; + } + } + + // As of writing (Oct. 2024), no StepChooserUse::LtsStep chooser + // sets these. + ASSERT(not(step_request.end.has_value() or + step_request.size_hard_limit.has_value() or + step_request.end_hard_limit.has_value()), + "Unhandled field set by StepChooser. Please file a bug " + "containing the options passed to FixedLtsRatio."); + } + + if (size_goal.has_value()) { + *size_goal *= *step_ratio; + } + if (size.has_value()) { + *size *= *step_ratio; + if (size_goal.has_value() and less(*size_goal, *size)) { + // Not allowed to request a goal and a bigger step. + size.reset(); + } + } + + return {{.size_goal = size_goal, .size = size}, true}; + } + + bool uses_local_data() const override; + bool can_be_delayed() const override; + + void pup(PUP::er& p) override; + + private: + std::vector>> + step_choosers_; +}; +} // namespace StepChoosers diff --git a/tests/Unit/Time/StepChoosers/CMakeLists.txt b/tests/Unit/Time/StepChoosers/CMakeLists.txt index c01c86593086..99efd8887c66 100644 --- a/tests/Unit/Time/StepChoosers/CMakeLists.txt +++ b/tests/Unit/Time/StepChoosers/CMakeLists.txt @@ -8,6 +8,7 @@ set(LIBRARY_SOURCES StepChoosers/Test_Constant.cpp StepChoosers/Test_ElementSizeCfl.cpp StepChoosers/Test_ErrorControl.cpp + StepChoosers/Test_FixedLtsRatio.cpp StepChoosers/Test_LimitIncrease.cpp StepChoosers/Test_Maximum.cpp StepChoosers/Test_PreventRapidIncrease.cpp diff --git a/tests/Unit/Time/StepChoosers/Test_FixedLtsRatio.cpp b/tests/Unit/Time/StepChoosers/Test_FixedLtsRatio.cpp new file mode 100644 index 000000000000..9c133264435f --- /dev/null +++ b/tests/Unit/Time/StepChoosers/Test_FixedLtsRatio.cpp @@ -0,0 +1,143 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Framework/TestingFramework.hpp" + +#include +#include +#include +#include +#include + +#include "DataStructures/DataBox/DataBox.hpp" +#include "Framework/TestCreation.hpp" +#include "Framework/TestHelpers.hpp" +#include "Options/Protocols/FactoryCreation.hpp" +#include "Options/String.hpp" +#include "Parallel/Tags/Metavariables.hpp" +#include "Time/Slab.hpp" +#include "Time/StepChoosers/Constant.hpp" +#include "Time/StepChoosers/FixedLtsRatio.hpp" +#include "Time/StepChoosers/LimitIncrease.hpp" +#include "Time/StepChoosers/StepChooser.hpp" +#include "Time/Tags/FixedLtsRatio.hpp" +#include "Time/Tags/TimeStep.hpp" +#include "Time/TimeStepRequest.hpp" +#include "Utilities/ErrorHandling/Error.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/Serialization/CharmPupable.hpp" +#include "Utilities/Serialization/RegisterDerivedClassesWithCharm.hpp" +#include "Utilities/TMPL.hpp" + +namespace { +class ErrorChooser : public StepChooser { + public: + ErrorChooser() = default; + explicit ErrorChooser(CkMigrateMessage* /*unused*/) {} + using PUP::able::register_constructor; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + WRAPPED_PUPable_decl_template(ErrorChooser); // NOLINT +#pragma GCC diagnostic pop + + static constexpr Options::String help{""}; + using options = tmpl::list<>; + + using argument_tags = tmpl::list<>; + + std::pair operator()(double /*last_step*/) const { + ERROR("StepChooser should not be called in fixed LTS region"); + } + + bool uses_local_data() const override { return false; } + bool can_be_delayed() const override { return true; } +}; + +PUP::able::PUP_ID ErrorChooser::my_PUP_ID = 0; // NOLINT + +struct Metavariables { + struct factory_creation + : tt::ConformsTo { + using factory_classes = tmpl::map< + tmpl::pair, + tmpl::list>, + tmpl::pair, + tmpl::list>>; + }; +}; + +void test(const std::optional& expected_goal, + const std::optional& expected_size, + const std::optional& fixed_ratio, + const std::string& lts_choosers) { + CAPTURE(lts_choosers); + const Slab slab(2.0, 6.0); + const auto time_step = slab.duration() / 2; + + for (const auto& time_sign : {1, -1}) { + CAPTURE(time_sign); + auto box = db::create< + db::AddSimpleTags, + Tags::TimeStep, Tags::FixedLtsRatio>>( + Metavariables{}, time_sign * time_step, fixed_ratio); + + const auto chooser = TestHelpers::test_creation< + std::unique_ptr>, Metavariables>( + "FixedLtsRatio:\n" + " StepChoosers:\n" + + lts_choosers); + + const auto set_sign = [&](const std::optional& opt) { + if (opt.has_value()) { + return std::optional(time_sign * *opt); + } else { +#if defined(__GNUC__) and not defined(__clang__) and __GNUC__ < 10 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + return std::optional{}; +#if defined(__GNUC__) and not defined(__clang__) and __GNUC__ < 10 +#pragma GCC diagnostic pop +#endif + } + }; + + const double current_step = time_sign * slab.duration().value(); + const std::pair expected{ + {.size_goal = set_sign(expected_goal), .size = set_sign(expected_size)}, + true}; + CHECK(chooser->desired_step(current_step, box) == expected); + CHECK(serialize_and_deserialize(chooser)->desired_step(current_step, box) == + expected); + } +} +} // namespace + +SPECTRE_TEST_CASE("Unit.Time.StepChoosers.FixedLtsRatio", "[Unit][Time]") { + register_factory_classes_with_charm(); + + test({}, {}, {}, " - ErrorChooser"); + test({}, {}, {8}, ""); + test({40.0}, {}, {8}, + " - Constant: 5.0\n" + " - Constant: 7.0"); + // Initial step size used in test is 2.0 + test({}, {64.0}, {8}, + " - LimitIncrease:\n" + " Factor: 4.0\n" + " - LimitIncrease:\n" + " Factor: 9.0"); + test({40.0}, {32.0}, {8}, + " - Constant: 5.0\n" + " - LimitIncrease:\n" + " Factor: 2.0"); + // Should never give a limit larger than the goal. + test({40.0}, {}, {8}, + " - Constant: 5.0\n" + " - LimitIncrease:\n" + " Factor: 4.0"); + + CHECK(StepChoosers::FixedLtsRatio{}.uses_local_data()); + CHECK(StepChoosers::FixedLtsRatio{}.can_be_delayed()); +}