This commit is contained in:
Joshua Coles 2023-03-15 19:20:36 +00:00
parent 5f546a03b0
commit a9e80d6df9
7 changed files with 132 additions and 4 deletions

View File

@ -41,6 +41,7 @@ pub enum PCM {
Grid3KDTsang(StickProbabilityCli), Grid3KDTsang(StickProbabilityCli),
Grid3(StickProbabilityCli), Grid3(StickProbabilityCli),
Hex(StickProbabilityCli), Hex(StickProbabilityCli),
Balls2d(BallsCli),
Balls(BallsCli), Balls(BallsCli),
SurfaceProbabilityMeasure(SurfaceProbabilityMeasureCli), SurfaceProbabilityMeasure(SurfaceProbabilityMeasureCli),
} }

View File

@ -6,10 +6,11 @@ use clap::Parser;
use rand::prelude::*; use rand::prelude::*;
use crate::cli::{drive_system}; use crate::cli::{drive_system};
use crate::cli::cli::{StickProbabilityCli, InitialCli, BallsCli, PCM, ModelCli, SurfaceProbabilityMeasureCli}; use crate::cli::cli::{StickProbabilityCli, InitialCli, BallsCli, PCM, ModelCli, SurfaceProbabilityMeasureCli};
use crate::cli::cli::PCM::Balls2d;
use crate::cli::output::write; use crate::cli::output::write;
use crate::surface_probability_measure::{LoggerSticker, ReadOnlyVectorStorage}; use crate::surface_probability_measure::{LoggerSticker, ReadOnlyVectorStorage};
use crate::system::model::DLASystem; use crate::system::model::DLASystem;
use crate::system::spaces::continuous::{ContinuousSticker, ContinuousStorage, ContinuousWalker}; use crate::system::spaces::continuous_3d::{ContinuousSticker, ContinuousStorage, ContinuousWalker};
use crate::system::spaces::hexagonal::HexPosition; use crate::system::spaces::hexagonal::HexPosition;
use crate::system::spaces::kd_grid::{KDSpace}; use crate::system::spaces::kd_grid::{KDSpace};
use crate::system::spaces::square_grid::{Grid2D, Grid3D}; use crate::system::spaces::square_grid::{Grid2D, Grid3D};
@ -112,6 +113,22 @@ fn main() {
write(&sys, cli.format, &cli.output); write(&sys, cli.format, &cli.output);
} }
PCM::Balls2d(BallsCli { ball_radius, stick_distance, walk_step }) => {
use system::spaces::continuous_2d;
let mut sys = DLASystem::new(
SmallRng::seed_from_u64(cli.seed),
continuous_2d::ContinuousStorage { inner: kiddo::KdTree::new(), ball_radius_sq: ball_radius * ball_radius },
continuous_2d::ContinuousWalker { walk_step },
UniformSpawner,
continuous_2d::ContinuousSticker { range_sq: stick_distance * stick_distance },
cli.max_particles,
);
drive_system(&mut sys, cli.max_frames, cli.notify_every);
write(&sys, cli.format, &cli.output);
}
PCM::Balls(BallsCli { ball_radius, stick_distance, walk_step }) => { PCM::Balls(BallsCli { ball_radius, stick_distance, walk_step }) => {
let mut sys = DLASystem::new( let mut sys = DLASystem::new(
SmallRng::seed_from_u64(cli.seed), SmallRng::seed_from_u64(cli.seed),

View File

@ -0,0 +1,102 @@
use std::f32::consts::PI;
use std::ops::Add;
use kiddo::distance::squared_euclidean;
use rand::Rng;
use serde::Serialize;
use crate::system::sticker::Sticker;
use crate::system::{Position, Storage};
use crate::system::walker::Walker;
#[derive(Serialize, Debug, Clone)]
pub struct P2 {
x: f32,
y: f32,
}
impl P2 {
fn as_arr(&self) -> [f32; 2] {
[self.x, self.y]
}
pub fn random_with_radius<R: Rng>(rng: &mut R, radius: f32) -> P2 {
let theta = rng.gen_range(0f32..1.0) * 2.0 * PI;
let (x, y) = (
radius * theta.sin(),
radius * theta.sin(),
);
P2 { x, y }
}
}
impl Add for P2 {
type Output = P2;
fn add(self, rhs: Self) -> Self::Output {
P2 {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
pub struct ContinuousStorage {
pub inner: kiddo::KdTree<f32, (), 2>,
pub ball_radius_sq: f32,
}
impl Position for P2 {
type Cartesian = [f32; 2];
fn zero() -> Self {
P2 { x: 0f32, y: 0f32 }
}
fn abs(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).powf(0.5)
}
fn from_cartesian(cartesian: Self::Cartesian) -> Self {
P2 { x: cartesian[0], y: cartesian[1] }
}
fn to_cartesian(&self) -> Self::Cartesian {
[self.x, self.y]
}
}
impl Storage<P2> for ContinuousStorage {
fn is_occupied(&self, position: &P2) -> bool {
let (dist_sq, _) = self.inner.nearest_one(&position.as_arr(), &squared_euclidean).unwrap();
// Is the distance of this point to the next one less than twice the ball radius
dist_sq < 2.0 * self.ball_radius_sq
}
fn deposit(&mut self, position: &P2) {
self.inner.add(&position.as_arr(), ()).expect("Failed to write to space")
}
}
pub struct ContinuousSticker {
/// INVARIANT: THIS SHOULD BE GREATER THAN THE BALL_RADIUS_SQ value
pub range_sq: f32,
}
impl Sticker<P2, ContinuousStorage> for ContinuousSticker {
fn should_stick<R: Rng>(&self, _rng: &mut R, space: &ContinuousStorage, position: &P2) -> bool {
let (a, _) = space.inner.nearest_one(&position.as_arr(), &squared_euclidean).unwrap();
a < self.range_sq
}
}
pub struct ContinuousWalker {
pub walk_step: f32
}
impl Walker<P2> for ContinuousWalker {
fn walk<R: Rng>(&self, rng: &mut R, position: &P2) -> P2 {
position.clone() + P2::random_with_radius(rng, self.walk_step)
}
}

View File

@ -5,4 +5,5 @@ pub mod square_grid;
pub mod kd_grid; pub mod kd_grid;
pub mod hexagonal; pub mod hexagonal;
pub mod continuous; pub mod continuous_3d;
pub mod continuous_2d;

View File

@ -80,7 +80,7 @@ impl GriddedPosition for Grid2D {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Grid3D { pub struct Grid3D {
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,

View File

@ -1,7 +1,8 @@
use std::f32::consts::PI; use std::f32::consts::PI;
use rand::Rng; use rand::Rng;
use crate::system::Position; use crate::system::Position;
use crate::system::spaces::continuous::P3; use crate::system::spaces::continuous_2d::P2;
use crate::system::spaces::continuous_3d::P3;
use crate::system::spaces::hexagonal::HexPosition; use crate::system::spaces::hexagonal::HexPosition;
use crate::system::spaces::square_grid::{Grid2D, Grid3D}; use crate::system::spaces::square_grid::{Grid2D, Grid3D};
@ -49,3 +50,9 @@ impl Spawner<P3> for UniformSpawner {
P3::random_with_radius(rng, radius) P3::random_with_radius(rng, radius)
} }
} }
impl Spawner<P2> for UniformSpawner {
fn spawn<R: Rng>(&self, rng: &mut R, radius: f32) -> P2 {
P2::random_with_radius(rng, radius)
}
}