use crate::config::parameters::default_bodies;
use crate::dynamics::integrator::Integrator;
use crate::orchestrator::pipeline::{Pipeline, RunBudget};
pub struct Scheduler {
pub pipeline: Pipeline,
pub output_interval_steps: usize,
pub current_step: usize,
}
impl Scheduler {
pub fn default_system(dt: f64) -> Self {
let bodies = default_bodies();
let pipeline = Pipeline::new(bodies, dt, Integrator::LeapfrogKDK);
Self {
pipeline,
output_interval_steps: 100,
current_step: 0,
}
}
pub fn with_integrator(dt: f64, integrator: Integrator) -> Self {
let bodies = default_bodies();
let pipeline = Pipeline::new(bodies, dt, integrator);
Self {
pipeline,
output_interval_steps: 100,
current_step: 0,
}
}
pub fn run(&mut self, total_steps: usize) {
let executed = self
.pipeline
.run_with_budget(total_steps, RunBudget::default());
self.current_step += executed;
}
pub fn run_budgeted(&mut self, total_steps: usize, budget: RunBudget) {
let executed = self.pipeline.run_with_budget(total_steps, budget);
self.current_step += executed;
}
pub fn run_with_callback<F>(&mut self, total_steps: usize, callback: F)
where
F: FnMut(usize, &Pipeline),
{
self.run_with_callback_budgeted(total_steps, RunBudget::default(), callback);
}
pub fn run_with_callback_budgeted<F>(
&mut self,
total_steps: usize,
budget: RunBudget,
mut callback: F,
) where
F: FnMut(usize, &Pipeline),
{
self.pipeline.initialize();
let capped_steps = budget.max_steps.map_or(total_steps, |m| m.min(total_steps));
let deadline = budget
.max_runtime_ms
.map(|ms| std::time::Instant::now() + std::time::Duration::from_millis(ms));
for idx in 0..capped_steps {
if let Some(t) = deadline
&& std::time::Instant::now() >= t
{
break;
}
self.pipeline.step();
self.current_step += 1;
if self.current_step.is_multiple_of(self.output_interval_steps) {
callback(self.current_step, &self.pipeline);
}
if budget.yield_every > 0 && (idx + 1).is_multiple_of(budget.yield_every) {
std::thread::yield_now();
}
}
}
pub fn elapsed_years(&self) -> f64 {
self.pipeline.time.years_elapsed()
}
pub fn elapsed_days(&self) -> f64 {
self.pipeline.time.days_elapsed()
}
pub fn event_count(&self) -> usize {
self.pipeline.events.len()
}
}