#![allow(dead_code)]
use scirs2_core::ndarray::{array, ArrayView1};
use scirs2_integrate::ode::{solve_ivp, ODEMethod, ODEOptions};
use std::f64::consts::PI;
#[allow(dead_code)]
fn main() {
println!("DOP853 High-Order Runge-Kutta Solver Example");
println!("--------------------------------------------");
println!("Example 1: Simple Harmonic Oscillator with High Accuracy");
let harmonic = |_t: f64, y: ArrayView1<f64>| array![y[1], -y[0]];
let options = ODEOptions {
method: ODEMethod::DOP853, rtol: 1e-10, atol: 1e-12, ..Default::default()
};
let result = solve_ivp(harmonic, [0.0, 10.0 * PI], array![1.0, 0.0], Some(options))
.expect("Operation failed");
println!("\nSolving harmonic oscillator over t = [0, 10π] with high accuracy");
println!("Exact solution is y(t) = cos(t), y'(t) = -sin(t)");
println!("Initial condition: [1.0, 0.0]");
let check_points = vec![0.0, PI, 2.0 * PI, 3.0 * PI, 4.0 * PI, 5.0 * PI];
println!("\nChecking solution at key points:");
println!("{:>10} {:>15} {:>15} {:>15}", "t", "y[0]", "exact", "error");
println!("{:->10} {:->15} {:->15} {:->15}", "", "", "", "");
for &t in &check_points {
let idx = result
.t
.iter()
.enumerate()
.min_by(|(_, &a), (_, &b)| {
(a - t)
.abs()
.partial_cmp(&(b - t).abs())
.expect("Operation failed")
})
.map(|(idx_, _)| idx_)
.unwrap_or(0);
let y0 = result.y[idx][0];
let exact0 = t.cos();
let error = (y0 - exact0).abs();
println!(
"{:10.6} {:15.10} {:15.10} {:15.2e}",
result.t[idx], y0, exact0, error
);
}
println!("\nStatistics:");
println!(" Number of steps: {}", result.n_steps);
println!(" Number of function evaluations: {}", result.n_eval);
println!(" Number of accepted steps: {}", result.n_accepted);
println!(" Number of rejected steps: {}", result.n_rejected);
println!(" Success: {}", result.success);
let final_y = result.y.last().expect("Operation failed");
println!("\nFinal state: [{:.10}, {:.10}]", final_y[0], final_y[1]);
println!(
"Error from exact: [{:.2e}, {:.2e}]",
(final_y[0] - 1.0).abs(),
(final_y[1] - 0.0).abs()
);
println!("\n\nExample 2: Comparing Different ODE Methods");
println!("Solving y' = -y, y(0) = 1 over t = [0, 5]");
println!("Exact solution: y(t) = e^(-t)");
let exp_decay = |_t: f64, y: ArrayView1<f64>| array![-y[0]];
let methods = [ODEMethod::RK23, ODEMethod::RK45, ODEMethod::DOP853];
let method_names = ["RK23 (order 3)", "RK45 (order 5)", "DOP853 (order 8)"];
println!(
"\n{:>15} {:>12} {:>12} {:>15} {:>15}",
"Method", "Steps", "Evaluations", "Final Value", "Error"
);
println!(
"{:->15} {:->12} {:->12} {:->15} {:->15}",
"", "", "", "", ""
);
for (i, &method) in methods.iter().enumerate() {
let options = ODEOptions {
method,
rtol: 1e-8,
atol: 1e-10,
..Default::default()
};
let result =
solve_ivp(exp_decay, [0.0, 5.0], array![1.0], Some(options)).expect("Operation failed");
let final_y = result.y.last().expect("Operation failed")[0];
let exact = (-5.0f64).exp();
let error = (final_y - exact).abs();
println!(
"{:>15} {:>12} {:>12} {:>15.10} {:>15.2e}",
method_names[i], result.n_steps, result.n_eval, final_y, error
);
}
println!("\n\nExample 3: Kepler Problem (Two-Body Orbital Motion)");
let kepler = |_t: f64, y: ArrayView1<f64>| {
let r = (y[0] * y[0] + y[1] * y[1]).sqrt();
let r3 = r * r * r;
array![
y[2], y[3], -y[0] / r3, -y[1] / r3, ]
};
let y0 = array![1.0, 0.0, 0.0, 1.0];
let options = ODEOptions {
method: ODEMethod::DOP853,
rtol: 1e-10,
atol: 1e-12,
..Default::default()
};
let result = solve_ivp(kepler, [0.0, 2.0 * PI], y0, Some(options)).expect("Operation failed");
println!("Solving for one complete orbit (period = 2π)");
println!("Initial state: [x, y, vx, vy] = [1, 0, 0, 1]");
println!("After one orbit, should return to initial state");
let final_state = result.y.last().expect("Operation failed");
println!(
"\nFinal state: [{:.10}, {:.10}, {:.10}, {:.10}]",
final_state[0], final_state[1], final_state[2], final_state[3]
);
let errors = [
(final_state[0] - 1.0).abs(),
(final_state[1] - 0.0).abs(),
(final_state[2] - 0.0).abs(),
(final_state[3] - 1.0).abs(),
];
println!(
"Errors: [{:.2e}, {:.2e}, {:.2e}, {:.2e}]",
errors[0], errors[1], errors[2], errors[3]
);
println!("\nStatistics:");
println!(" Number of steps: {}", result.n_steps);
println!(" Number of function evaluations: {}", result.n_eval);
println!(" Number of accepted steps: {}", result.n_accepted);
println!(" Number of rejected steps: {}", result.n_rejected);
}