DiffEq - Modern C++ ODE Integration Library 1.0.0
High-performance C++ library for solving ODEs with async signal processing
Loading...
Searching...
No Matches
advanced_integrators_usage.cpp
1#include <iostream>
2#include <vector>
3#include <array>
4#include <iomanip>
5#include <chrono>
6
7// Include modern diffeq library
8#include <diffeq.hpp>
9
10// Test systems
11
12// 1. Simple exponential decay: dy/dt = -y
13void exponential_decay(double t, const std::vector<double>& y, std::vector<double>& dydt) {
14 dydt[0] = -y[0];
15}
16
17// 2. Van der Pol oscillator: d^2x/dt^2 - mu*(1-x^2)*dx/dt + x = 0
19public:
20 explicit VanderPolOscillator(double mu) : mu_(mu) {}
21
22 void operator()(double t, const std::vector<double>& y, std::vector<double>& dydt) {
23 dydt[0] = y[1]; // dx/dt = v
24 dydt[1] = mu_ * (1 - y[0]*y[0]) * y[1] - y[0]; // dv/dt = mu*(1-x^2)*v - x
25 }
26
27private:
28 double mu_;
29};
30
31// 3. Lorenz system (chaotic)
32void lorenz_system(double t, const std::vector<double>& y, std::vector<double>& dydt) {
33 const double sigma = 10.0;
34 const double rho = 28.0;
35 const double beta = 8.0/3.0;
36
37 dydt[0] = sigma * (y[1] - y[0]); // dx/dt = sigma*(y - x)
38 dydt[1] = y[0] * (rho - y[2]) - y[1]; // dy/dt = x*(rho - z) - y
39 dydt[2] = y[0] * y[1] - beta * y[2]; // dz/dt = xy - beta*z
40}
41
42// 4. Stiff test problem: Robertson chemical kinetics
43void robertson_kinetics(double t, const std::vector<double>& y, std::vector<double>& dydt) {
44 const double k1 = 0.04;
45 const double k2 = 3e7;
46 const double k3 = 1e4;
47
48 dydt[0] = -k1 * y[0] + k3 * y[1] * y[2]; // dA/dt
49 dydt[1] = k1 * y[0] - k2 * y[1] * y[1] - k3 * y[1] * y[2]; // dB/dt
50 dydt[2] = k2 * y[1] * y[1]; // dC/dt
51}
52
53// Helper function to time integrator performance
54template<typename Integrator>
55double time_integrator(Integrator& integrator, std::vector<double>& y,
56 double t_start, double dt, double t_end, const std::string& name) {
57 auto start = std::chrono::high_resolution_clock::now();
58
59 integrator.set_time(t_start);
60
61 // Use timeout protection to prevent hanging
62 const std::chrono::seconds TIMEOUT{30}; // 30 second timeout for more complex integrators
63 bool completed = diffeq::integrate_with_timeout(integrator, y, dt, t_end, TIMEOUT);
64
65 auto end = std::chrono::high_resolution_clock::now();
66 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
67
68 std::cout << std::setw(15) << name << ": y = [";
69 for (size_t i = 0; i < y.size(); ++i) {
70 std::cout << std::setw(12) << std::scientific << std::setprecision(4) << y[i];
71 if (i < y.size() - 1) std::cout << ", ";
72 }
73 std::cout << "] (Time: " << duration.count() << " us)";
74
75 if (!completed) {
76 std::cout << " [TIMEOUT]";
77 }
78 std::cout << std::endl;
79
80 return static_cast<double>(duration.count());
81}
82
83void demonstrate_exponential_decay() {
84 std::cout << "\n=== Exponential Decay: dy/dt = -y, y(0) = 1 ===" << std::endl;
85 std::cout << "Analytical solution: y(t) = exp(-t)" << std::endl;
86 std::cout << "At t = 1: y(1) = " << std::exp(-1.0) << std::endl << std::endl;
87
88 double t_start = 0.0, t_end = 1.0, dt = 0.1;
89
90 // Test all integrators
91 {
92 std::vector<double> y = {1.0};
93 diffeq::RK4Integrator<std::vector<double>> integrator(exponential_decay);
94 time_integrator(integrator, y, t_start, dt, t_end, "RK4");
95 }
96
97 {
98 std::vector<double> y = {1.0};
99 diffeq::RK23Integrator<std::vector<double>> integrator(exponential_decay, 1e-6, 1e-9);
100 time_integrator(integrator, y, t_start, dt, t_end, "RK23");
101 }
102
103 {
104 std::vector<double> y = {1.0};
105 diffeq::RK45Integrator<std::vector<double>> integrator(exponential_decay, 1e-8, 1e-12);
106 time_integrator(integrator, y, t_start, dt, t_end, "RK45");
107 }
108
109 {
110 std::vector<double> y = {1.0};
111 diffeq::DOP853Integrator<std::vector<double>> integrator(exponential_decay, 1e-3, 1e-6);
112 time_integrator(integrator, y, t_start, dt, t_end, "DOP853");
113 }
114
115 {
116 std::vector<double> y = {1.0};
117 diffeq::BDFIntegrator<std::vector<double>> integrator(exponential_decay, 1e-6, 1e-9);
118 time_integrator(integrator, y, t_start, dt, t_end, "BDF");
119 }
120
121 {
122 std::vector<double> y = {1.0};
123 diffeq::LSODAIntegrator<std::vector<double>> integrator(exponential_decay, 1e-6, 1e-9);
124 time_integrator(integrator, y, t_start, dt, t_end, "LSODA");
125 }
126}
127
128void demonstrate_van_der_pol() {
129 std::cout << "\n=== Van der Pol Oscillator: mu = 5 (moderately stiff) ===" << std::endl;
130 std::cout << "x''(t) - mu*(1-x^2)*x'(t) + x(t) = 0" << std::endl;
131 std::cout << "Initial conditions: x(0) = 1, x'(0) = 0" << std::endl << std::endl;
132
133 VanderPolOscillator vdp(5.0);
134 double t_start = 0.0, t_end = 10.0, dt = 0.1;
135
136 {
137 std::vector<double> y = {1.0, 0.0};
139 [&vdp](double t, const std::vector<double>& y, std::vector<double>& dydt) {
140 vdp(t, y, dydt);
141 });
142 time_integrator(integrator, y, t_start, dt, t_end, "RK4");
143 }
144
145 {
146 std::vector<double> y = {1.0, 0.0};
148 [&vdp](double t, const std::vector<double>& y, std::vector<double>& dydt) {
149 vdp(t, y, dydt);
150 }, 1e-6, 1e-9);
151 time_integrator(integrator, y, t_start, dt, t_end, "RK45");
152 }
153
154 // Note: RadauIntegrator not implemented in current hierarchy
155 // {
156 // std::vector<double> y = {1.0, 0.0};
157 // RadauIntegrator<std::vector<double>> integrator(
158 // [&vdp](double t, const std::vector<double>& y, std::vector<double>& dydt) {
159 // vdp(t, y, dydt);
160 // }, 1e-6, 1e-9);
161 // time_integrator(integrator, y, t_start, dt, t_end, "Radau");
162 // }
163
164 {
165 std::vector<double> y = {1.0, 0.0};
167 [&vdp](double t, const std::vector<double>& y, std::vector<double>& dydt) {
168 vdp(t, y, dydt);
169 }, 1e-6, 1e-9);
170 time_integrator(integrator, y, t_start, dt, t_end, "BDF");
171 }
172
173 {
174 std::vector<double> y = {1.0, 0.0};
176 [&vdp](double t, const std::vector<double>& y, std::vector<double>& dydt) {
177 vdp(t, y, dydt);
178 }, 1e-6, 1e-9);
179 double timing = time_integrator(integrator, y, t_start, dt, t_end, "LSODA");
180 std::cout << " Final method: " <<
181 (integrator.get_current_method() == diffeq::LSODAIntegrator<std::vector<double>>::MethodType::ADAMS ?
182 "Adams (non-stiff)" : "BDF (stiff)") << std::endl;
183 }
184}
185
186void demonstrate_lorenz_system() {
187 std::cout << "\n=== Lorenz System (Chaotic) ===" << std::endl;
188 std::cout << "dx/dt = sigma*(y - x), dy/dt = x*(rho - z) - y, dz/dt = xy - beta*z" << std::endl;
189 std::cout << "sigma = 10, rho = 28, beta = 8/3" << std::endl;
190 std::cout << "Initial conditions: x(0) = 1, y(0) = 1, z(0) = 1" << std::endl << std::endl;
191
192 double t_start = 0.0, t_end = 0.5, dt = 0.01; // Reduced from 5.0 to 0.5 for faster execution
193
194 {
195 std::vector<double> y = {1.0, 1.0, 1.0};
196 diffeq::RK4Integrator<std::vector<double>> integrator(lorenz_system);
197 time_integrator(integrator, y, t_start, dt, t_end, "RK4");
198 }
199
200 {
201 std::vector<double> y = {1.0, 1.0, 1.0};
202 diffeq::RK45Integrator<std::vector<double>> integrator(lorenz_system, 1e-6, 1e-9); // Relaxed tolerances
203 time_integrator(integrator, y, t_start, dt, t_end, "RK45");
204 }
205
206 {
207 std::vector<double> y = {1.0, 1.0, 1.0};
208 diffeq::DOP853Integrator<std::vector<double>> integrator(lorenz_system, 1e-6, 1e-9); // Relaxed tolerances
209 time_integrator(integrator, y, t_start, dt, t_end, "DOP853");
210 }
211
212 {
213 std::vector<double> y = {1.0, 1.0, 1.0};
214 diffeq::LSODAIntegrator<std::vector<double>> integrator(lorenz_system, 1e-6, 1e-9); // Relaxed tolerances
215 time_integrator(integrator, y, t_start, dt, t_end, "LSODA");
216 }
217}
218
219void demonstrate_stiff_robertson() {
220 std::cout << "\n=== Robertson Chemical Kinetics (Very Stiff) ===" << std::endl;
221 std::cout << "A -> B (k1 = 0.04)" << std::endl;
222 std::cout << "B + B -> B + C (k2 = 3e7)" << std::endl;
223 std::cout << "B + C -> A + C (k3 = 1e4)" << std::endl;
224 std::cout << "Initial conditions: A(0) = 1, B(0) = 0, C(0) = 0" << std::endl << std::endl;
225
226 double t_start = 0.0, t_end = 1.0, dt = 0.1; // Much shorter time scale for demo
227
228 std::cout << "Note: This is a very stiff system. Explicit methods may fail or be very slow." << std::endl;
229 std::cout << "Using shortened time range (t=1.0) for demonstration purposes." << std::endl;
230
231 // Only test implicit methods for this stiff system
232 // Note: RadauIntegrator not implemented in current hierarchy
233 // try {
234 // std::vector<double> y = {1.0, 0.0, 0.0};
235 // RadauIntegrator<std::vector<double>> integrator(robertson_kinetics, 1e-6, 1e-9);
236 // time_integrator(integrator, y, t_start, dt, t_end, "Radau");
237 // } catch (const std::exception& e) {
238 // std::cout << std::setw(15) << "Radau" << ": Failed - " << e.what() << std::endl;
239 // }
240
241 try {
242 std::vector<double> y = {1.0, 0.0, 0.0};
243 diffeq::BDFIntegrator<std::vector<double>> integrator(robertson_kinetics, 1e-6, 1e-9);
244 time_integrator(integrator, y, t_start, dt, t_end, "BDF");
245 } catch (const std::exception& e) {
246 std::cout << std::setw(15) << "BDF" << ": Failed - " << e.what() << std::endl;
247 }
248
249 try {
250 std::vector<double> y = {1.0, 0.0, 0.0};
251 diffeq::LSODAIntegrator<std::vector<double>> integrator(robertson_kinetics, 1e-6, 1e-9);
252 double timing = time_integrator(integrator, y, t_start, dt, t_end, "LSODA");
253 std::cout << " Final method: " <<
254 (integrator.get_current_method() == diffeq::LSODAIntegrator<std::vector<double>>::MethodType::ADAMS ?
255 "Adams (non-stiff)" : "BDF (stiff)") << std::endl;
256 } catch (const std::exception& e) {
257 std::cout << std::setw(15) << "LSODA" << ": Failed - " << e.what() << std::endl;
258 }
259}
260
261void demonstrate_adaptive_features() {
262 std::cout << "\n=== Adaptive Step Size Control Demonstration ===" << std::endl;
263 std::cout << "Using RK45 with different tolerance levels on exponential decay" << std::endl << std::endl;
264
265 double t_start = 0.0, t_end = 2.0, dt = 0.1;
266
267 std::vector<std::pair<double, double>> tolerances = {
268 {1e-3, 1e-6},
269 {1e-6, 1e-9},
270 {1e-8, 1e-11} // Removed extremely tight tolerances to prevent timeout
271 };
272
273 for (auto [rtol, atol] : tolerances) {
274 std::vector<double> y = {1.0};
275 diffeq::RK45Integrator<std::vector<double>> integrator(exponential_decay, rtol, atol);
276
277 std::cout << "Tolerances: rtol = " << rtol << ", atol = " << atol << std::endl;
278 time_integrator(integrator, y, t_start, dt, t_end, "RK45");
279
280 double exact = std::exp(-t_end);
281 double error = std::abs(y[0] - exact);
282 std::cout << " Error: " << std::scientific << error << std::endl << std::endl;
283 }
284}
285
286int main() {
287 std::cout << "Advanced ODE Integrators Demonstration" << std::endl;
288 std::cout << "======================================" << std::endl;
289
290 try {
291 demonstrate_exponential_decay();
292 demonstrate_van_der_pol();
293 demonstrate_lorenz_system();
294 demonstrate_stiff_robertson();
295 demonstrate_adaptive_features();
296
297 std::cout << "\n=== Summary ===" << std::endl;
298 std::cout << "[OK] RK4: Simple, fixed-step 4th order method" << std::endl;
299 std::cout << "[OK] RK23: Adaptive 3rd order with embedded error estimation" << std::endl;
300 std::cout << "[OK] RK45: Adaptive 5th order Dormand-Prince (scipy default)" << std::endl;
301 std::cout << "[OK] DOP853: High-accuracy 8th order for demanding problems" << std::endl;
302 std::cout << "- Radau: Implicit 5th order for stiff systems (not yet implemented)" << std::endl;
303 std::cout << "[OK] BDF: Variable-order implicit multistep for stiff systems" << std::endl;
304 std::cout << "[OK] LSODA: Automatic method switching (Adams <-> BDF)" << std::endl;
305
306 } catch (const std::exception& e) {
307 std::cerr << "Error: " << e.what() << std::endl;
308 return 1;
309 }
310
311 return 0;
312}
BDF (Backward Differentiation Formula) integrator.
Definition bdf.hpp:35
DOP853 (Dormand-Prince 8(5,3)) adaptive integrator.
Definition dop853.hpp:51
LSODA integrator - automatically switches between stiff and non-stiff methods.
Definition lsoda.hpp:20
RK23 (Bogacki-Shampine) adaptive integrator.
Definition rk23.hpp:21
RK45 (Runge-Kutta-Fehlberg 4(5)) adaptive integrator.
Definition rk45.hpp:20
Classical 4th-order Runge-Kutta integrator.
Definition rk4.hpp:19
Modern C++ ODE Integration Library with Real-time Signal Processing.