conspire/math/integrate/verner_8/
mod.rs1#[cfg(test)]
2mod test;
3
4use super::{
5 super::{
6 Tensor, TensorArray, TensorRank0, TensorVec, Vector, interpolate::InterpolateSolution,
7 },
8 Explicit, IntegrationError,
9};
10use crate::{ABS_TOL, REL_TOL};
11use std::ops::{Mul, Sub};
12
13const C_2: TensorRank0 = 0.05;
14const C_3: TensorRank0 = 0.1065625;
15const C_4: TensorRank0 = 0.15984375;
16const C_5: TensorRank0 = 0.39;
17const C_6: TensorRank0 = 0.465;
18const C_7: TensorRank0 = 0.155;
19const C_8: TensorRank0 = 0.943;
20const C_9: TensorRank0 = 0.901802041735857;
21const C_10: TensorRank0 = 0.909;
22const C_11: TensorRank0 = 0.94;
23
24const A_2_1: TensorRank0 = 0.05;
25const A_3_1: TensorRank0 = -0.0069931640625;
26const A_3_2: TensorRank0 = 0.1135556640625;
27const A_4_1: TensorRank0 = 0.0399609375;
28const A_4_3: TensorRank0 = 0.1198828125;
29const A_5_1: TensorRank0 = 0.36139756280045754;
30const A_5_3: TensorRank0 = -1.3415240667004928;
31const A_5_4: TensorRank0 = 1.3701265039000352;
32const A_6_1: TensorRank0 = 0.049047202797202795;
33const A_6_4: TensorRank0 = 0.23509720422144048;
34const A_6_5: TensorRank0 = 0.18085559298135673;
35const A_7_1: TensorRank0 = 0.06169289044289044;
36const A_7_4: TensorRank0 = 0.11236568314640277;
37const A_7_5: TensorRank0 = -0.03885046071451367;
38const A_7_6: TensorRank0 = 0.01979188712522046;
39const A_8_1: TensorRank0 = -1.767630240222327;
40const A_8_4: TensorRank0 = -62.5;
41const A_8_5: TensorRank0 = -6.061889377376669;
42const A_8_6: TensorRank0 = 5.6508231982227635;
43const A_8_7: TensorRank0 = 65.62169641937624;
44const A_9_1: TensorRank0 = -1.1809450665549708;
45const A_9_4: TensorRank0 = -41.50473441114321;
46const A_9_5: TensorRank0 = -4.434438319103725;
47const A_9_6: TensorRank0 = 4.260408188586133;
48const A_9_7: TensorRank0 = 43.75364022446172;
49const A_9_8: TensorRank0 = 0.00787142548991231;
50const A_10_1: TensorRank0 = -1.2814059994414884;
51const A_10_4: TensorRank0 = -45.047139960139866;
52const A_10_5: TensorRank0 = -4.731362069449576;
53const A_10_6: TensorRank0 = 4.514967016593808;
54const A_10_7: TensorRank0 = 47.44909557172985;
55const A_10_8: TensorRank0 = 0.01059228297111661;
56const A_10_9: TensorRank0 = -0.0057468422638446166;
57const A_11_1: TensorRank0 = -1.7244701342624853;
58const A_11_4: TensorRank0 = -60.92349008483054;
59const A_11_5: TensorRank0 = -5.951518376222392;
60const A_11_6: TensorRank0 = 5.556523730698456;
61const A_11_7: TensorRank0 = 63.98301198033305;
62const A_11_8: TensorRank0 = 0.014642028250414961;
63const A_11_9: TensorRank0 = 0.06460408772358203;
64const A_11_10: TensorRank0 = -0.0793032316900888;
65const A_12_1: TensorRank0 = -3.301622667747079;
66const A_12_4: TensorRank0 = -118.01127235975251;
67const A_12_5: TensorRank0 = -10.141422388456112;
68const A_12_6: TensorRank0 = 9.139311332232058;
69const A_12_7: TensorRank0 = 123.37594282840426;
70const A_12_8: TensorRank0 = 4.62324437887458;
71const A_12_9: TensorRank0 = -3.3832777380682018;
72const A_12_10: TensorRank0 = 4.527592100324618;
73const A_12_11: TensorRank0 = -5.828495485811623;
74const A_13_1: TensorRank0 = -3.039515033766309;
75const A_13_4: TensorRank0 = -109.26086808941763;
76const A_13_5: TensorRank0 = -9.290642497400293;
77const A_13_6: TensorRank0 = 8.43050498176491;
78const A_13_7: TensorRank0 = 114.20100103783314;
79const A_13_8: TensorRank0 = -0.9637271342145479;
80const A_13_9: TensorRank0 = -5.0348840888021895;
81const A_13_10: TensorRank0 = 5.958130824002923;
82
83const B_1: TensorRank0 = 0.04427989419007951;
84const B_6: TensorRank0 = 0.3541049391724449;
85const B_7: TensorRank0 = 0.24796921549564377;
86const B_8: TensorRank0 = -15.694202038838085;
87const B_9: TensorRank0 = 25.084064965558564;
88const B_10: TensorRank0 = -31.738367786260277;
89const B_11: TensorRank0 = 22.938283273988784;
90const B_12: TensorRank0 = -0.2361324633071542;
91
92const D_1: TensorRank0 = -0.00003272103901028138;
93const D_6: TensorRank0 = -0.0005046250618777704;
94const D_7: TensorRank0 = 0.0001211723589784759;
95const D_8: TensorRank0 = -20.142336771313868;
96const D_9: TensorRank0 = 5.2371785994398286;
97const D_10: TensorRank0 = -8.156744408794658;
98const D_11: TensorRank0 = 22.938283273988784;
99const D_12: TensorRank0 = -0.2361324633071542;
100const D_13: TensorRank0 = 0.36016794372897754;
101
102#[derive(Debug)]
122pub struct Verner8 {
123 pub abs_tol: TensorRank0,
125 pub rel_tol: TensorRank0,
127 pub dt_beta: TensorRank0,
129 pub dt_expn: TensorRank0,
131 pub dt_init: TensorRank0,
133}
134
135impl Default for Verner8 {
136 fn default() -> Self {
137 Self {
138 abs_tol: ABS_TOL,
139 rel_tol: REL_TOL,
140 dt_beta: 0.9,
141 dt_expn: 8.0,
142 dt_init: 0.1,
143 }
144 }
145}
146
147impl<Y, U> Explicit<Y, U> for Verner8
148where
149 Self: InterpolateSolution<Y, U>,
150 Y: Tensor + TensorArray,
151 for<'a> &'a Y: Mul<TensorRank0, Output = Y> + Sub<&'a Y, Output = Y>,
152 U: TensorVec<Item = Y>,
153{
154 fn integrate(
155 &self,
156 function: impl Fn(&TensorRank0, &Y) -> Y,
157 time: &[TensorRank0],
158 initial_condition: Y,
159 ) -> Result<(Vector, U), IntegrationError> {
160 if time.len() < 2 {
161 return Err(IntegrationError::LengthTimeLessThanTwo);
162 } else if time[0] >= time[time.len() - 1] {
163 return Err(IntegrationError::InitialTimeNotLessThanFinalTime);
164 }
165 let mut t = time[0];
166 let mut dt = self.dt_init * time[time.len() - 1];
167 let mut e;
168 let mut k_1;
169 let mut k_2;
170 let mut k_3;
171 let mut k_4;
172 let mut k_5;
173 let mut k_6;
174 let mut k_7;
175 let mut k_8;
176 let mut k_9;
177 let mut k_10;
178 let mut k_11;
179 let mut k_12;
180 let mut k_13;
181 let mut t_sol = Vector::zero(0);
182 t_sol.push(time[0]);
183 let mut y = initial_condition.clone();
184 let mut y_sol = U::zero(0);
185 y_sol.push(initial_condition.clone());
186 let mut y_trial;
187 while t < time[time.len() - 1] {
188 k_1 = function(&t, &y);
189 k_2 = function(&(t + C_2 * dt), &(&k_1 * (A_2_1 * dt) + &y));
190 k_3 = function(
191 &(t + C_3 * dt),
192 &(&k_1 * (A_3_1 * dt) + &k_2 * (A_3_2 * dt) + &y),
193 );
194 k_4 = function(
195 &(t + C_4 * dt),
196 &(&k_1 * (A_4_1 * dt) + &k_3 * (A_4_3 * dt) + &y),
197 );
198 k_5 = function(
199 &(t + C_5 * dt),
200 &(&k_1 * (A_5_1 * dt) + &k_3 * (A_5_3 * dt) + &k_4 * (A_5_4 * dt) + &y),
201 );
202 k_6 = function(
203 &(t + C_6 * dt),
204 &(&k_1 * (A_6_1 * dt) + &k_4 * (A_6_4 * dt) + &k_5 * (A_6_5 * dt) + &y),
205 );
206 k_7 = function(
207 &(t + C_7 * dt),
208 &(&k_1 * (A_7_1 * dt)
209 + &k_4 * (A_7_4 * dt)
210 + &k_5 * (A_7_5 * dt)
211 + &k_6 * (A_7_6 * dt)
212 + &y),
213 );
214 k_8 = function(
215 &(t + C_8 * dt),
216 &(&k_1 * (A_8_1 * dt)
217 + &k_4 * (A_8_4 * dt)
218 + &k_5 * (A_8_5 * dt)
219 + &k_6 * (A_8_6 * dt)
220 + &k_7 * (A_8_7 * dt)
221 + &y),
222 );
223 k_9 = function(
224 &(t + C_9 * dt),
225 &(&k_1 * (A_9_1 * dt)
226 + &k_4 * (A_9_4 * dt)
227 + &k_5 * (A_9_5 * dt)
228 + &k_6 * (A_9_6 * dt)
229 + &k_7 * (A_9_7 * dt)
230 + &k_8 * (A_9_8 * dt)
231 + &y),
232 );
233 k_10 = function(
234 &(t + C_10 * dt),
235 &(&k_1 * (A_10_1 * dt)
236 + &k_4 * (A_10_4 * dt)
237 + &k_5 * (A_10_5 * dt)
238 + &k_6 * (A_10_6 * dt)
239 + &k_7 * (A_10_7 * dt)
240 + &k_8 * (A_10_8 * dt)
241 + &k_9 * (A_10_9 * dt)
242 + &y),
243 );
244 k_11 = function(
245 &(t + C_11 * dt),
246 &(&k_1 * (A_11_1 * dt)
247 + &k_4 * (A_11_4 * dt)
248 + &k_5 * (A_11_5 * dt)
249 + &k_6 * (A_11_6 * dt)
250 + &k_7 * (A_11_7 * dt)
251 + &k_8 * (A_11_8 * dt)
252 + &k_9 * (A_11_9 * dt)
253 + &k_10 * (A_11_10 * dt)
254 + &y),
255 );
256 k_12 = function(
257 &(t + dt),
258 &(&k_1 * (A_12_1 * dt)
259 + &k_4 * (A_12_4 * dt)
260 + &k_5 * (A_12_5 * dt)
261 + &k_6 * (A_12_6 * dt)
262 + &k_7 * (A_12_7 * dt)
263 + &k_8 * (A_12_8 * dt)
264 + &k_9 * (A_12_9 * dt)
265 + &k_10 * (A_12_10 * dt)
266 + &k_11 * (A_12_11 * dt)
267 + &y),
268 );
269 y_trial = (&k_1 * B_1
270 + &k_6 * B_6
271 + &k_7 * B_7
272 + &k_8 * B_8
273 + &k_9 * B_9
274 + &k_10 * B_10
275 + &k_11 * B_11
276 + &k_12 * B_12)
277 * dt
278 + &y;
279 k_13 = function(
280 &(t + dt),
281 &(&k_1 * (A_13_1 * dt)
282 + &k_4 * (A_13_4 * dt)
283 + &k_5 * (A_13_5 * dt)
284 + &k_6 * (A_13_6 * dt)
285 + &k_7 * (A_13_7 * dt)
286 + &k_8 * (A_13_8 * dt)
287 + &k_9 * (A_13_9 * dt)
288 + &k_10 * (A_13_10 * dt)
289 + &y),
290 );
291 e = ((&k_1 * D_1
292 + &k_6 * D_6
293 + &k_7 * D_7
294 + &k_8 * D_8
295 + &k_9 * D_9
296 + &k_10 * D_10
297 + &k_11 * D_11
298 + &k_12 * D_12
299 + &k_13 * D_13)
300 * dt)
301 .norm();
302 if e < self.abs_tol || e / y_trial.norm() < self.rel_tol {
303 t += dt;
304 y = y_trial;
305 t_sol.push(t);
306 y_sol.push(y.clone());
307 }
308 dt *= self.dt_beta * (self.abs_tol / e).powf(1.0 / self.dt_expn);
309 }
310 if time.len() > 2 {
311 let t_int = Vector::new(time);
312 let y_int = self.interpolate(&t_int, &t_sol, &y_sol, function);
313 Ok((t_int, y_int))
314 } else {
315 Ok((t_sol, y_sol))
316 }
317 }
318}
319
320impl<Y, U> InterpolateSolution<Y, U> for Verner8
321where
322 Y: Tensor + TensorArray,
323 for<'a> &'a Y: Mul<TensorRank0, Output = Y> + Sub<&'a Y, Output = Y>,
324 U: TensorVec<Item = Y>,
325{
326 fn interpolate(
327 &self,
328 time: &Vector,
329 tp: &Vector,
330 yp: &U,
331 function: impl Fn(&TensorRank0, &Y) -> Y,
332 ) -> U {
333 let mut dt = 0.0;
334 let mut i = 0;
335 let mut k_1 = Y::zero();
336 let mut k_2 = Y::zero();
337 let mut k_3 = Y::zero();
338 let mut k_4 = Y::zero();
339 let mut k_5 = Y::zero();
340 let mut k_6 = Y::zero();
341 let mut k_7 = Y::zero();
342 let mut k_8 = Y::zero();
343 let mut k_9 = Y::zero();
344 let mut k_10 = Y::zero();
345 let mut k_11 = Y::zero();
346 let mut k_12 = Y::zero();
347 let mut t = 0.0;
348 let mut y = Y::zero();
349 time.iter()
350 .map(|time_k| {
351 i = tp.iter().position(|tp_i| tp_i > time_k).unwrap();
352 t = tp[i - 1];
353 y = yp[i - 1].clone();
354 dt = time_k - t;
355 k_1 = function(&t, &y);
356 k_2 = function(&(t + C_2 * dt), &(&k_1 * (A_2_1 * dt) + &y));
357 k_3 = function(
358 &(t + C_3 * dt),
359 &(&k_1 * (A_3_1 * dt) + &k_2 * (A_3_2 * dt) + &y),
360 );
361 k_4 = function(
362 &(t + C_4 * dt),
363 &(&k_1 * (A_4_1 * dt) + &k_3 * (A_4_3 * dt) + &y),
364 );
365 k_5 = function(
366 &(t + C_5 * dt),
367 &(&k_1 * (A_5_1 * dt) + &k_3 * (A_5_3 * dt) + &k_4 * (A_5_4 * dt) + &y),
368 );
369 k_6 = function(
370 &(t + C_6 * dt),
371 &(&k_1 * (A_6_1 * dt) + &k_4 * (A_6_4 * dt) + &k_5 * (A_6_5 * dt) + &y),
372 );
373 k_7 = function(
374 &(t + C_7 * dt),
375 &(&k_1 * (A_7_1 * dt)
376 + &k_4 * (A_7_4 * dt)
377 + &k_5 * (A_7_5 * dt)
378 + &k_6 * (A_7_6 * dt)
379 + &y),
380 );
381 k_8 = function(
382 &(t + C_8 * dt),
383 &(&k_1 * (A_8_1 * dt)
384 + &k_4 * (A_8_4 * dt)
385 + &k_5 * (A_8_5 * dt)
386 + &k_6 * (A_8_6 * dt)
387 + &k_7 * (A_8_7 * dt)
388 + &y),
389 );
390 k_9 = function(
391 &(t + C_9 * dt),
392 &(&k_1 * (A_9_1 * dt)
393 + &k_4 * (A_9_4 * dt)
394 + &k_5 * (A_9_5 * dt)
395 + &k_6 * (A_9_6 * dt)
396 + &k_7 * (A_9_7 * dt)
397 + &k_8 * (A_9_8 * dt)
398 + &y),
399 );
400 k_10 = function(
401 &(t + C_10 * dt),
402 &(&k_1 * (A_10_1 * dt)
403 + &k_4 * (A_10_4 * dt)
404 + &k_5 * (A_10_5 * dt)
405 + &k_6 * (A_10_6 * dt)
406 + &k_7 * (A_10_7 * dt)
407 + &k_8 * (A_10_8 * dt)
408 + &k_9 * (A_10_9 * dt)
409 + &y),
410 );
411 k_11 = function(
412 &(t + C_11 * dt),
413 &(&k_1 * (A_11_1 * dt)
414 + &k_4 * (A_11_4 * dt)
415 + &k_5 * (A_11_5 * dt)
416 + &k_6 * (A_11_6 * dt)
417 + &k_7 * (A_11_7 * dt)
418 + &k_8 * (A_11_8 * dt)
419 + &k_9 * (A_11_9 * dt)
420 + &k_10 * (A_11_10 * dt)
421 + &y),
422 );
423 k_12 = function(
424 &(t + dt),
425 &(&k_1 * (A_12_1 * dt)
426 + &k_4 * (A_12_4 * dt)
427 + &k_5 * (A_12_5 * dt)
428 + &k_6 * (A_12_6 * dt)
429 + &k_7 * (A_12_7 * dt)
430 + &k_8 * (A_12_8 * dt)
431 + &k_9 * (A_12_9 * dt)
432 + &k_10 * (A_12_10 * dt)
433 + &k_11 * (A_12_11 * dt)
434 + &y),
435 );
436 (&k_1 * B_1
437 + &k_6 * B_6
438 + &k_7 * B_7
439 + &k_8 * B_8
440 + &k_9 * B_9
441 + &k_10 * B_10
442 + &k_11 * B_11
443 + &k_12 * B_12)
444 * dt
445 + &y
446 })
447 .collect()
448 }
449}