use std::fs::File;
use std::io::Write;
use dace::*;
use ndarray_linalg::Scalar;
macro_rules! define_functions {
($t:ty) => {
::paste::paste! {
pub fn [<midpoint_ $t:lower>](
x0: &AlgebraicVector<$t>,
t0: f64,
t1: f64,
f: fn(&AlgebraicVector<$t>, f64) -> AlgebraicVector<$t>,
) -> AlgebraicVector<$t> {
const HMAX: f64 = 0.005;
let steps: f64 = ((t1 - t0) / HMAX).ceil();
let h: f64 = (t1 - t0) / steps;
let mut t: f64 = t0;
let mut x: AlgebraicVector<$t> = x0.to_owned();
let mut xmid: AlgebraicVector<$t>;
for _i in 0..(steps as i32) {
xmid = &x + 0.5 * h * f(&x, t);
x += h * f(&xmid, t + 0.5 * h);
t += h;
}
x
}
fn [<pendulum_rhs_ $t:lower>](x: &AlgebraicVector<$t>, _t: f64) -> AlgebraicVector<$t> {
const L: f64 = 0.61; const M1: f64 = 0.21; const M2: f64 = 0.4926; const G: f64 = 9.81;
darray![
x[1].clone(),
((M2 + M1) * G * x[0].sin() - M1 * L * x[1].square() * x[0].sin() * x[0].cos())
/ ((M2 + M1) * L + M1 * L * x[0].cos().square()),
]
}
}
};
}
define_functions!(DA);
define_functions!(f64);
fn ex6_1_2() {
let mut xda: AlgebraicVector<DA> = darray![da!(0.0), 0.2 + 0.04 * da!(1)]; let mut xdb: AlgebraicVector<f64> = darray![0.0, 0.2]; let mut t: f64;
const DT: f64 = 0.05; let mut file = File::create("ex6_1_2.dat").unwrap();
t = 0.0;
for _i in 0..100 {
xdb = midpoint_f64(&xdb, t, t + DT, pendulum_rhs_f64); writeln!(&mut file, "{} {} {}", t, xdb[0], xdb[1]).unwrap();
t += DT;
}
write!(&mut file, "\n\n").unwrap();
t = 0.0;
for _i in 0..100 {
xda = midpoint_da(&xda, t, t + DT, pendulum_rhs_da); writeln!(
&mut file,
"{} {} {} {} {}",
t,
xda[0].eval(-1.0),
xda[0].eval(1.0),
xda[1].eval(-1.0),
xda[1].eval(1.0)
)
.unwrap();
t += DT;
}
writeln!(&mut file).unwrap();
println!(
"Exercise 6.1.2: Model of the (uncontrolled) pendulum\n{}",
xda
);
}
fn plot(x: &AlgebraicVector<DA>, t: f64, n: i32, file: &mut File) {
let nf = n as f64;
for i in -n..=n {
let arg_0 = (i as f64) / nf;
for j in -n..=n {
let arg_1 = (j as f64) / nf;
let res = x.eval(&darray![arg_0, arg_1]);
writeln!(file, "{} {} {}", t, res[0], res[1]).unwrap();
}
writeln!(file).unwrap();
}
writeln!(file).unwrap();
}
fn f(x: &AlgebraicVector<DA>, _t: f64) -> AlgebraicVector<DA> {
let alpha = 0.1;
(1.0 + alpha * x.vnorm()) * darray![-&x[1], x[0].to_owned()]
}
fn ex6_1_3() {
let mut x = AlgebraicVector::<DA>::zeros(2);
let mut t: f64;
const DT: f64 = 2.0 * PI / 6.0;
let mut file = File::create("ex6_1_3.dat").unwrap();
x[0] = 2.0 + da!(1);
x[1] = da!(2);
t = 0.0;
plot(&x, t, 7, &mut file);
for _i in 0..6 {
x = midpoint_da(&x, t, t + DT, f);
t += DT;
plot(&x, t, 7, &mut file);
}
println!("Exercise 6.1.3: Set propagation\n{}", x);
}
fn ex6_1_4() {
let mut x = AlgebraicVector::<DA>::zeros(2);
x[0] = 1.0 + da!(1);
x[1] = 1.0 + da!(2);
x = midpoint_da(&x, 0.0, 2.0 * PI, f);
println!("Exercise 6.1.4: State Transition Matrix");
println!("{} {}", x[0].deriv(1).cons(), x[0].deriv(2).cons());
println!("{} {}", x[1].deriv(1).cons(), x[1].deriv(2).cons());
println!();
}
fn f_param(x: &AlgebraicVector<DA>, _t: f64) -> AlgebraicVector<DA> {
let alpha = 0.05 + 0.05 * da!(1); (1.0 + alpha * x.vnorm()) * darray![-&x[1], x[0].to_owned()]
}
fn ex6_1_5() {
let mut x = AlgebraicVector::<DA>::zeros(2);
x[0] = 1.0.into();
x[1] = 1.0.into();
x = midpoint_da(&x, 0.0, 2.0 * PI, f_param);
let mut file = File::create("ex6_1_5.dat").unwrap();
writeln!(&mut file, "1 1").unwrap();
for i in 0..=20 {
let i_f = i as f64;
writeln!(
&mut file,
"{} {}",
x[0].eval(-1.0 + i_f / 10.0),
x[1].eval(-1.0 + i_f / 10.0)
)
.unwrap();
}
println!("Exercise 6.1.5: Parameter dependence\n{}", x);
}
fn rk4(
x0: &AlgebraicVector<DA>,
t0: f64,
t1: f64,
f: fn(&AlgebraicVector<DA>, f64) -> AlgebraicVector<DA>,
) -> AlgebraicVector<DA> {
const HMAX: f64 = 0.01;
let steps = ((t1 - t0) / HMAX).ceil();
let h = (t1 - t0) / steps;
let mut t = t0;
let mut x = x0.to_owned();
for _i in 0..(steps as i32) {
let k1 = f(&x, t);
let k2 = f(&(&x + h * &k1 / 3.0), t + h / 3.0);
let k3 = f(&(&x + h * (-&k1 / 3.0 + &k2)), t + 2.0 * h / 3.0);
let k4 = f(&(&x + h * (&k1 - &k2 + &k3)), t + h);
x += h * (k1 + 3.0 * k2 + 3.0 * k3 + k4) / 8.0;
t += h;
}
x
}
fn ex6_2_2() {
let mut x = AlgebraicVector::<DA>::zeros(2);
let mut t: f64;
const DT: f64 = 2.0 * PI / 6.0;
let mut file = File::create("ex6_2_2.dat").unwrap();
let da1 = &da!(1);
let da2 = &da!(2);
x[0] = da1.clone();
x[1] = ((1.0 - da1 * da1) * (da2 + 1.0) + (da1 * da1 * da1 - da1) * (1.0 - da2)) / 2.0;
t = 0.0;
plot(&x, t, 7, &mut file);
for _i in 0..6 {
x = midpoint_da(&x, t, t + DT, f); t += DT;
plot(&x, t, 7, &mut file);
}
println!("Exercise 6.2.2: Artsy Set propagation\n{}", x);
}
fn cr3bp(x: &AlgebraicVector<DA>, _t: f64) -> AlgebraicVector<DA> {
const MU: f64 = 0.30404234e-5;
let (mut d1, mut d2): (DA, DA);
d1 = ((&x[0] + MU).square() + x[1].square() + x[2].square()).sqrt();
d1 = 1.0 / (&d1 * &d1 * &d1); d2 = ((&x[0] + MU - 1.0).square() + x[1].square() + x[2].square()).sqrt();
d2 = 1.0 / (&d2 * &d2 * &d2);
darray![
x[3].clone(),
x[4].clone(),
x[5].clone(),
&x[0] + 2.0 * &x[4] - &d1 * (1.0 - MU) * (&x[0] + MU) - &d2 * MU * (&x[0] + MU - 1.0),
&x[1] - 2.0 * &x[3] - &d1 * (1.0 - MU) * &x[1] - &d2 * MU * &x[1],
-&d1 * (1.0 - MU) * &x[2] - &d2 * MU * &x[2],
]
}
fn ex6_2_3() {
const T: f64 = 3.05923;
let x0 = darray![0.9888426847, 0.0, 0.0011210277, 0.0, 0.0090335498, 0.0];
let mut x = x0 + AlgebraicVector::<DA>::identity(6);
DA::push_truncation_order(1);
x = rk4(&x, 0.0, T, cr3bp);
println!("Exercise 6.2.3: CR3BP STM\n{}", x.cons());
for i in 0..6 {
for j in 1..=6 {
print!("{} ", x[i].deriv(j).cons());
}
println!();
}
println!();
DA::pop_truncation_order();
}
fn ex6_2_4() {
let mut x = AlgebraicVector::<DA>::zeros(2);
let mut t: f64;
const DT: f64 = 2.0 * PI / 6.0;
let mut file = File::create("ex6_2_4.dat").unwrap();
x[0] = (0.3 * da!(2)).cos() * (2.0 + da!(1));
x[1] = (0.3 * da!(2)).sin() * (2.0 + da!(1));
t = 0.0;
plot(&x, t, 40, &mut file);
for _i in 0..6 {
x = midpoint_da(&x, t, t + DT, f); t += DT;
plot(&x, t, 40, &mut file);
}
println!("Exercise 6.2.4: Set propagation revisited\n{}", x);
}
fn ex6_2_5() {
let mut x = darray![1.0 + da!(2), 1.0 + da!(3)];
x = midpoint_da(&x, 0.0, 2.0 * PI, f_param);
let mut arg = AlgebraicVector::<DA>::zeros(3);
arg[0] = da!(1);
println!("Exercise 6.2.5: The State Transition Matrix reloaded");
println!("{} {}", x[0].deriv(2).eval(&arg), x[0].deriv(3).eval(&arg));
println!("{} {}", x[1].deriv(2).eval(&arg), x[1].deriv(3).eval(&arg));
println!();
}
fn main() {
DA::init(15, 6);
ex6_1_2();
ex6_1_3();
ex6_1_4();
ex6_1_5();
ex6_2_2();
ex6_2_3();
ex6_2_4();
ex6_2_5();
}