DiffEq - Modern C++ ODE Integration Library 1.0.0
High-performance C++ library for solving ODEs with async signal processing
Loading...
Searching...
No Matches
integration_interface.hpp
1#pragma once
2
3#include <core/concepts.hpp>
4#include <signal/signal_processor.hpp>
5#include <functional>
6#include <memory>
7#include <vector>
8#include <chrono>
9#include <optional>
10#include <any>
11
12namespace diffeq::interfaces {
13
23template<system_state StateType, can_be_time TimeType>
25public:
26 using state_type = StateType;
27 using time_type = TimeType;
29
33 enum class InfluenceMode {
34 DISCRETE_EVENT, // Signal causes instantaneous state jump
35 CONTINUOUS_SHIFT, // Signal modifies ODE trajectory continuously
36 PARAMETER_UPDATE, // Signal updates integration parameters
37 OUTPUT_TRIGGER // Signal triggers output/logging
38 };
39
44 InfluenceMode mode;
45 std::string signal_type;
46 std::function<void(const std::any&, state_type&, time_type)> handler;
47 double priority = 1.0;
48 bool is_active = true;
49 };
50
54 struct OutputStream {
55 std::string stream_id;
56 std::function<void(const state_type&, time_type)> output_func;
57 std::chrono::microseconds interval{1000}; // Output frequency
58 std::chrono::steady_clock::time_point last_output;
59 bool is_active = true;
60 };
61
62private:
63 std::shared_ptr<signal_processor_type> signal_processor_;
64 std::vector<SignalInfluence> signal_influences_;
65 std::vector<OutputStream> output_streams_;
66
67 // Current integration state
68 std::optional<state_type> current_state_;
69 time_type current_time_ = {};
70
71 // Trajectory modification functions
72 std::vector<std::function<void(time_type, state_type&, state_type&)>> trajectory_modifiers_;
73
74public:
75 explicit IntegrationInterface(std::shared_ptr<signal_processor_type> processor = nullptr)
76 : signal_processor_(processor ? processor : signal::make_signal_processor<StateType>()) {
77 setup_signal_handling();
78 }
79
83 template<typename SignalDataType>
85 std::string_view signal_type,
86 InfluenceMode mode,
87 std::function<void(const SignalDataType&, state_type&, time_type)> handler,
88 double priority = 1.0) {
89
90 SignalInfluence influence{
91 .mode = mode,
92 .signal_type = std::string(signal_type),
93 .handler = [h = std::move(handler)](const std::any& signal_data, state_type& state, time_type t) {
94 try {
95 const auto& typed_data = std::any_cast<const SignalDataType&>(signal_data);
96 h(typed_data, state, t);
97 } catch (const std::bad_any_cast&) {
98 // Type mismatch - ignore silently
99 }
100 },
101 .priority = priority,
102 .is_active = true
103 };
104
105 signal_influences_.push_back(std::move(influence));
106
107 // Register with signal processor
108 signal_processor_->template register_handler<SignalDataType>(signal_type,
109 [this, signal_type_str = std::string(signal_type)](const signal::Signal<SignalDataType>& sig) {
110 handle_signal(signal_type_str, sig.data);
111 });
112 }
113
118 std::string_view stream_id,
119 std::function<void(const state_type&, time_type)> output_func,
120 std::chrono::microseconds interval = std::chrono::microseconds{1000}) {
121
122 OutputStream stream{
123 .stream_id = std::string(stream_id),
124 .output_func = std::move(output_func),
125 .interval = interval,
126 .last_output = std::chrono::steady_clock::now(),
127 .is_active = true
128 };
129
130 output_streams_.push_back(std::move(stream));
131 }
132
140 std::function<void(time_type, state_type&, state_type&)> modifier) {
141 trajectory_modifiers_.push_back(std::move(modifier));
142 }
143
150 template<typename OriginalODE>
151 auto make_signal_aware_ode(OriginalODE&& original_ode) {
152 return [this, ode = std::forward<OriginalODE>(original_ode)]
153 (time_type t, const state_type& y, state_type& dydt) {
154
155 // Update current state for signal handling
156 current_state_ = y;
157 current_time_ = t;
158
159 // Compute original dynamics
160 ode(t, y, dydt);
161
162 // Apply trajectory modifiers from continuous signal influences
163 state_type modified_state = y;
164 for (auto& modifier : trajectory_modifiers_) {
165 modifier(t, modified_state, dydt);
166 }
167
168 // Handle real-time outputs
169 process_output_streams(y, t);
170 };
171 }
172
176 void apply_discrete_event(const std::string& signal_type, const std::any& signal_data) {
177 if (!current_state_) return;
178
179 for (auto& influence : signal_influences_) {
180 if (influence.signal_type == signal_type &&
181 influence.mode == InfluenceMode::DISCRETE_EVENT &&
182 influence.is_active) {
183
184 influence.handler(signal_data, *current_state_, current_time_);
185 }
186 }
187 }
188
192 std::optional<state_type> get_current_state() const {
193 return current_state_;
194 }
195
199 time_type get_current_time() const {
200 return current_time_;
201 }
202
206 void set_signal_influence_active(const std::string& signal_type, bool active) {
207 for (auto& influence : signal_influences_) {
208 if (influence.signal_type == signal_type) {
209 influence.is_active = active;
210 }
211 }
212 }
213
217 void set_output_stream_active(const std::string& stream_id, bool active) {
218 for (auto& stream : output_streams_) {
219 if (stream.stream_id == stream_id) {
220 stream.is_active = active;
221 }
222 }
223 }
224
228 std::shared_ptr<signal_processor_type> get_signal_processor() {
229 return signal_processor_;
230 }
231
232private:
233 void setup_signal_handling() {
234 // Basic signal handling is set up when influences are registered
235 }
236
237 void handle_signal(const std::string& signal_type, const std::any& signal_data) {
238 // Handle different influence modes
239 for (auto& influence : signal_influences_) {
240 if (influence.signal_type == signal_type && influence.is_active) {
241
242 if (influence.mode == InfluenceMode::DISCRETE_EVENT && current_state_) {
243 // Apply immediate state modification
244 influence.handler(signal_data, *current_state_, current_time_);
245
246 } else if (influence.mode == InfluenceMode::CONTINUOUS_SHIFT) {
247 // Add to trajectory modifiers for continuous influence
248 add_trajectory_modifier([influence, signal_data]
249 (time_type t, state_type& state, state_type& /* dydt */) {
250 influence.handler(signal_data, state, t);
251 });
252
253 } else if (influence.mode == InfluenceMode::PARAMETER_UPDATE) {
254 // Handle parameter updates (integrator-specific)
255 if (current_state_) {
256 influence.handler(signal_data, *current_state_, current_time_);
257 }
258
259 } else if (influence.mode == InfluenceMode::OUTPUT_TRIGGER && current_state_) {
260 // Trigger immediate output
261 for (auto& stream : output_streams_) {
262 if (stream.is_active) {
263 stream.output_func(*current_state_, current_time_);
264 }
265 }
266 }
267 }
268 }
269 }
270
271 void process_output_streams(const state_type& state, time_type t) {
272 auto now = std::chrono::steady_clock::now();
273
274 for (auto& stream : output_streams_) {
275 if (!stream.is_active) continue;
276
277 if (now - stream.last_output >= stream.interval) {
278 stream.output_func(state, t);
279 stream.last_output = now;
280 }
281 }
282 }
283};
284
288template<system_state StateType, can_be_time TimeType = double>
289auto make_integration_interface(
290 std::shared_ptr<signal::SignalProcessor<StateType>> processor) {
291 return std::make_unique<IntegrationInterface<StateType, TimeType>>(processor);
292}
293
297template<system_state StateType, can_be_time TimeType = double>
298auto make_integration_interface() {
299 return std::make_unique<IntegrationInterface<StateType, TimeType>>();
300}
301
302} // namespace diffeq::interfaces
General interface for ODE integration with real-time signal processing.
void register_signal_influence(std::string_view signal_type, InfluenceMode mode, std::function< void(const SignalDataType &, state_type &, time_type)> handler, double priority=1.0)
Register a signal influence on the ODE system.
time_type get_current_time() const
Get current time.
std::optional< state_type > get_current_state() const
Get current integration state.
void apply_discrete_event(const std::string &signal_type, const std::any &signal_data)
Process discrete events (instantaneous state modifications)
void add_trajectory_modifier(std::function< void(time_type, state_type &, state_type &)> modifier)
Add a continuous trajectory modifier.
std::shared_ptr< signal_processor_type > get_signal_processor()
Get signal processor for direct access.
void set_output_stream_active(const std::string &stream_id, bool active)
Enable/disable output stream.
void set_signal_influence_active(const std::string &signal_type, bool active)
Enable/disable signal influence.
void register_output_stream(std::string_view stream_id, std::function< void(const state_type &, time_type)> output_func, std::chrono::microseconds interval=std::chrono::microseconds{1000})
Register an output stream for real-time data export.
auto make_signal_aware_ode(OriginalODE &&original_ode)
ODE system wrapper that incorporates signal influences.
Generic signal data structure.