librebound_sys/
wrappers.rs1use crate::ffi;
4use crate::{Error, Result};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[repr(i32)]
14pub enum Ias15AdaptiveMode {
15 Individual = 0,
17 Global = 1,
19 Prs23 = 2,
21 Aarseth85 = 3,
23}
24
25impl Ias15AdaptiveMode {
26 fn from_raw(raw: i32) -> Self {
27 match raw {
28 0 => Self::Individual,
29 1 => Self::Global,
30 2 => Self::Prs23,
31 3 => Self::Aarseth85,
32 _ => Self::Prs23,
36 }
37 }
38}
39
40#[derive(Debug, Clone, Copy, Default)]
49pub struct IntegratorConfig {
50 pub initial_dt: Option<f64>,
53 pub min_dt: Option<f64>,
56 pub epsilon: Option<f64>,
58 pub adaptive_mode: Option<Ias15AdaptiveMode>,
60}
61
62impl IntegratorConfig {
63 pub fn apply(&self, sim: &mut Simulation) {
66 if let Some(dt) = self.initial_dt {
67 sim.set_dt(dt);
68 }
69 if let Some(eps) = self.epsilon {
70 sim.set_ias15_epsilon(eps);
71 }
72 if let Some(min_dt) = self.min_dt {
73 sim.set_ias15_min_dt(min_dt);
74 }
75 if let Some(mode) = self.adaptive_mode {
76 sim.set_ias15_adaptive_mode(mode);
77 }
78 }
79}
80
81pub struct Simulation {
89 ptr: *mut ffi::reb_simulation,
90}
91
92impl Simulation {
93 pub fn new() -> Result<Self> {
95 let ptr = unsafe { ffi::reb_simulation_create() };
96 if ptr.is_null() {
97 return Err(Error::Other("reb_simulation_create returned null".into()));
98 }
99 Ok(Self { ptr })
100 }
101
102 pub fn as_ptr(&self) -> *const ffi::reb_simulation {
106 self.ptr
107 }
108
109 pub fn as_mut_ptr(&mut self) -> *mut ffi::reb_simulation {
113 self.ptr
114 }
115
116 #[doc(hidden)]
118 pub fn raw_ptr_mut(&mut self) -> *mut ffi::reb_simulation {
119 self.ptr
120 }
121
122 pub fn t(&self) -> f64 {
123 unsafe { ffi::assist_rs_sim_get_t(self.ptr) }
124 }
125 pub fn set_t(&mut self, t: f64) {
126 unsafe { ffi::assist_rs_sim_set_t(self.ptr, t) }
127 }
128
129 pub fn dt(&self) -> f64 {
130 unsafe { ffi::assist_rs_sim_get_dt(self.ptr) }
131 }
132 pub fn set_dt(&mut self, dt: f64) {
133 unsafe { ffi::assist_rs_sim_set_dt(self.ptr, dt) }
134 }
135
136 pub fn n_particles(&self) -> usize {
137 unsafe { ffi::assist_rs_sim_get_N(self.ptr) as usize }
138 }
139
140 pub fn steps_done(&self) -> u64 {
143 unsafe { ffi::assist_rs_sim_get_steps_done(self.ptr) }
144 }
145
146 pub fn n_var(&self) -> i32 {
147 unsafe { ffi::assist_rs_sim_get_N_var(self.ptr) }
148 }
149
150 pub fn status(&self) -> i32 {
151 unsafe { ffi::assist_rs_sim_get_status(self.ptr) }
152 }
153
154 pub fn set_exact_finish_time(&mut self, v: bool) {
155 unsafe { ffi::assist_rs_sim_set_exact_finish_time(self.ptr, v as i32) }
156 }
157
158 pub fn ias15_epsilon(&self) -> f64 {
161 unsafe { ffi::assist_rs_sim_get_ias15_epsilon(self.ptr) }
162 }
163 pub fn set_ias15_epsilon(&mut self, eps: f64) {
164 unsafe { ffi::assist_rs_sim_set_ias15_epsilon(self.ptr, eps) }
165 }
166
167 pub fn ias15_min_dt(&self) -> f64 {
171 unsafe { ffi::assist_rs_sim_get_ias15_min_dt(self.ptr) }
172 }
173 pub fn set_ias15_min_dt(&mut self, min_dt: f64) {
174 unsafe { ffi::assist_rs_sim_set_ias15_min_dt(self.ptr, min_dt) }
175 }
176
177 pub fn ias15_adaptive_mode(&self) -> Ias15AdaptiveMode {
180 let raw = unsafe { ffi::assist_rs_sim_get_ias15_adaptive_mode(self.ptr) };
181 Ias15AdaptiveMode::from_raw(raw)
182 }
183 pub fn set_ias15_adaptive_mode(&mut self, mode: Ias15AdaptiveMode) {
184 unsafe { ffi::assist_rs_sim_set_ias15_adaptive_mode(self.ptr, mode as i32) }
185 }
186
187 pub fn ias15_iterations_max_exceeded(&self) -> u64 {
193 unsafe { ffi::assist_rs_sim_get_ias15_iterations_max_exceeded(self.ptr) }
194 }
195
196 pub fn add_particle(&mut self, p: ffi::reb_particle) {
198 unsafe { ffi::reb_simulation_add(self.ptr, p) }
199 }
200
201 pub fn add_test_particle(&mut self, x: f64, y: f64, z: f64, vx: f64, vy: f64, vz: f64) {
203 let p = ffi::reb_particle {
204 x,
205 y,
206 z,
207 vx,
208 vy,
209 vz,
210 m: 0.0,
211 ..Default::default()
212 };
213 self.add_particle(p);
214 }
215
216 pub fn particles(&self) -> &[ffi::reb_particle] {
218 let n = self.n_particles();
219 if n == 0 {
220 return &[];
221 }
222 let ptr = unsafe { ffi::assist_rs_sim_get_particles(self.ptr) };
223 if ptr.is_null() {
224 return &[];
225 }
226 unsafe { std::slice::from_raw_parts(ptr, n) }
227 }
228
229 pub fn integrate(&mut self, tmax: f64) -> Result<()> {
231 let status = unsafe { ffi::reb_simulation_integrate(self.ptr, tmax) };
232 match status {
233 ffi::REB_STATUS_SUCCESS | ffi::REB_STATUS_RUNNING => Ok(()),
234 ffi::REB_STATUS_NO_PARTICLES => Err(Error::NoParticles),
235 ffi::REB_STATUS_ENCOUNTER => Err(Error::CloseEncounter),
236 ffi::REB_STATUS_ESCAPE => Err(Error::Escape),
237 ffi::REB_STATUS_COLLISION => Err(Error::Collision),
238 other => Err(Error::IntegrationFailed(other)),
239 }
240 }
241
242 pub fn add_variation_1st_order(&mut self, testparticle: i32) -> i32 {
245 unsafe { ffi::reb_simulation_add_variation_1st_order(self.ptr, testparticle) }
246 }
247}
248
249impl Drop for Simulation {
250 fn drop(&mut self) {
251 if !self.ptr.is_null() {
252 unsafe { ffi::reb_simulation_free(self.ptr) }
253 }
254 }
255}