Skip to content

Commit

Permalink
Merge pull request #6319 from wthrowe/fixed_lts_ratio
Browse files Browse the repository at this point in the history
Add ability to take a consistent LTS step in a region
  • Loading branch information
nilsdeppe authored Oct 3, 2024
2 parents e5481c9 + 552751b commit 4187625
Show file tree
Hide file tree
Showing 13 changed files with 448 additions and 14 deletions.
60 changes: 46 additions & 14 deletions src/Time/Actions/ChangeStepSize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <bit>
#include <limits>
#include <optional>
#include <tuple>
Expand All @@ -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"
Expand All @@ -36,6 +38,7 @@ namespace StepChooserUse {
struct LtsStep;
} // namespace StepChooserUse
namespace Tags {
struct FixedLtsRatio;
template <typename Tag>
struct Next;
struct StepChoosers;
Expand All @@ -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
Expand All @@ -65,19 +82,6 @@ bool change_step_size(const gsl::not_null<db::DataBox<DbTags>*> box) {
const auto& time_step_id = db::get<Tags::TimeStepId>(*box);
ASSERT(time_step_id.substep() == 0, "Can't change step size on a substep.");

const auto current_step = db::get<Tags::TimeStep>(*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<StepChoosersToUse>(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<DbTags>;
bool can_change_step_size = true;
tmpl::for_each<history_tags>([&box, &can_change_step_size, &time_stepper,
Expand All @@ -90,6 +94,34 @@ bool change_step_size(const gsl::not_null<db::DataBox<DbTags>*> box) {
can_change_step_size =
time_stepper.can_change_step_size(time_step_id, history);
});

const auto current_step = db::get<Tags::TimeStep>(*box);

std::optional<size_t> fixed_lts_ratio{};
if constexpr (db::tag_is_retrievable_v<Tags::FixedLtsRatio,
db::DataBox<DbTags>>) {
fixed_lts_ratio = db::get<Tags::FixedLtsRatio>(*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<StepChoosersToUse>(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(),
Expand Down
4 changes: 4 additions & 0 deletions src/Time/StepChoosers/ByBlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <size_t Dim>
class ByBlock : public StepChooser<StepChooserUse::Slab>,
public StepChooser<StepChooserUse::LtsStep> {
Expand Down
2 changes: 2 additions & 0 deletions src/Time/StepChoosers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ spectre_target_sources(
PRIVATE
ByBlock.cpp
Constant.cpp
FixedLtsRatio.cpp
LimitIncrease.cpp
Maximum.cpp
PreventRapidIncrease.cpp
Expand All @@ -23,6 +24,7 @@ spectre_target_headers(
ElementSizeCfl.hpp
ErrorControl.hpp
Factory.hpp
FixedLtsRatio.hpp
LimitIncrease.hpp
Maximum.hpp
PreventRapidIncrease.hpp
Expand Down
29 changes: 29 additions & 0 deletions src/Time/StepChoosers/FixedLtsRatio.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Time/StepChoosers/FixedLtsRatio.hpp"

#include <memory>
#include <pup.h>
#include <pup_stl.h>
#include <utility>
#include <vector>

#include "Time/StepChoosers/StepChooser.hpp"

namespace StepChoosers {
FixedLtsRatio::FixedLtsRatio(
std::vector<std::unique_ptr<::StepChooser<StepChooserUse::LtsStep>>>
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<StepChooserUse::Slab>::pup(p);
p | step_choosers_;
}

PUP::able::PUP_ID FixedLtsRatio::my_PUP_ID = 0; // NOLINT
} // namespace StepChoosers
129 changes: 129 additions & 0 deletions src/Time/StepChoosers/FixedLtsRatio.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#pragma once

#include <algorithm>
#include <memory>
#include <optional>
#include <utility>
#include <vector>

#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<StepChooserUse::Slab> {
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<std::unique_ptr<::StepChooser<StepChooserUse::LtsStep>>>;
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<StepChoosers>;

explicit FixedLtsRatio(
std::vector<std::unique_ptr<::StepChooser<StepChooserUse::LtsStep>>>
step_choosers);

using argument_tags = tmpl::list<::Tags::DataBox>;

template <typename DbTags>
std::pair<TimeStepRequest, bool> operator()(
const db::DataBox<DbTags>& 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<double> less{current_step.is_positive()};

std::optional<double> size_goal{};
std::optional<double> 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<std::unique_ptr<::StepChooser<StepChooserUse::LtsStep>>>
step_choosers_;
};
} // namespace StepChoosers
4 changes: 4 additions & 0 deletions src/Time/StepChoosers/Random.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <size_t VolumeDim>
class Random : public StepChooser<StepChooserUse::Slab>,
public StepChooser<StepChooserUse::LtsStep> {
Expand Down
1 change: 1 addition & 0 deletions src/Time/Tags/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ spectre_target_headers(
INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/src
HEADERS
AdaptiveSteppingDiagnostics.hpp
FixedLtsRatio.hpp
HistoryEvolvedVariables.hpp
IsUsingTimeSteppingErrorControl.hpp
MinimumTimeStep.hpp
Expand Down
17 changes: 17 additions & 0 deletions src/Time/Tags/FixedLtsRatio.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#pragma once

#include <cstddef>
#include <optional>

#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<size_t>;
};
} // namespace Tags
Loading

0 comments on commit 4187625

Please sign in to comment.