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

View File

@ -1,11 +1,29 @@
{ {
"bodies": [ "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", "name": "Earth",
"mass": 5.972e24, "mass": 5.972e24,
"position": [1.47095e11, 0, 0], "position": [1.47095e11, 0, 0],
"velocity": [0, 29290, 0] "velocity": [0, 29290, 0]
}, },
{
"name": "Moon",
"mass": 7.34767309e22,
"position": [149982270700, 0, 0],
"velocity": [0, 30822, 0]
},
{ {
"name": "Sun", "name": "Sun",
"mass": 1.989e30, "mass": 1.989e30,
@ -13,4 +31,4 @@
"velocity": [0, 0, 0] "velocity": [0, 0, 0]
} }
] ]
} }

View File

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

View File

@ -3,11 +3,13 @@ use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::path::Path; use std::path::Path;
use std::time::Duration;
// External crates // External crates
use clap::Parser; use clap::Parser;
use log::{info, warn, error, debug, trace}; use log::{info, warn, error, debug, trace};
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use humantime;
// Internal modules // Internal modules
mod types; mod types;
@ -15,7 +17,9 @@ mod config;
mod simulator; mod simulator;
// Specific uses from modules // 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)] #[derive(Parser, Debug)]
#[command( #[command(
@ -29,9 +33,21 @@ struct Args {
#[arg(short, long)] #[arg(short, long)]
config: String, 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) ///Step size for simulation (seconds)
#[arg(short, long, default_value_t = 10)] #[arg(short, long, default_value_t = 10.0)]
step_size: u8, 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>> { 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); info!("Loaded {} with mass {:.3e} kg", body.name, body.mass);
debug!("R_i = {:?}, V_i = {:?}", body.position, body.velocity); 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( 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() .unwrap()
.progress_chars("=>-"), .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 log::{info, warn, error, debug, trace};
use glam::DVec3; use glam::DVec3;
use crate::config::Body; 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>, bodies: Vec<Body>,
step_size: f64, step_size: f64,
steps_per_save: usize, steps_per_save: usize,
save_file: String
} }
impl Simulator { #[derive(Serialize)]
pub fn new(mut bodies: Vec<Body>, mut step_size: f64, steps_per_save: usize) -> Self { 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(); let n = bodies.len();
for i in 0..n { for i in 0..n {
bodies[i].mass = norm_mass(bodies[i].mass); bodies[i].mass = norm_mass(bodies[i].mass);
@ -19,17 +35,31 @@ impl Simulator {
bodies[i].velocity = norm_vel(bodies[i].velocity); bodies[i].velocity = norm_vel(bodies[i].velocity);
} }
step_size = norm_time(step_size); 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>) pub fn run<F>(&mut self, steps: usize, mut on_step: Option<F>)
where F: FnMut() { 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 { for i in 0..steps {
debug!("Step: {}", i); debug!("Step: {}", i);
self.reset_accelerations(); self.reset_accelerations();
self.caclulate_accelerations(); self.caclulate_accelerations();
self.step_bodies(); 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 { if let Some(f) = &mut on_step {
f(); f();
} }

View File

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