Compare commits
4 Commits
183293fe7e
...
73bb0f8ed1
| Author | SHA1 | Date | |
|---|---|---|---|
| 73bb0f8ed1 | |||
| 58f19cdb9a | |||
| 9f74ec2ef0 | |||
| cef9024bc5 |
@ -25,13 +25,23 @@ pub struct BallsCli {
|
|||||||
pub walk_step: f32,
|
pub walk_step: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
pub struct SurfaceProbabilityMeasureCli {
|
||||||
|
pub grid_size: u32,
|
||||||
|
pub stick_probability: f32,
|
||||||
|
pub initial_data: PathBuf,
|
||||||
|
pub particles: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub enum PCM {
|
pub enum PCM {
|
||||||
Initial(InitialCli),
|
Initial(InitialCli),
|
||||||
StickProbability(StickProbabilityCli),
|
StickProbability(StickProbabilityCli),
|
||||||
|
Grid3KD(StickProbabilityCli),
|
||||||
Grid3(StickProbabilityCli),
|
Grid3(StickProbabilityCli),
|
||||||
Hex(StickProbabilityCli),
|
Hex(StickProbabilityCli),
|
||||||
Balls(BallsCli)
|
Balls(BallsCli),
|
||||||
|
SurfaceProbabilityMeasure(SurfaceProbabilityMeasureCli),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use crate::system::{Position, Storage};
|
|||||||
use crate::system::spawner::Spawner;
|
use crate::system::spawner::Spawner;
|
||||||
use crate::system::sticker::Sticker;
|
use crate::system::sticker::Sticker;
|
||||||
use crate::system::walker::Walker;
|
use crate::system::walker::Walker;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
@ -13,12 +14,22 @@ pub fn drive_system<R: Rng, P: Position, S: Storage<P>, W: Walker<P>, Sp: Spawne
|
|||||||
max_frames: Option<usize>,
|
max_frames: Option<usize>,
|
||||||
notify_every: Option<usize>,
|
notify_every: Option<usize>,
|
||||||
) {
|
) {
|
||||||
|
let start = SystemTime::now();
|
||||||
|
let mut prev = start.clone();
|
||||||
let mut previous_n: usize = 0;
|
let mut previous_n: usize = 0;
|
||||||
while sys.running {
|
while sys.running {
|
||||||
sys.update();
|
sys.update();
|
||||||
|
|
||||||
if let Some(notify_every) = notify_every && (sys.history.len() % notify_every) == 0 && previous_n != sys.history.len() {
|
if let Some(notify_every) = notify_every && (sys.history.len() % notify_every) == 0 && previous_n != sys.history.len() {
|
||||||
println!("On frame {}, deposited {} particles", sys.frame, sys.history.len());
|
let now = SystemTime::now();
|
||||||
|
|
||||||
|
println!("[{}ms, d = {}ms] On frame {}, deposited {} particles",
|
||||||
|
now.duration_since(start).unwrap().as_millis(),
|
||||||
|
now.duration_since(prev).unwrap().as_millis(),
|
||||||
|
sys.frame, sys.history.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
prev = now;
|
||||||
previous_n = sys.history.len();
|
previous_n = sys.history.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
53
src/main.rs
53
src/main.rs
@ -2,14 +2,17 @@
|
|||||||
#![feature(generic_const_exprs)]
|
#![feature(generic_const_exprs)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
use clap::Parser;
|
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};
|
use crate::cli::cli::{StickProbabilityCli, InitialCli, BallsCli, PCM, ModelCli, SurfaceProbabilityMeasureCli};
|
||||||
use crate::cli::output::write;
|
use crate::cli::output::write;
|
||||||
|
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::{ContinuousSticker, ContinuousStorage, ContinuousWalker};
|
||||||
use crate::system::spaces::hexagonal::HexPosition;
|
use crate::system::spaces::hexagonal::HexPosition;
|
||||||
|
use crate::system::spaces::kd_grid::{KDGrid, KDGrid2Sticker};
|
||||||
use crate::system::spaces::square_grid::{Grid2D, Grid3D};
|
use crate::system::spaces::square_grid::{Grid2D, Grid3D};
|
||||||
use crate::system::spaces::VectorStorage;
|
use crate::system::spaces::VectorStorage;
|
||||||
use crate::system::spawner::UniformSpawner;
|
use crate::system::spawner::UniformSpawner;
|
||||||
@ -54,6 +57,20 @@ fn main() {
|
|||||||
write(&sys, cli.format, &cli.output);
|
write(&sys, cli.format, &cli.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PCM::Grid3KD(StickProbabilityCli { grid_size, stick_probability }) => {
|
||||||
|
let mut sys = DLASystem::<_, Grid2D, _, _, _, _>::new(
|
||||||
|
SmallRng::seed_from_u64(cli.seed),
|
||||||
|
KDGrid { inner: kiddo::KdTree::new() },
|
||||||
|
LocalRandomWalker,
|
||||||
|
UniformSpawner,
|
||||||
|
KDGrid2Sticker { stick_probability },
|
||||||
|
cli.max_particles,
|
||||||
|
);
|
||||||
|
|
||||||
|
drive_system(&mut sys, cli.max_frames, cli.notify_every);
|
||||||
|
write(&sys, cli.format, &cli.output);
|
||||||
|
}
|
||||||
|
|
||||||
PCM::Grid3(StickProbabilityCli { grid_size, stick_probability }) => {
|
PCM::Grid3(StickProbabilityCli { grid_size, stick_probability }) => {
|
||||||
let mut sys = DLASystem::<_, Grid3D, _, _, _, _>::new(
|
let mut sys = DLASystem::<_, Grid3D, _, _, _, _>::new(
|
||||||
SmallRng::seed_from_u64(cli.seed),
|
SmallRng::seed_from_u64(cli.seed),
|
||||||
@ -95,5 +112,39 @@ fn main() {
|
|||||||
drive_system(&mut sys, cli.max_frames, cli.notify_every);
|
drive_system(&mut sys, cli.max_frames, cli.notify_every);
|
||||||
write(&sys, cli.format, &cli.output);
|
write(&sys, cli.format, &cli.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PCM::SurfaceProbabilityMeasure(SurfaceProbabilityMeasureCli { grid_size, stick_probability, particles, initial_data }) => {
|
||||||
|
let logger_sticker = LoggerSticker::new(stick_probability);
|
||||||
|
|
||||||
|
let mut sys = DLASystem::new(
|
||||||
|
SmallRng::seed_from_u64(cli.seed),
|
||||||
|
ReadOnlyVectorStorage::new(&initial_data, grid_size),
|
||||||
|
LocalRandomWalker,
|
||||||
|
UniformSpawner,
|
||||||
|
&logger_sticker,
|
||||||
|
cli.max_particles,
|
||||||
|
);
|
||||||
|
|
||||||
|
let particles = particles as usize;
|
||||||
|
|
||||||
|
while sys.running && logger_sticker.stick_positions.borrow().len() < particles {
|
||||||
|
sys.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut writer = csv::Writer::from_path(cli.output)
|
||||||
|
.expect("Failed to open output path");
|
||||||
|
|
||||||
|
let stick_positions = logger_sticker.stick_positions.borrow();
|
||||||
|
|
||||||
|
stick_positions
|
||||||
|
.iter()
|
||||||
|
.for_each(|pos|
|
||||||
|
writer.serialize(pos)
|
||||||
|
.expect("Failed to write position")
|
||||||
|
);
|
||||||
|
|
||||||
|
writer.flush()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use rand::rngs::SmallRng;
|
use rand::rngs::SmallRng;
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use crate::system::model::DLASystem;
|
use crate::system::model::DLASystem;
|
||||||
@ -8,41 +10,61 @@ use crate::system::spawner::UniformSpawner;
|
|||||||
use crate::system::sticker::{ProbabilisticSticking, SimpleSticking, Sticker};
|
use crate::system::sticker::{ProbabilisticSticking, SimpleSticking, Sticker};
|
||||||
use crate::system::walker::LocalRandomWalker;
|
use crate::system::walker::LocalRandomWalker;
|
||||||
|
|
||||||
struct LoggerSticker {
|
pub struct LoggerSticker {
|
||||||
inner: SimpleSticking
|
inner: ProbabilisticSticking,
|
||||||
|
pub stick_positions: RefCell<Vec<Grid2D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Storage<Grid2D>> Sticker<Grid2D, S> for LoggerSticker {
|
impl LoggerSticker {
|
||||||
fn should_stick<R: Rng>(&self, rng: &mut R, space: &S, position: &Grid2D) -> bool {
|
pub fn new(stick_probability: f32) -> LoggerSticker {
|
||||||
if self.inner.should_stick(rng, space, position) {
|
LoggerSticker {
|
||||||
println!("{:?}", position);
|
inner: ProbabilisticSticking { stick_probability },
|
||||||
|
stick_positions: RefCell::new(Vec::new()),
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReadOnlyVectorStorage {
|
impl<S: Storage<Grid2D>> Sticker<Grid2D, S> for &LoggerSticker {
|
||||||
|
fn should_stick<R: Rng>(&self, rng: &mut R, space: &S, position: &Grid2D) -> bool {
|
||||||
|
let should_stick = self.inner.should_stick(rng, space, position);
|
||||||
|
|
||||||
|
if should_stick {
|
||||||
|
self.stick_positions.borrow_mut()
|
||||||
|
.push(position.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes are ignored so we deposit to delete the particle but it is not written
|
||||||
|
should_stick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ReadOnlyVectorStorage {
|
||||||
inner: VectorStorage,
|
inner: VectorStorage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReadOnlyVectorStorage {
|
||||||
|
pub fn new(path: &Path, grid_size: u32) -> ReadOnlyVectorStorage {
|
||||||
|
let mut inner = VectorStorage::new(grid_size, 2);
|
||||||
|
let positions: Vec<Grid2D> = csv::Reader::from_path(path)
|
||||||
|
.expect("Failed to read initial data")
|
||||||
|
.deserialize::<Grid2D>()
|
||||||
|
.map(|row| row.expect("Failed to read row"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for pos in positions {
|
||||||
|
inner.deposit(&pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlyVectorStorage { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Storage<Grid2D> for ReadOnlyVectorStorage {
|
impl Storage<Grid2D> for ReadOnlyVectorStorage {
|
||||||
fn is_occupied(&self, position: &Grid2D) -> bool {
|
fn is_occupied(&self, position: &Grid2D) -> bool {
|
||||||
self.inner.is_occupied(position)
|
self.inner.is_occupied(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deposit(&mut self, position: &Grid2D) {
|
fn deposit(&mut self, position: &Grid2D) {
|
||||||
eprintln!("Write ignore for space at {position:?}");
|
eprintln!("Write ignored for space at {position:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn surface_probability_measure(seed: u64, max_particles: usize, stick_probability: f32) -> DLASystem<SmallRng, Grid2D, VectorStorage, LocalRandomWalker, UniformSpawner, ProbabilisticSticking> {
|
|
||||||
DLASystem::new(
|
|
||||||
SmallRng::seed_from_u64(seed),
|
|
||||||
VectorStorage::new(1600, 3),
|
|
||||||
LocalRandomWalker,
|
|
||||||
UniformSpawner,
|
|
||||||
ProbabilisticSticking { stick_probability },
|
|
||||||
max_particles,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
71
src/system/spaces/kd_grid.rs
Normal file
71
src/system/spaces/kd_grid.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
use crate::system::{GriddedPosition, Position, Storage};
|
||||||
|
use crate::system::spaces::square_grid::{Grid2D, Grid3D};
|
||||||
|
use crate::system::sticker::Sticker;
|
||||||
|
|
||||||
|
fn taxicab_grid2(a: &[f32; 2], b: &[f32; 2]) -> f32 {
|
||||||
|
(a[0] - b[0]).abs() + (a[1] - b[1]).abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn taxicab_grid3(a: &[f32; 3], b: &[f32; 3]) -> f32 {
|
||||||
|
(a[0] - b[0]).abs() + (a[1] - b[1]).abs() + (a[2] - b[2]).abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KDGrid<const N: usize> {
|
||||||
|
pub(crate) inner: kiddo::KdTree<f32, (), N>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage<Grid2D> for KDGrid<2> {
|
||||||
|
fn is_occupied(&self, position: &Grid2D) -> bool {
|
||||||
|
let a = self.inner.best_n_within(&[position.x as f32, position.y as f32], 0f32, 1, &taxicab_grid2).unwrap();
|
||||||
|
!a.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deposit(&mut self, position: &Grid2D) {
|
||||||
|
self.inner.add(&[position.x as f32, position.y as f32], ())
|
||||||
|
.expect("Failed to write to space")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage<Grid3D> for KDGrid<3> {
|
||||||
|
fn is_occupied(&self, position: &Grid3D) -> bool {
|
||||||
|
let a = self.inner.best_n_within(&[position.x as f32, position.y as f32, position.z as f32], 0f32, 1, &taxicab_grid3).unwrap();
|
||||||
|
!a.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deposit(&mut self, position: &Grid3D) {
|
||||||
|
self.inner.add(&[position.x as f32, position.y as f32, position.z as f32], ())
|
||||||
|
.expect("Failed to write to space")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct KDGrid2Sticker {
|
||||||
|
pub(crate) stick_probability: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sticker<Grid2D, KDGrid<2>> for KDGrid2Sticker {
|
||||||
|
fn should_stick<R: Rng>(&self, rng: &mut R, space: &KDGrid<2>, position: &Grid2D) -> bool {
|
||||||
|
let a = space.inner.best_n_within(&[position.x as f32, position.y as f32], 1f32, Grid2D::NEIGHBOURS as usize, &taxicab_grid2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if a.len() == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let q = (1f32 - self.stick_probability);
|
||||||
|
let a = q.powi(a.len() as i32);
|
||||||
|
rng.gen_range(0f32..1f32) > a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sticker<Grid3D, KDGrid<3>> for KDGrid2Sticker {
|
||||||
|
fn should_stick<R: Rng>(&self, rng: &mut R, space: &KDGrid<3>, position: &Grid3D) -> bool {
|
||||||
|
let a = space.inner.best_n_within(&[position.x as f32, position.y as f32, position.z as f32], 1f32, Grid2D::NEIGHBOURS as usize, &taxicab_grid3)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let q = (1f32 - self.stick_probability);
|
||||||
|
let a = q.powi(a.len() as i32);
|
||||||
|
rng.gen_range(0f32..1f32) > a
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ pub mod vector_storage;
|
|||||||
pub use vector_storage::VectorStorage;
|
pub use vector_storage::VectorStorage;
|
||||||
|
|
||||||
pub mod square_grid;
|
pub mod square_grid;
|
||||||
|
pub mod kd_grid;
|
||||||
pub mod hexagonal;
|
pub mod hexagonal;
|
||||||
|
|
||||||
pub mod continuous;
|
pub mod continuous;
|
||||||
|
|||||||
@ -26,4 +26,3 @@ impl<P: GriddedPosition, S: Storage<P>> Sticker<P, S> for ProbabilisticSticking
|
|||||||
.any(|neighbour| space.is_occupied(&neighbour) && rng.gen_range(0.0f32..=1.0) < self.stick_probability)
|
.any(|neighbour| space.is_occupied(&neighbour) && rng.gen_range(0.0f32..=1.0) < self.stick_probability)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user