diff --git a/Cargo.toml b/Cargo.toml index 266f8df..6af2de1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,19 @@ Kessler is a library for simulating fragmentation events in low Earth orbit. [dependencies] blas-src = { version = "0.8", features = ["openblas"] } -ndarray = { version = "=0.15.6", features = ["blas", "rayon"] } +js-sys = "0.3.67" +ndarray = { version = "=0.15.6", features = ["blas", "rayon", "serde"] } ndarray-linalg = "0.14" ndarray-rand = "0.13.0" openblas-src = { version = "0.10", features = ["cblas", "system"] } rand = "0.8.5" rand_distr = "0.4.3" +serde = { version = "1.0", features = ["derive"] } +serde-wasm-bindgen = "0.4" +wasm-bindgen = { version = "0.2.90", features = ["serde"]} + +[lib] +crate-type = ["cdylib", "rlib"] [profile.release] strip = true # Strip symbols from the binary diff --git a/src/event.rs b/src/event.rs index e3fd204..f87bca3 100644 --- a/src/event.rs +++ b/src/event.rs @@ -2,6 +2,7 @@ use crate::satellite::{SatKind, Satellite}; use ndarray::*; use ndarray_linalg::*; +use wasm_bindgen::prelude::*; pub trait FragmentationEvent { fn fragment_count(&self, min_characteristic_len: f32) -> f32; @@ -14,19 +15,22 @@ pub trait FragmentationEvent { fn delta_velocity_offset(&self) -> [f32; 2]; } +#[wasm_bindgen] #[derive(Debug)] pub struct CollisionEvent { pub min_characteristic_length: f32, pub sat_kind: SatKind, pub input_mass: f32, - pub satellites: Array1, pub max_characteristic_length: f32, + satellites: Vec, } +#[wasm_bindgen] impl CollisionEvent { - pub fn new(satellites: &[Satellite], min_characteristic_length: f32) -> CollisionEvent { - let mut satellite_1 = satellites[0].clone(); - let mut satellite_2 = satellites[1].clone(); + #[wasm_bindgen(constructor)] + pub fn new(satellites: Vec, min_characteristic_length: f32) -> CollisionEvent { + let mut satellite_1 = satellites[0].to_owned(); + let mut satellite_2 = satellites[1].to_owned(); let max_characteristic_length = satellite_1.characteristic_length.max(satellite_2.characteristic_length); let mut sat_kind = SatKind::Soc; if satellite_1.sat_kind == SatKind::Rb || satellite_2.sat_kind == SatKind::Rb { @@ -39,14 +43,14 @@ impl CollisionEvent { if satellite_2.characteristic_length > satellite_1.characteristic_length { std::mem::swap(&mut satellite_1, &mut satellite_2) } - let satellites = array![satellite_1, satellite_2]; + let satellites = vec![satellite_1, satellite_2]; CollisionEvent { min_characteristic_length, sat_kind, input_mass, satellites, - max_characteristic_length + max_characteristic_length, } } @@ -90,7 +94,9 @@ impl FragmentationEvent for CollisionEvent { let satellite_2 = &self.satellites[1]; // Determine impact velocity - let v_impact = (&satellite_1.velocity - &satellite_2.velocity).norm(); + let v1 = satellite_1.get_velocity(); + let v2 = satellite_2.get_velocity(); + let v_impact = (Array1::from_vec(v1) - Array1::from_vec(v2)).norm(); // Target is the larger satellite let m_targ = satellite_1.mass; @@ -104,7 +110,8 @@ impl FragmentationEvent for CollisionEvent { } fn location(&self) -> Array1 { - self.satellites[0].position.to_owned() + let position = self.satellites[0].get_position(); + Array1::from_vec(position) } fn min_characteristic_length(&self) -> f32 { @@ -128,16 +135,19 @@ impl FragmentationEvent for CollisionEvent { } } +#[wasm_bindgen] #[derive(Debug, Clone)] pub struct ExplosionEvent { pub min_characteristic_length: f32, pub sat_type: SatKind, pub input_mass: f32, - pub satellites: Array1, pub max_characteristic_length: f32, + satellites: Vec, } +#[wasm_bindgen] impl ExplosionEvent { + #[wasm_bindgen(constructor)] pub fn new(satellite: Satellite, min_characteristic_length: f32) -> ExplosionEvent { let input_mass = satellite.mass; let sat_type = satellite.sat_kind.clone(); @@ -147,8 +157,8 @@ impl ExplosionEvent { min_characteristic_length, input_mass, sat_type, - satellites: array![satellite], - max_characteristic_length + satellites: vec![satellite], + max_characteristic_length, } } } @@ -164,7 +174,8 @@ impl FragmentationEvent for ExplosionEvent { } fn location(&self) -> Array1 { - self.satellites.get(0).unwrap().position.to_owned() + let position = self.satellites.get(0).unwrap().get_position(); + Array1::from_vec(position) } fn min_characteristic_length(&self) -> f32 { diff --git a/src/lib.rs b/src/lib.rs index dd48e2e..0484ba6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,24 @@ use ndarray::{s, Array, Array1, Array2, Array3}; use rand::distributions::{Distribution, Uniform}; use rand_distr::{Normal, UnitSphere}; +// Non-WebAssembly bindings +#[cfg(not(target_arch = "wasm32"))] pub fn run(event: &impl FragmentationEvent) -> Array3 { + run_core(event) +} + +// WebAssembly bindings +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::{prelude::*, JsValue}; + +#[cfg(target_arch = "wasm32")] +pub fn run(event: &impl FragmentationEvent) -> Option { + let result = run_core(event); + // Convert the result to JsValue + serde_wasm_bindgen::to_value(&result).ok() +} + +fn run_core(event: &impl FragmentationEvent) -> Array3 { let characteristic_len_min = event.min_characteristic_length(); let fragment_count = event.fragment_count(characteristic_len_min).floor() as usize; let location = event.location(); diff --git a/src/satellite.rs b/src/satellite.rs index 083774a..178cfad 100644 --- a/src/satellite.rs +++ b/src/satellite.rs @@ -1,32 +1,48 @@ use ndarray::prelude::*; +use wasm_bindgen::prelude::*; +#[wasm_bindgen] #[derive(Debug, Clone)] pub struct Satellite { - pub position: Array1, - pub velocity: Array1, pub mass: f32, pub characteristic_length: f32, pub sat_kind: SatKind, + position: Array1, + velocity: Array1, } +#[wasm_bindgen] impl Satellite { - pub fn new( - position: impl Into<[f32; 3]>, - velocity: impl Into<[f32; 3]>, - mass: f32, - sat_kind: SatKind, - ) -> Self { + #[wasm_bindgen(constructor)] + pub fn new(position: Vec, velocity: Vec, mass: f32, sat_kind: SatKind) -> Self { Self { - position: Array1::from(position.into().to_vec()), - velocity: Array1::from(velocity.into().to_vec()), + position: Array1::from_vec(position), + velocity: Array1::from_vec(velocity), mass, characteristic_length: calculate_characteristic_length_from_mass(mass), sat_kind, } } + + pub fn set_position(&mut self, position: &[f32]) { + self.position = Array1::from_vec(position.to_vec()); + } + + pub fn set_velocity(&mut self, velocity: &[f32]) { + self.velocity = Array1::from_vec(velocity.to_vec()); + } + + pub fn get_position(&self) -> Vec { + self.position.to_vec() + } + + pub fn get_velocity(&self) -> Vec { + self.velocity.to_vec() + } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[wasm_bindgen] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum SatKind { Rb = 0, Soc = 1, diff --git a/tests/explosion.rs b/tests/explosion.rs index db84ea9..b949f23 100644 --- a/tests/explosion.rs +++ b/tests/explosion.rs @@ -3,10 +3,9 @@ use kessler::{run, ExplosionEvent, SatKind, Satellite}; #[test] fn explosion_nimbus() { - // Define the initial position, velocity, mass, characteristic length, and kind of a satellite. - let position = [0.0, 0.0, 0.0]; // position vector [m] relative to Earth's center - let velocity = [0.0, 0.0, 0.0]; // velocity vector [m/s] + let position = vec![0.0, 0.0, 0.0]; // position vector [m] relative to Earth's center + let velocity = vec![0.0, 0.0, 0.0]; // velocity vector [m/s] let mass = 849.0; // kg let characteristic_length = 0.1; // m let sat_kind = SatKind::Rb; // kind of satellite (Rb, Debris, or Satellite)