1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use super::traits::*;
use super::diag::Diagonal;
use ndarray::*;
use ndarray_linalg::{Scalar, into_scalar, replicate};
pub struct DiagRK4<A, S, F, D>
where A: Scalar,
S: Data<Elem = A>,
D: Dimension
{
f: F,
lin_half: Diagonal<A, S, D>,
dt: A::Real,
}
pub fn diag_rk4<A, S, F, D>(f: F, dt: A::Real) -> DiagRK4<A, S, F, D>
where A: Scalar,
S: DataClone<Elem = A> + DataMut,
F: SemiImplicitDiag<S, S, D>,
D: Dimension
{
DiagRK4::new(f, dt)
}
impl<A, S, F, D> DiagRK4<A, S, F, D>
where A: Scalar,
S: DataClone<Elem = A> + DataMut,
D: Dimension
{
pub fn new(f: F, dt: A::Real) -> Self
where F: SemiImplicitDiag<S, S, D>
{
let diag = f.diag();
let lin_half = Diagonal::new(diag, dt / into_scalar(2.0));
DiagRK4 {
f: f,
lin_half: lin_half,
dt: dt,
}
}
}
impl<A, S, F, D> ModelSize<D> for DiagRK4<A, S, F, D>
where A: Scalar,
F: ModelSize<D>,
S: DataClone<Elem = A> + DataMut,
D: Dimension
{
fn model_size(&self) -> D::Pattern {
self.f.model_size()
}
}
impl<A, S, F, D> TimeEvolutionBase<S, D> for DiagRK4<A, S, F, D>
where A: Scalar,
S: DataMut<Elem = A> + DataClone + DataOwned,
F: SemiImplicitDiag<S, S, D, Time = A::Real, Scalar = A>,
D: Dimension
{
type Scalar = F::Scalar;
type Time = F::Time;
fn iterate<'a>(&self, x: &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D> {
let dt = self.dt;
let dt_2 = self.dt / into_scalar(2.0);
let dt_3 = self.dt / into_scalar(3.0);
let dt_6 = self.dt / into_scalar(6.0);
let l = &self.lin_half;
let f = &self.f;
let mut x_ = replicate(&x);
let mut lx = replicate(&x);
l.iterate(&mut lx);
let mut k1 = f.nlin(x);
let k1_ = k1.to_owned();
Zip::from(&mut *k1)
.and(&x_)
.apply(|k1, &x_| { *k1 = x_ + k1.mul_real(dt_2); });
let mut k2 = f.nlin(l.iterate(k1));
let k2_ = k2.to_owned();
Zip::from(&mut *k2)
.and(&lx)
.apply(|k2, &lx| { *k2 = lx + k2.mul_real(dt_2); });
let mut k3 = f.nlin(k2);
let k3_ = k3.to_owned();
Zip::from(&mut *k3)
.and(&lx)
.apply(|k3, &lx| { *k3 = lx + k3.mul_real(dt); });
let mut k4 = f.nlin(l.iterate(k3));
azip!(mut x_, k1_ in { *x_ = *x_ + k1_.mul_real(dt_6) });
l.iterate(&mut x_);
azip!(mut x_, k2_, k3_ in { *x_ = *x_ + (k2_ + k3_).mul_real(dt_3) });
l.iterate(&mut x_);
Zip::from(&mut *k4)
.and(&x_)
.apply(|k4, &x_| { *k4 = x_ + k4.mul_real(dt_6); });
k4
}
}