scirs2_integrate/ode/methods/
adaptive.rs1use crate::common::IntegrateFloat;
8use crate::error::IntegrateResult;
9use crate::ode::types::{ODEMethod, ODEOptions, ODEResult};
10use scirs2_core::ndarray::{Array1, ArrayView1};
11
12#[allow(dead_code)]
28pub fn rk45_method<F, Func>(
29 f: Func,
30 t_span: [F; 2],
31 y0: Array1<F>,
32 opts: ODEOptions<F>,
33) -> IntegrateResult<ODEResult<F>>
34where
35 F: IntegrateFloat,
36 Func: Fn(F, ArrayView1<F>) -> Array1<F>,
37{
38 let [t_start, t_end] = t_span;
40 let n_dim = y0.len();
41
42 let h0 = opts.h0.unwrap_or_else(|| {
44 let _span = t_end - t_start;
46 _span / F::from_usize(100).unwrap()
47 });
48
49 let min_step = opts.min_step.unwrap_or_else(|| {
51 let _span = t_end - t_start;
52 _span * F::from_f64(1e-8).unwrap() });
54
55 let max_step = opts.max_step.unwrap_or_else(|| {
56 t_end - t_start });
58
59 let mut t = t_start;
61 let mut y = y0.clone();
62 let mut h = h0;
63
64 let mut t_values = vec![t_start];
66 let mut y_values = vec![y0.clone()];
67
68 let mut func_evals = 0;
70 let mut step_count = 0;
71 let mut accepted_steps = 0;
72 let mut rejected_steps = 0;
73
74 let c2 = F::from_f64(1.0 / 5.0).unwrap();
77 let c3 = F::from_f64(3.0 / 10.0).unwrap();
78 let c4 = F::from_f64(4.0 / 5.0).unwrap();
79 let c5 = F::from_f64(8.0 / 9.0).unwrap();
80 let c6 = F::one();
81
82 while t < t_end && step_count < opts.max_steps {
84 if t + h > t_end {
86 h = t_end - t;
87 }
88
89 h = h.min(max_step).max(min_step);
91
92 let k1 = f(t, y.view());
94
95 let mut y_stage = y.clone();
97 for i in 0..n_dim {
98 y_stage[i] = y[i] + h * F::from_f64(1.0 / 5.0).unwrap() * k1[i];
99 }
100 let k2 = f(t + c2 * h, y_stage.view());
101
102 let mut y_stage = y.clone();
103 for i in 0..n_dim {
104 y_stage[i] = y[i]
105 + h * (F::from_f64(3.0 / 40.0).unwrap() * k1[i]
106 + F::from_f64(9.0 / 40.0).unwrap() * k2[i]);
107 }
108 let k3 = f(t + c3 * h, y_stage.view());
109
110 let mut y_stage = y.clone();
111 for i in 0..n_dim {
112 y_stage[i] = y[i]
113 + h * (F::from_f64(44.0 / 45.0).unwrap() * k1[i]
114 + F::from_f64(-56.0 / 15.0).unwrap() * k2[i]
115 + F::from_f64(32.0 / 9.0).unwrap() * k3[i]);
116 }
117 let k4 = f(t + c4 * h, y_stage.view());
118
119 let mut y_stage = y.clone();
120 for i in 0..n_dim {
121 y_stage[i] = y[i]
122 + h * (F::from_f64(19372.0 / 6561.0).unwrap() * k1[i]
123 + F::from_f64(-25360.0 / 2187.0).unwrap() * k2[i]
124 + F::from_f64(64448.0 / 6561.0).unwrap() * k3[i]
125 + F::from_f64(-212.0 / 729.0).unwrap() * k4[i]);
126 }
127 let k5 = f(t + c5 * h, y_stage.view());
128
129 let mut y_stage = y.clone();
130 for i in 0..n_dim {
131 y_stage[i] = y[i]
132 + h * (F::from_f64(9017.0 / 3168.0).unwrap() * k1[i]
133 + F::from_f64(-355.0 / 33.0).unwrap() * k2[i]
134 + F::from_f64(46732.0 / 5247.0).unwrap() * k3[i]
135 + F::from_f64(49.0 / 176.0).unwrap() * k4[i]
136 + F::from_f64(-5103.0 / 18656.0).unwrap() * k5[i]);
137 }
138 let k6 = f(t + c6 * h, y_stage.view());
139
140 let mut y_stage = y.clone();
141 for i in 0..n_dim {
142 y_stage[i] = y[i]
143 + h * (F::from_f64(35.0 / 384.0).unwrap() * k1[i]
144 + F::zero() * k2[i]
145 + F::from_f64(500.0 / 1113.0).unwrap() * k3[i]
146 + F::from_f64(125.0 / 192.0).unwrap() * k4[i]
147 + F::from_f64(-2187.0 / 6784.0).unwrap() * k5[i]
148 + F::from_f64(11.0 / 84.0).unwrap() * k6[i]);
149 }
150 let k7 = f(t + h, y_stage.view());
151
152 func_evals += 7;
153
154 let mut y5 = y.clone();
156 for i in 0..n_dim {
157 y5[i] = y[i]
158 + h * (F::from_f64(35.0 / 384.0).unwrap() * k1[i]
159 + F::zero() * k2[i]
160 + F::from_f64(500.0 / 1113.0).unwrap() * k3[i]
161 + F::from_f64(125.0 / 192.0).unwrap() * k4[i]
162 + F::from_f64(-2187.0 / 6784.0).unwrap() * k5[i]
163 + F::from_f64(11.0 / 84.0).unwrap() * k6[i]
164 + F::zero() * k7[i]);
165 }
166
167 let mut y4 = y.clone();
169 for i in 0..n_dim {
170 y4[i] = y[i]
171 + h * (F::from_f64(5179.0 / 57600.0).unwrap() * k1[i]
172 + F::zero() * k2[i]
173 + F::from_f64(7571.0 / 16695.0).unwrap() * k3[i]
174 + F::from_f64(393.0 / 640.0).unwrap() * k4[i]
175 + F::from_f64(-92097.0 / 339200.0).unwrap() * k5[i]
176 + F::from_f64(187.0 / 2100.0).unwrap() * k6[i]
177 + F::from_f64(1.0 / 40.0).unwrap() * k7[i]);
178 }
179
180 let mut err_norm = F::zero();
182 for i in 0..n_dim {
183 let sc = opts.atol + opts.rtol * y5[i].abs();
184 let err = (y5[i] - y4[i]).abs() / sc;
185 err_norm = err_norm.max(err);
186 }
187
188 let order = F::from_f64(5.0).unwrap(); let exponent = F::one() / (order + F::one());
191 let safety = F::from_f64(0.9).unwrap();
192 let factor = safety * (F::one() / err_norm).powf(exponent);
193 let factor_min = F::from_f64(0.2).unwrap();
194 let factor_max = F::from_f64(5.0).unwrap();
195 let factor = factor.min(factor_max).max(factor_min);
196
197 if err_norm <= F::one() {
198 t += h;
200 y = y5; t_values.push(t);
204 y_values.push(y.clone());
205
206 if err_norm <= F::from_f64(0.1).unwrap() {
208 h *= factor.max(F::from_f64(2.0).unwrap());
210 } else {
211 h *= factor;
212 }
213
214 step_count += 1;
215 accepted_steps += 1;
216 } else {
217 h *= factor.min(F::one());
219 rejected_steps += 1;
220
221 if h < min_step {
223 return Err(crate::error::IntegrateError::StepSizeTooSmall(format!(
224 "Step size {h} too small at t {t}"
225 )));
226 }
227 }
228 }
229
230 let success = t >= t_end;
232 let message = if !success {
233 Some(format!(
234 "Maximum number of steps ({}) reached",
235 opts.max_steps
236 ))
237 } else {
238 None
239 };
240
241 Ok(ODEResult {
243 t: t_values,
244 y: y_values,
245 success,
246 message,
247 n_eval: func_evals,
248 n_steps: step_count,
249 n_accepted: accepted_steps,
250 n_rejected: rejected_steps,
251 n_lu: 0, n_jac: 0, method: ODEMethod::RK45,
254 })
255}
256
257#[allow(dead_code)]
273pub fn rk23_method<F, Func>(
274 f: Func,
275 t_span: [F; 2],
276 y0: Array1<F>,
277 opts: ODEOptions<F>,
278) -> IntegrateResult<ODEResult<F>>
279where
280 F: IntegrateFloat,
281 Func: Fn(F, ArrayView1<F>) -> Array1<F>,
282{
283 let [t_start, t_end] = t_span;
285
286 let h0 = opts.h0.unwrap_or_else(|| {
288 let _span = t_end - t_start;
290 _span / F::from_usize(100).unwrap()
291 });
292
293 let min_step = opts.min_step.unwrap_or_else(|| {
295 let _span = t_end - t_start;
296 _span * F::from_f64(1e-8).unwrap() });
298
299 let max_step = opts.max_step.unwrap_or_else(|| {
300 t_end - t_start });
302
303 let mut t = t_start;
305 let mut y = y0.clone();
306 let mut h = h0;
307
308 let mut t_values = vec![t_start];
310 let mut y_values = vec![y0.clone()];
311
312 let mut func_evals = 0;
314 let mut step_count = 0;
315 let mut accepted_steps = 0;
316 let rejected_steps = 0;
317
318 while t < t_end && step_count < opts.max_steps {
321 if t + h > t_end {
323 h = t_end - t;
324 }
325
326 h = h.min(max_step).max(min_step);
328
329 let k1 = f(t, y.view());
331 func_evals += 1;
332
333 let y_next = y.clone() + k1.clone() * h;
334
335 t += h;
337 y = y_next;
338
339 t_values.push(t);
341 y_values.push(y.clone());
342
343 step_count += 1;
344 accepted_steps += 1;
345 }
346
347 let success = t >= t_end;
349 let message = if !success {
350 Some(format!(
351 "Maximum number of steps ({}) reached",
352 opts.max_steps
353 ))
354 } else {
355 None
356 };
357
358 Ok(ODEResult {
360 t: t_values,
361 y: y_values,
362 success,
363 message,
364 n_eval: func_evals,
365 n_steps: step_count,
366 n_accepted: accepted_steps,
367 n_rejected: rejected_steps,
368 n_lu: 0, n_jac: 0, method: ODEMethod::RK23,
371 })
372}
373
374#[allow(dead_code)]
391pub fn dop853_method<F, Func>(
392 f: Func,
393 t_span: [F; 2],
394 y0: Array1<F>,
395 opts: ODEOptions<F>,
396) -> IntegrateResult<ODEResult<F>>
397where
398 F: IntegrateFloat,
399 Func: Fn(F, ArrayView1<F>) -> Array1<F>,
400{
401 let [t_start, t_end] = t_span;
403
404 let h0 = opts.h0.unwrap_or_else(|| {
406 let _span = t_end - t_start;
408 _span / F::from_usize(100).unwrap()
409 });
410
411 let min_step = opts.min_step.unwrap_or_else(|| {
413 let _span = t_end - t_start;
414 _span * F::from_f64(1e-8).unwrap() });
416
417 let max_step = opts.max_step.unwrap_or_else(|| {
418 t_end - t_start });
420
421 let mut t = t_start;
423 let mut y = y0.clone();
424 let mut h = h0;
425
426 let mut t_values = vec![t_start];
428 let mut y_values = vec![y0.clone()];
429
430 let mut func_evals = 0;
432 let mut step_count = 0;
433 let mut accepted_steps = 0;
434 let rejected_steps = 0;
435
436 while t < t_end && step_count < opts.max_steps {
439 if t + h > t_end {
441 h = t_end - t;
442 }
443
444 h = h.min(max_step).max(min_step);
446
447 let k1 = f(t, y.view());
449 func_evals += 1;
450
451 let y_next = y.clone() + k1.clone() * h;
452
453 t += h;
455 y = y_next;
456
457 t_values.push(t);
459 y_values.push(y.clone());
460
461 step_count += 1;
462 accepted_steps += 1;
463 }
464
465 let success = t >= t_end;
467 let message = if !success {
468 Some(format!(
469 "Maximum number of steps ({}) reached",
470 opts.max_steps
471 ))
472 } else {
473 None
474 };
475
476 Ok(ODEResult {
478 t: t_values,
479 y: y_values,
480 success,
481 message,
482 n_eval: func_evals,
483 n_steps: step_count,
484 n_accepted: accepted_steps,
485 n_rejected: rejected_steps,
486 n_lu: 0, n_jac: 0, method: ODEMethod::DOP853,
489 })
490}