use crate::ffi;
use crate::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum Ias15AdaptiveMode {
Individual = 0,
Global = 1,
Prs23 = 2,
Aarseth85 = 3,
}
impl Ias15AdaptiveMode {
fn from_raw(raw: i32) -> Self {
match raw {
0 => Self::Individual,
1 => Self::Global,
2 => Self::Prs23,
3 => Self::Aarseth85,
_ => Self::Prs23,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct IntegratorConfig {
pub initial_dt: Option<f64>,
pub min_dt: Option<f64>,
pub epsilon: Option<f64>,
pub adaptive_mode: Option<Ias15AdaptiveMode>,
}
impl IntegratorConfig {
pub fn apply(&self, sim: &mut Simulation) {
if let Some(dt) = self.initial_dt {
sim.set_dt(dt);
}
if let Some(eps) = self.epsilon {
sim.set_ias15_epsilon(eps);
}
if let Some(min_dt) = self.min_dt {
sim.set_ias15_min_dt(min_dt);
}
if let Some(mode) = self.adaptive_mode {
sim.set_ias15_adaptive_mode(mode);
}
}
}
pub struct Simulation {
ptr: *mut ffi::reb_simulation,
}
impl Simulation {
pub fn new() -> Result<Self> {
let ptr = unsafe { ffi::reb_simulation_create() };
if ptr.is_null() {
return Err(Error::Other("reb_simulation_create returned null".into()));
}
Ok(Self { ptr })
}
pub fn as_ptr(&self) -> *const ffi::reb_simulation {
self.ptr
}
pub fn as_mut_ptr(&mut self) -> *mut ffi::reb_simulation {
self.ptr
}
#[doc(hidden)]
pub fn raw_ptr_mut(&mut self) -> *mut ffi::reb_simulation {
self.ptr
}
pub fn t(&self) -> f64 {
unsafe { ffi::assist_rs_sim_get_t(self.ptr) }
}
pub fn set_t(&mut self, t: f64) {
unsafe { ffi::assist_rs_sim_set_t(self.ptr, t) }
}
pub fn dt(&self) -> f64 {
unsafe { ffi::assist_rs_sim_get_dt(self.ptr) }
}
pub fn set_dt(&mut self, dt: f64) {
unsafe { ffi::assist_rs_sim_set_dt(self.ptr, dt) }
}
pub fn n_particles(&self) -> usize {
unsafe { ffi::assist_rs_sim_get_N(self.ptr) as usize }
}
pub fn steps_done(&self) -> u64 {
unsafe { ffi::assist_rs_sim_get_steps_done(self.ptr) }
}
pub fn n_var(&self) -> i32 {
unsafe { ffi::assist_rs_sim_get_N_var(self.ptr) }
}
pub fn status(&self) -> i32 {
unsafe { ffi::assist_rs_sim_get_status(self.ptr) }
}
pub fn set_exact_finish_time(&mut self, v: bool) {
unsafe { ffi::assist_rs_sim_set_exact_finish_time(self.ptr, v as i32) }
}
pub fn ias15_epsilon(&self) -> f64 {
unsafe { ffi::assist_rs_sim_get_ias15_epsilon(self.ptr) }
}
pub fn set_ias15_epsilon(&mut self, eps: f64) {
unsafe { ffi::assist_rs_sim_set_ias15_epsilon(self.ptr, eps) }
}
pub fn ias15_min_dt(&self) -> f64 {
unsafe { ffi::assist_rs_sim_get_ias15_min_dt(self.ptr) }
}
pub fn set_ias15_min_dt(&mut self, min_dt: f64) {
unsafe { ffi::assist_rs_sim_set_ias15_min_dt(self.ptr, min_dt) }
}
pub fn ias15_adaptive_mode(&self) -> Ias15AdaptiveMode {
let raw = unsafe { ffi::assist_rs_sim_get_ias15_adaptive_mode(self.ptr) };
Ias15AdaptiveMode::from_raw(raw)
}
pub fn set_ias15_adaptive_mode(&mut self, mode: Ias15AdaptiveMode) {
unsafe { ffi::assist_rs_sim_set_ias15_adaptive_mode(self.ptr, mode as i32) }
}
pub fn ias15_iterations_max_exceeded(&self) -> u64 {
unsafe { ffi::assist_rs_sim_get_ias15_iterations_max_exceeded(self.ptr) }
}
pub fn add_particle(&mut self, p: ffi::reb_particle) {
unsafe { ffi::reb_simulation_add(self.ptr, p) }
}
pub fn add_test_particle(&mut self, x: f64, y: f64, z: f64, vx: f64, vy: f64, vz: f64) {
let p = ffi::reb_particle {
x,
y,
z,
vx,
vy,
vz,
m: 0.0,
..Default::default()
};
self.add_particle(p);
}
pub fn particles(&self) -> &[ffi::reb_particle] {
let n = self.n_particles();
if n == 0 {
return &[];
}
let ptr = unsafe { ffi::assist_rs_sim_get_particles(self.ptr) };
if ptr.is_null() {
return &[];
}
unsafe { std::slice::from_raw_parts(ptr, n) }
}
pub fn integrate(&mut self, tmax: f64) -> Result<()> {
let status = unsafe { ffi::reb_simulation_integrate(self.ptr, tmax) };
match status {
ffi::REB_STATUS_SUCCESS | ffi::REB_STATUS_RUNNING => Ok(()),
ffi::REB_STATUS_NO_PARTICLES => Err(Error::NoParticles),
ffi::REB_STATUS_ENCOUNTER => Err(Error::CloseEncounter),
ffi::REB_STATUS_ESCAPE => Err(Error::Escape),
ffi::REB_STATUS_COLLISION => Err(Error::Collision),
other => Err(Error::IntegrationFailed(other)),
}
}
pub fn add_variation_1st_order(&mut self, testparticle: i32) -> i32 {
unsafe { ffi::reb_simulation_add_variation_1st_order(self.ptr, testparticle) }
}
}
impl Drop for Simulation {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::reb_simulation_free(self.ptr) }
}
}
}