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 105 106 107 108
use ndarray::Dimension; use ndarray::IntoNdProducer; use ode::Ode; use super::{ RungeKutta4, Stepper, ZipMarker, }; impl<T> RungeKutta4<T> where T: Clone, { pub fn new(state: &T, dt: f64) -> Self { let dt_2 = dt/2.0; let dt_3 = dt/3.0; let dt_6 = dt/6.0; let temp = state.clone(); let k1 = state.clone(); let k2 = state.clone(); let k3 = state.clone(); let k4 = state.clone(); RungeKutta4 { dt: dt, dt_2: dt_2, dt_3: dt_3, dt_6: dt_6, temp: temp, k1: k1, k2: k2, k3: k3, k4: k4, } } fn timestep(&self) -> f64 { self.dt } } impl Stepper for RungeKutta4<f64> { type State = f64; fn do_step<Sy>(&mut self, system: &mut Sy, state: &mut Self::State) where Sy: Ode<State=f64>, { system.differentiate_into(state, &mut self.k1); system.differentiate_into(&(*state + &self.k1 * self.dt_2), &mut self.k2); system.differentiate_into(&(*state + &self.k2 * self.dt_2), &mut self.k3); system.differentiate_into(&(*state + &self.k3 * self.dt), &mut self.k4); self.temp = *state + &(self.dt_6 * &self.k1) + &(self.dt_3 * &self.k2) + &(self.dt_3 * &self.k3) + &(self.dt_6 * &self.k4); system.update_state(state, &self.temp); } fn timestep(&self) -> f64 { self.timestep() } } impl<D, P: ZipMarker> Stepper for RungeKutta4<P> where P: Clone, D: Dimension, for<'a> &'a P: IntoNdProducer<Dim=D, Item=&'a f64>, for<'a> &'a mut P: IntoNdProducer<Dim=D, Item=&'a mut f64>, { type State = P; fn do_step<Sy>(&mut self, system: &mut Sy, state: &mut Self::State) where Sy: Ode<State=P>, { let dt = self.dt; let dt_2 = self.dt_2; let dt_3 = self.dt_3; let dt_6 = self.dt_6; system.differentiate_into(state, &mut self.k1); azip!(mut t (&mut self.temp), s (&*state), k1 (&self.k1) in { *t = s + dt_2 * k1 }); system.differentiate_into(&self.temp, &mut self.k2); azip!(mut t (&mut self.temp), s (&*state), k2 (&self.k2) in { *t = s + dt_2 * k2 }); system.differentiate_into(&self.temp, &mut self.k3); azip!(mut t (&mut self.temp), s (&*state), k3 (&self.k3) in { *t = s + dt * k3 }); system.differentiate_into(&self.temp, &mut self.k4); azip!(mut t (&mut self.temp), s (&*state), k1 (&self.k1), k2 (&self.k2), k3 (&self.k3), k4 (&self.k4) in { *t = s + dt_6 * k1 + dt_3 * k2 + dt_3 * k3 + dt_6 * k4; }); system.update_state(state, &self.temp); } fn timestep(&self) -> f64 { self.timestep() } }