Began adding the rosenbrock integrator
This commit is contained in:
105
src/problem.rs
105
src/problem.rs
@@ -1,87 +1,48 @@
|
||||
use num_traits::identities;
|
||||
use num_traits::Float;
|
||||
use std::fmt::Debug;
|
||||
use std::cmp::PartialOrd;
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign};
|
||||
use nalgebra::SVector;
|
||||
|
||||
use super::ode::{ODE, SystemTrait};
|
||||
use super::ode::ODE;
|
||||
use super::controller::{Controller, PIController};
|
||||
use super::integrator::Integrator;
|
||||
|
||||
pub struct Problem<T, F, const D1: usize, const D2: usize, S>
|
||||
pub struct Problem<'a, const D: usize, S>
|
||||
where
|
||||
f64: From<T>,
|
||||
F: SystemTrait<T,D1>,
|
||||
T: Copy +
|
||||
From<f64> +
|
||||
identities::One +
|
||||
identities::Zero +
|
||||
PartialEq +
|
||||
Debug +
|
||||
Add +
|
||||
AddAssign +
|
||||
Sub +
|
||||
SubAssign +
|
||||
Mul +
|
||||
MulAssign +
|
||||
Float +
|
||||
PartialOrd +
|
||||
'static,
|
||||
S: Integrator<T, F, D1, D2>,
|
||||
S: Integrator<D>,
|
||||
{
|
||||
ode: ODE<T,F,D1>,
|
||||
ode: ODE<'a, D>,
|
||||
integrator: S,
|
||||
controller: PIController<T>,
|
||||
controller: PIController,
|
||||
}
|
||||
|
||||
impl<T, F, const D1: usize, const D2: usize, S> Problem<T,F,D1,D2,S>
|
||||
impl<'a, const D: usize, S> Problem<'a,D,S>
|
||||
where
|
||||
f64: From<T>,
|
||||
F: SystemTrait<T,D1>,
|
||||
T: Copy +
|
||||
From<f64> +
|
||||
identities::One +
|
||||
identities::Zero +
|
||||
PartialEq +
|
||||
Debug +
|
||||
Add +
|
||||
AddAssign +
|
||||
Sub +
|
||||
SubAssign +
|
||||
Mul +
|
||||
MulAssign +
|
||||
Float +
|
||||
PartialOrd +
|
||||
'static,
|
||||
S: Integrator<T, F, D1, D2>,
|
||||
S: Integrator<D>,
|
||||
{
|
||||
pub fn new(ode: ODE<T,F,D1>, integrator: S, controller: PIController<T>) -> Self {
|
||||
pub fn new(ode: ODE<'a,D>, integrator: S, controller: PIController) -> Self {
|
||||
Problem {
|
||||
ode: ode,
|
||||
integrator: integrator,
|
||||
controller: controller,
|
||||
}
|
||||
}
|
||||
pub fn solve(&mut self) -> Solution<T, D1> {
|
||||
let mut times: Vec::<T> = Vec::new();
|
||||
let mut states: Vec::<SVector<T,D1>> = Vec::new();
|
||||
let mut step: T = self.controller.old_h;
|
||||
pub fn solve(&mut self) -> Solution<D> {
|
||||
let mut times: Vec::<f64> = Vec::new();
|
||||
let mut states: Vec::<SVector<f64,D>> = Vec::new();
|
||||
let mut step: f64 = self.controller.old_h;
|
||||
times.push(self.ode.t);
|
||||
states.push(self.ode.y);
|
||||
let (mut new_y, mut err_option) = self.integrator.step(&self.ode, 0.0);
|
||||
while self.ode.t < self.ode.t_end {
|
||||
let (mut new_y, mut err_option) = self.integrator.step(&self.ode, step);
|
||||
match err_option {
|
||||
Some(mut err) => {
|
||||
// Adaptive Step Size
|
||||
let mut accepted: bool = false;
|
||||
while !accepted {
|
||||
(accepted, step) = <PIController<T> as Controller<T, F, D1>>::determine_step(&mut self.controller, step, err);
|
||||
(accepted, step) = <PIController as Controller<D>>::determine_step(&mut self.controller, step, err);
|
||||
(new_y, err_option) = self.integrator.step(&self.ode, step);
|
||||
err = err_option.unwrap();
|
||||
}
|
||||
self.controller.old_h = step;
|
||||
self.controller.h_max = self.ode.t_end - self.ode.t - step;
|
||||
self.controller.h_max = self.controller.h_max.min(self.ode.t_end - self.ode.t - step);
|
||||
},
|
||||
None => {},
|
||||
};
|
||||
@@ -97,9 +58,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Solution<T,const D: usize> {
|
||||
pub times: Vec<T>,
|
||||
pub states: Vec<SVector<T,D>>,
|
||||
pub struct Solution<const D: usize> {
|
||||
pub times: Vec<f64>,
|
||||
pub states: Vec<SVector<f64,D>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -107,31 +68,25 @@ mod tests {
|
||||
use super::*;
|
||||
use nalgebra::Vector3;
|
||||
use approx::assert_relative_eq;
|
||||
use crate::integrator::{AdaptiveSixthOrder, RUNGE_KUTTA_FEHLBERG_54_TABLEAU};
|
||||
use crate::controller::{PIController};
|
||||
use crate::integrator::dormand_prince::DormandPrince45;
|
||||
use crate::controller::PIController;
|
||||
|
||||
// #[test]
|
||||
#[test]
|
||||
fn test_problem() {
|
||||
struct System {}
|
||||
fn derivative(_t: f64, y: Vector3<f64>) -> Vector3<f64> { y }
|
||||
let y0 = Vector3::new(1.0, 1.0, 1.0);
|
||||
|
||||
impl SystemTrait<f64,3> for System {
|
||||
fn derivative(&self, _t: f64, y: Vector3<f64>) -> Vector3<f64> { y }
|
||||
}
|
||||
let ode = ODE::new(&derivative, 0.0, 1.0, y0);
|
||||
let dp45 = DormandPrince45::new(1e-12_f64, 1e-5_f64);
|
||||
let controller = PIController::new(0.17, 0.04, 10.0, 0.2, 0.1, 0.9, 1e-8);
|
||||
|
||||
let system = System {};
|
||||
let y0 = Vector3::new(1.0, 0.0, 0.0);
|
||||
let ode = ODE::new(system, 0.0, 10.0, y0);
|
||||
let controller = PIController::new(0.17, 0.04, 10.0, 0.2, 10.0, 0.9, 1e-4);
|
||||
let rkf54 = AdaptiveSixthOrder {
|
||||
tableau: RUNGE_KUTTA_FEHLBERG_54_TABLEAU,
|
||||
atol: 1e-8_f64,
|
||||
rtol: 1e-8_f64,
|
||||
};
|
||||
let mut problem = Problem::new(ode, rkf54, controller);
|
||||
let mut problem = Problem::new(ode, dp45, controller);
|
||||
|
||||
let solution = problem.solve();
|
||||
// println!("{}", solution.times.len());
|
||||
// panic!();
|
||||
solution.times.iter().zip(solution.states.iter()).for_each(|(time, state)| {
|
||||
assert_relative_eq!(state[0], time.exp(), max_relative=1e-7);
|
||||
assert_relative_eq!(state[0], time.exp(), max_relative=1e-2);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user