diff --git a/src/cli/cli.rs b/src/cli/cli.rs index 4be7745..4ad7d3d 100644 --- a/src/cli/cli.rs +++ b/src/cli/cli.rs @@ -25,13 +25,22 @@ pub struct BallsCli { 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)] pub enum PCM { Initial(InitialCli), StickProbability(StickProbabilityCli), Grid3(StickProbabilityCli), Hex(StickProbabilityCli), - Balls(BallsCli) + Balls(BallsCli), + SurfaceProbabilityMeasure(SurfaceProbabilityMeasureCli), } #[derive(Parser, Debug)] diff --git a/src/main.rs b/src/main.rs index dfb27ea..0b5b9c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,13 @@ #![feature(generic_const_exprs)] #![feature(let_chains)] +use std::ops::Deref; use clap::Parser; use rand::prelude::*; 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::surface_probability_measure::{LoggerSticker, ReadOnlyVectorStorage}; use crate::system::model::DLASystem; use crate::system::spaces::continuous::{ContinuousSticker, ContinuousStorage, ContinuousWalker}; use crate::system::spaces::hexagonal::HexPosition; @@ -95,5 +97,39 @@ fn main() { drive_system(&mut sys, cli.max_frames, cli.notify_every); 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(); + } } } diff --git a/src/surface_probability_measure.rs b/src/surface_probability_measure.rs index 25c46a7..df20df3 100644 --- a/src/surface_probability_measure.rs +++ b/src/surface_probability_measure.rs @@ -1,3 +1,5 @@ +use std::cell::RefCell; +use std::path::{Path, PathBuf}; use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; use crate::system::model::DLASystem; @@ -8,41 +10,61 @@ use crate::system::spawner::UniformSpawner; use crate::system::sticker::{ProbabilisticSticking, SimpleSticking, Sticker}; use crate::system::walker::LocalRandomWalker; -struct LoggerSticker { - inner: SimpleSticking +pub struct LoggerSticker { + inner: ProbabilisticSticking, + pub stick_positions: RefCell>, } -impl> Sticker for LoggerSticker { - fn should_stick(&self, rng: &mut R, space: &S, position: &Grid2D) -> bool { - if self.inner.should_stick(rng, space, position) { - println!("{:?}", position); +impl LoggerSticker { + pub fn new(stick_probability: f32) -> LoggerSticker { + LoggerSticker { + inner: ProbabilisticSticking { stick_probability }, + stick_positions: RefCell::new(Vec::new()), } - - false } } -struct ReadOnlyVectorStorage { +impl> Sticker for &LoggerSticker { + fn should_stick(&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, } +impl ReadOnlyVectorStorage { + pub fn new(path: &Path, grid_size: u32) -> ReadOnlyVectorStorage { + let mut inner = VectorStorage::new(grid_size, 2); + let positions: Vec = csv::Reader::from_path(path) + .expect("Failed to read initial data") + .deserialize::() + .map(|row| row.expect("Failed to read row")) + .collect(); + + for pos in positions { + inner.deposit(&pos); + } + + ReadOnlyVectorStorage { inner } + } +} + impl Storage for ReadOnlyVectorStorage { fn is_occupied(&self, position: &Grid2D) -> bool { self.inner.is_occupied(position) } 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 { - DLASystem::new( - SmallRng::seed_from_u64(seed), - VectorStorage::new(1600, 3), - LocalRandomWalker, - UniformSpawner, - ProbabilisticSticking { stick_probability }, - max_particles, - ) -}