9#include "abstract_integrator.hpp"
11namespace diffeq::core {
19 : std::runtime_error(message) {}
22 : std::runtime_error(
"Integration timed out after " +
23 std::to_string(timeout_duration.count()) +
"ms") {}
30 std::chrono::milliseconds timeout_duration{5000};
31 bool throw_on_timeout{
true};
32 bool enable_progress_callback{
false};
33 std::chrono::milliseconds progress_interval{100};
36 std::function<bool(
double,
double, std::chrono::milliseconds)> progress_callback;
43 bool completed{
false};
44 std::chrono::milliseconds elapsed_time{0};
45 double final_time{0.0};
46 std::string error_message;
49 bool is_success()
const {
return completed && error_message.empty(); }
50 bool is_timeout()
const {
return !completed && error_message.find(
"timeout") != std::string::npos; }
51 bool is_error()
const {
return !completed && !is_timeout(); }
69template<
typename Integrator>
72 using integrator_type = Integrator;
73 using state_type =
typename Integrator::state_type;
74 using time_type =
typename Integrator::time_type;
89 template<
typename... Args>
91 : integrator_(std::forward<Args>(args)...), config_(std::move(
config)) {}
101 const auto start_time = std::chrono::high_resolution_clock::now();
103 result.final_time = integrator_.current_time();
107 auto future = std::async(std::launch::async, [
this, &state, dt, end_time]() {
108 integrator_.integrate(state, dt, end_time);
112 if (config_.enable_progress_callback && config_.progress_callback) {
114 result = wait_with_progress_monitoring(future, end_time, start_time);
117 if (future.wait_for(config_.timeout_duration) == std::future_status::timeout) {
118 result.completed =
false;
119 result.error_message =
"Integration timed out after " +
120 std::to_string(config_.timeout_duration.count()) +
"ms";
123 result.completed =
true;
127 result.final_time = integrator_.current_time();
129 }
catch (
const std::exception& e) {
130 result.completed =
false;
131 result.error_message =
"Integration failed: " + std::string(e.what());
135 const auto end_clock_time = std::chrono::high_resolution_clock::now();
136 result.elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(
137 end_clock_time - start_time);
140 if (!result.completed && config_.throw_on_timeout && result.is_timeout()) {
156 std::chrono::milliseconds timeout = std::chrono::milliseconds{0}) {
157 auto old_config = config_;
158 if (timeout.count() > 0) {
159 config_.timeout_duration = timeout;
161 config_.throw_on_timeout =
false;
163 auto result = integrate_with_timeout(state, dt, end_time);
164 config_ = old_config;
166 return result.completed;
174 const Integrator&
integrator()
const {
return integrator_; }
184 Integrator integrator_;
190 IntegrationResult wait_with_progress_monitoring(std::future<void>& future, time_type end_time,
191 std::chrono::high_resolution_clock::time_point start_time) {
194 auto last_progress_time = start_time;
198 if (future.wait_for(config_.progress_interval) == std::future_status::ready) {
200 result.completed =
true;
205 auto current_time = std::chrono::high_resolution_clock::now();
206 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time);
208 if (elapsed >= config_.timeout_duration) {
209 result.completed =
false;
210 result.error_message =
"Integration timed out after " +
211 std::to_string(elapsed.count()) +
"ms";
216 if (config_.progress_callback) {
217 bool should_continue = config_.progress_callback(
218 static_cast<double>(integrator_.current_time()),
219 static_cast<double>(end_time),
223 if (!should_continue) {
224 result.completed =
false;
225 result.error_message =
"Integration cancelled by progress callback";
230 last_progress_time = current_time;
244template<
typename Integrator>
245auto make_timeout_integrator(Integrator integrator, TimeoutConfig config = {}) {
246 return TimeoutIntegrator<Integrator>(std::move(integrator), std::move(config));
259template<
typename Integrator,
typename State>
260bool integrate_with_timeout(Integrator& integrator, State& state,
261 typename Integrator::time_type dt,
262 typename Integrator::time_type end_time,
263 std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) {
265 State state_copy = state;
267 auto future = std::async(std::launch::async, [&integrator, &state_copy, dt, end_time]() {
268 integrator.integrate(state_copy, dt, end_time);
271 auto status = future.wait_for(timeout);
273 if (status == std::future_status::ready) {
Exception thrown when integration times out.
Timeout-enabled integration wrapper.
bool integrate_with_timeout_simple(state_type &state, time_type dt, time_type end_time, std::chrono::milliseconds timeout=std::chrono::milliseconds{0})
Simple timeout integration (backwards compatibility)
IntegrationResult integrate_with_timeout(state_type &state, time_type dt, time_type end_time)
Perform timeout-protected integration.
TimeoutIntegrator(Integrator integrator, TimeoutConfig config={})
Construct timeout integrator with an existing integrator.
TimeoutIntegrator(TimeoutConfig config, Args &&... args)
Construct timeout integrator with integrator parameters.
Integrator & integrator()
Access the underlying integrator.
TimeoutConfig & config()
Access timeout configuration.
Result of a timeout-enabled integration.
Configuration for timeout-enabled integration.
Timeout configuration for integration protection.