implementing save trajectory

This commit is contained in:
Thomas Faour 2025-06-19 20:57:13 -04:00
parent 151e11076b
commit be6229263d
6 changed files with 108 additions and 31 deletions

View File

@ -7,9 +7,11 @@ authors = ["thomas"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bincode = "1.3"
clap = { version = "4.5.39", features = ["derive"] }
env_logger = "0.11.8"
glam = { version = "0.30.4", features = ["serde"] }
humantime = "2.2.0"
indicatif = "0.17.11"
log = "0.4.27"
once_cell = "1.21.3"

View File

@ -1,11 +1,29 @@
{
"bodies": [
{
"name": "Mercury",
"mass": 3.30104e23,
"position": [4.6000e10, 0, 0],
"velocity": [0, 58970, 0]
},
{
"name": "Venus",
"mass": 4.867e24,
"position": [1.08941e11, 0, 0],
"velocity": [0, 34780, 0]
},
{
"name": "Earth",
"mass": 5.972e24,
"position": [1.47095e11, 0, 0],
"velocity": [0, 29290, 0]
},
{
"name": "Moon",
"mass": 7.34767309e22,
"position": [149982270700, 0, 0],
"velocity": [0, 30822, 0]
},
{
"name": "Sun",
"mass": 1.989e30,
@ -13,4 +31,4 @@
"velocity": [0, 0, 0]
}
]
}
}

View File

@ -1,7 +1,8 @@
use crate::types;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Serialize)]
pub struct Body {
pub name: String,
pub mass: types::Mass,

View File

@ -3,11 +3,13 @@ use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::time::Duration;
// External crates
use clap::Parser;
use log::{info, warn, error, debug, trace};
use indicatif::{ProgressBar, ProgressStyle};
use humantime;
// Internal modules
mod types;
@ -15,7 +17,9 @@ mod config;
mod simulator;
// Specific uses from modules
use crate::simulator::Simulator;
use crate::simulator::Simulation;
use crate::types::{norm_mass, norm_pos, norm_vel, norm_time, real_pos, real_vel};
#[derive(Parser, Debug)]
#[command(
@ -29,9 +33,21 @@ struct Args {
#[arg(short, long)]
config: String,
/// Time to run simulation for (e.g. 10s, 5m, 2h, 100d)
#[arg(short, long, value_parser = humantime::parse_duration)]
time: Duration,
///Step size for simulation (seconds)
#[arg(short, long, default_value_t = 10)]
step_size: u8,
#[arg(short, long, default_value_t = 10.0)]
step_size: f64,
///How often to update progress bar and save (seconds)
#[arg(short = 'P', long, default_value_t = 1000)]
steps_per_save: usize,
/// Filename to save trajectory to
#[arg(short, long)]
output_file: String,
}
fn read_config<P: AsRef<Path>>(path: P) -> Result<config::ConfigFile, Box<dyn Error>> {
@ -55,13 +71,22 @@ fn main() {
info!("Loaded {} with mass {:.3e} kg", body.name, body.mass);
debug!("R_i = {:?}, V_i = {:?}", body.position, body.velocity);
}
let steps: usize = 10000000;
let pb = ProgressBar::new(steps.try_into().unwrap());
let n_steps = (args.time.as_secs() as f64 / args.step_size) as usize;
let pb = ProgressBar::new(n_steps.try_into().unwrap());
pb.set_style(
ProgressStyle::with_template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>3}/{len:3} {msg}")
ProgressStyle::with_template("[{elapsed_precise}] {bar:40.cyan/blue} {percent_precise}% {eta} {msg}")
.unwrap()
.progress_chars("=>-"),
);
let mut sim = Simulator::new(conf.bodies, 0.5, 10000);
sim.run(steps, Some(|| pb.inc(10000)));
let mut sim = Simulation::new(
conf.bodies,
norm_time(args.step_size),
args.steps_per_save,
args.output_file,
);
sim.run(n_steps, Some(|| pb.inc(args.steps_per_save as u64)));
}

View File

@ -1,17 +1,33 @@
use std::fs::OpenOptions;
use std::io::BufWriter;
use serde::{Deserialize, Serialize};
use log::{info, warn, error, debug, trace};
use glam::DVec3;
use crate::config::Body;
use crate::types::{norm_mass, norm_pos, norm_vel, norm_time, real_pos, real_vel};
use crate::types::{norm_mass, norm_pos, norm_vel, norm_time, real_pos, real_vel, real_time};
pub struct Simulator {
pub struct Simulation {
bodies: Vec<Body>,
step_size: f64,
steps_per_save: usize,
save_file: String
}
impl Simulator {
pub fn new(mut bodies: Vec<Body>, mut step_size: f64, steps_per_save: usize) -> Self {
#[derive(Serialize)]
struct Snapshot<'a> {
time: f64,
bodies: &'a [Body],
}
impl Simulation {
pub fn new(
mut bodies: Vec<Body>,
mut step_size: f64,
steps_per_save: usize,
save_file: String,
) -> Self {
let n = bodies.len();
for i in 0..n {
bodies[i].mass = norm_mass(bodies[i].mass);
@ -19,17 +35,31 @@ impl Simulator {
bodies[i].velocity = norm_vel(bodies[i].velocity);
}
step_size = norm_time(step_size);
Self {bodies, step_size, steps_per_save}
Self {bodies, step_size, steps_per_save, save_file}
}
pub fn run<F>(&mut self, steps: usize, mut on_step: Option<F>)
where F: FnMut() {
let file = OpenOptions::new()
.create(true)
.append(true)
.open(&self.save_file);
let mut writer = BufWriter::new(file.unwrap());
for i in 0..steps {
debug!("Step: {}", i);
self.reset_accelerations();
self.caclulate_accelerations();
self.step_bodies();
if (i%self.steps_per_save == 0) {
if i % self.steps_per_save == 0 {
//save the state
let snapshot = Snapshot {
time: real_time(i as f64*self.step_size),
bodies: &self.bodies,
};
bincode::serialize_into(&mut writer, &snapshot);
//Do the progress bar
if let Some(f) = &mut on_step {
f();
}

View File

@ -1,3 +1,4 @@
#![allow(unused)]
use glam::DVec3;
use once_cell::sync::Lazy;
@ -23,62 +24,62 @@ const SUN_MASS: f64 = 1.989e30; //kg
const SUN_RADIUS: f64 = 6.957e8; //meters
const G: f64 = 6.67430e-11;
const r_0: f64 = EARTH_RADIUS;
const m_0: f64 = EARTH_MASS;
const R_0: f64 = EARTH_RADIUS;
const M_0: f64 = EARTH_MASS;
static t_0: Lazy<f64> = Lazy::new(|| {
(r_0.powf(3.0) / (G * m_0)).sqrt()
static T_0: Lazy<f64> = Lazy::new(|| {
(R_0.powf(3.0) / (G * M_0)).sqrt()
});
#[inline]
pub fn norm_pos(pos: Position) -> Position {
pos / r_0
pos / R_0
}
#[inline]
pub fn real_pos(pos: Position) -> Position {
pos * r_0
pos * R_0
}
#[inline]
pub fn norm_mass(mass: Mass) -> Mass {
mass / m_0
mass / M_0
}
#[inline]
pub fn real_mass(mass: Mass) -> Mass {
mass * m_0
mass * M_0
}
#[inline]
pub fn norm_time(time: Time) -> Time {
time / *t_0
time / *T_0
}
#[inline]
pub fn real_time(time: Time) -> Time {
time * *t_0
time * *T_0
}
#[inline]
pub fn norm_vel(vel: Velocity) -> Velocity {
vel / (r_0 / *t_0)
vel / (R_0 / *T_0)
}
#[inline]
pub fn real_vel(vel: Velocity) -> Velocity {
vel * (r_0 / *t_0)
vel * (R_0 / *T_0)
}
#[inline]
pub fn norm_acc(acc: Acceleration) -> Acceleration {
acc / (r_0 / (*t_0 * *t_0))
acc / (R_0 / (*T_0 * *T_0))
}
#[inline]
pub fn real_acc(acc: Acceleration) -> Acceleration {
acc * (r_0 / (*t_0 * *t_0))
acc * (R_0 / (*T_0 * *T_0))
}
#[inline]