From d38bb0ca80eca04a2a3af20422702973e08f77ab Mon Sep 17 00:00:00 2001 From: Thomas Fischer <thomas.fischer@ufz.de> Date: Thu, 1 Dec 2022 15:10:50 +0100 Subject: [PATCH] [NL] Include fixed output times in FixedTimeStepping algorithm --- .../Algorithms/CreateFixedTimeStepping.cpp | 119 ++++++++++++++++-- .../Algorithms/CreateFixedTimeStepping.h | 4 + 2 files changed, 115 insertions(+), 8 deletions(-) diff --git a/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.cpp b/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.cpp index 9d6c8bec076..461ec71f28d 100644 --- a/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.cpp +++ b/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.cpp @@ -11,8 +11,13 @@ #include "CreateFixedTimeStepping.h" +#include <fmt/ranges.h> + +#include <algorithm> +#include <numeric> #include <string> +#include "BaseLib/Algorithm.h" #include "BaseLib/ConfigTree.h" #include "BaseLib/Error.h" #include "FixedTimeStepping.h" @@ -20,6 +25,102 @@ namespace NumLib { +std::size_t findDeltatInterval(double const t_initial, + std::vector<double> const& delta_ts, + double const fixed_output_time) +{ + if (fixed_output_time < t_initial) + { + return std::numeric_limits<std::size_t>::max(); + } + + auto timestepper_time = t_initial; + for (std::size_t k = 0; k < delta_ts.size(); ++k) + { + if (timestepper_time <= fixed_output_time && + fixed_output_time < timestepper_time + delta_ts[k]) + { + return k; + } + timestepper_time += delta_ts[k]; + } + if (fixed_output_time == timestepper_time + delta_ts.back()) + { + return std::numeric_limits<std::size_t>::max(); + } + return std::numeric_limits<std::size_t>::max(); +} + +void incorporateFixedTimesForOutput( + double const t_initial, double const t_end, std::vector<double>& delta_ts, + std::vector<double> const& fixed_times_for_output) +{ + if (fixed_times_for_output.empty()) + { + return; + } + + if (auto lower_bound = + std::lower_bound(begin(fixed_times_for_output), + end(fixed_times_for_output), t_initial); + lower_bound != begin(fixed_times_for_output)) + { + WARN( + "Request for output at times {}, but the simulation's start time " + "is {}. Output will be skipped.", + fmt::join(begin(fixed_times_for_output), lower_bound, ", "), + t_initial); + } + + if (auto upper_bound = std::upper_bound(begin(fixed_times_for_output), + end(fixed_times_for_output), t_end); + upper_bound != end(fixed_times_for_output)) + { + WARN( + "Request for output at times {}, but simulation's end time is {}. " + "Output will be skipped.", + fmt::join(upper_bound, end(fixed_times_for_output), ", "), + t_end); + } + + if (delta_ts.empty()) + { + WARN("No timesteps specified."); + return; + } + + // incorporate fixed output times into dts vector + for (auto const fixed_time_for_output : fixed_times_for_output) + { + auto const interval_number = + findDeltatInterval(t_initial, delta_ts, fixed_time_for_output); + if (interval_number == std::numeric_limits<std::size_t>::max()) + { + WARN("Did not find interval for fixed output time {}", + fixed_time_for_output); + continue; + } + auto const lower_bound = std::accumulate( + begin(delta_ts), begin(delta_ts) + interval_number, t_initial); + auto const upper_bound = std::accumulate( + begin(delta_ts), begin(delta_ts) + interval_number + 1, t_initial); + if (fixed_time_for_output - lower_bound <= + std::numeric_limits<double>::epsilon()) + { + continue; + } + if (upper_bound - fixed_time_for_output <= + std::numeric_limits<double>::epsilon()) + { + continue; + } + delta_ts[interval_number] = fixed_time_for_output - lower_bound; + + delta_ts.insert(delta_ts.begin() + interval_number + 1, + upper_bound - fixed_time_for_output); + } +} + class TimeStepAlgorithm; std::unique_ptr<TimeStepAlgorithm> createFixedTimeStepping( BaseLib::ConfigTree const& config, @@ -33,15 +134,15 @@ std::unique_ptr<TimeStepAlgorithm> createFixedTimeStepping( //! \ogs_file_param{prj__time_loop__processes__process__time_stepping__FixedTimeStepping__t_end} auto const t_end = config.getConfigParameter<double>("t_end"); //! \ogs_file_param{prj__time_loop__processes__process__time_stepping__FixedTimeStepping__timesteps} - auto const delta_ts = config.getConfigSubtree("timesteps"); + auto const delta_ts_config = config.getConfigSubtree("timesteps"); - std::vector<double> timesteps; + std::vector<double> delta_ts; double t_curr = t_initial; double delta_t = 0.0; // TODO: consider adding call "listNonEmpty" to config tree //! \ogs_file_param{prj__time_loop__processes__process__time_stepping__FixedTimeStepping__timesteps__pair} - auto const range = delta_ts.getConfigSubtreeList("pair"); + auto const range = delta_ts_config.getConfigSubtreeList("pair"); if (range.begin() == range.end()) { OGS_FATAL("no timesteps have been given"); @@ -64,10 +165,10 @@ std::unique_ptr<TimeStepAlgorithm> createFixedTimeStepping( if (t_curr <= t_end) { - auto const new_size = timesteps.size() + repeat; + auto const new_size = delta_ts.size() + repeat; try { - timesteps.resize(new_size, delta_t); + delta_ts.resize(new_size, delta_t); } catch (std::length_error const& e) { @@ -100,10 +201,10 @@ std::unique_ptr<TimeStepAlgorithm> createFixedTimeStepping( { auto const repeat = static_cast<std::size_t>(std::ceil((t_end - t_curr) / delta_t)); - auto const new_size = timesteps.size() + repeat; + auto const new_size = delta_ts.size() + repeat; try { - timesteps.resize(new_size, delta_t); + delta_ts.resize(new_size, delta_t); } catch (std::length_error const& e) { @@ -128,6 +229,8 @@ std::unique_ptr<TimeStepAlgorithm> createFixedTimeStepping( } } - return std::make_unique<FixedTimeStepping>(t_initial, t_end, timesteps); + incorporateFixedTimesForOutput(t_initial, t_end, delta_ts, + fixed_times_for_output); + return std::make_unique<FixedTimeStepping>(t_initial, t_end, delta_ts); } } // end of namespace NumLib diff --git a/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.h b/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.h index fd0aa7fe8d2..9c2062faf86 100644 --- a/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.h +++ b/NumLib/TimeStepping/Algorithms/CreateFixedTimeStepping.h @@ -23,6 +23,10 @@ namespace NumLib { class TimeStepAlgorithm; +std::size_t findDeltatInterval(double const t_initial, + std::vector<double> const& delta_ts, + double const fixed_output_time); + /// Create a FixedTimeStepping time stepper from the given /// configuration std::unique_ptr<TimeStepAlgorithm> createFixedTimeStepping( -- GitLab