This commit is contained in:
Simon Gardling 2021-03-31 10:24:56 -04:00
parent bec6340607
commit 32bfd1b27e
9 changed files with 66 additions and 54 deletions

View File

@ -1,4 +1,3 @@
unstable_features = true unstable_features = true
imports_granularity = "Crate" imports_granularity = "Crate"
wrap_comments = true wrap_comments = false
comment_width = 100

View File

@ -10,7 +10,7 @@ impl Clone for Blur {
fn clone(&self) -> Blur { fn clone(&self) -> Blur {
return Blur { return Blur {
row_buffer: self.row_buffer.clone(), row_buffer: self.row_buffer.clone(),
} };
} }
} }

View File

@ -25,7 +25,7 @@ impl Clone for PopulationConfig {
rotation_angle: self.rotation_angle, rotation_angle: self.rotation_angle,
decay_factor: self.decay_factor, decay_factor: self.decay_factor,
deposition_amount: self.deposition_amount, deposition_amount: self.deposition_amount,
} };
} }
} }
@ -93,13 +93,13 @@ pub struct Grid {
impl Clone for Grid { impl Clone for Grid {
fn clone(&self) -> Grid { fn clone(&self) -> Grid {
return Grid { return Grid {
config: self.config.clone(), config: self.config.clone(),
width: self.width.clone(), width: self.width.clone(),
height: self.height.clone(), height: self.height.clone(),
data: self.data.clone(), data: self.data.clone(),
buf: self.buf.clone(), buf: self.buf.clone(),
blur: self.blur.clone(), blur: self.blur.clone(),
} };
} }
} }

View File

@ -1,8 +1,4 @@
use crate::{ use crate::{grid::Grid, palette::Palette};
grid::{Grid},
palette::{Palette},
};
// Class for storing data that will be used to create images // Class for storing data that will be used to create images
pub struct ImgData { pub struct ImgData {
@ -17,16 +13,16 @@ impl Clone for ImgData {
grids: self.grids.clone(), grids: self.grids.clone(),
palette: self.palette.clone(), palette: self.palette.clone(),
iteration: self.iteration.clone(), iteration: self.iteration.clone(),
} };
} }
} }
impl ImgData { impl ImgData {
pub fn new(in_grids: Vec<Grid>, in_palette: Palette, in_iteration: i32) -> Self { pub fn new(in_grids: Vec<Grid>, in_palette: Palette, in_iteration: i32) -> Self {
ImgData { ImgData {
grids: in_grids, grids: in_grids,
palette: in_palette, palette: in_palette,
iteration: in_iteration, iteration: in_iteration,
} }
} }
} }

View File

@ -1,7 +1,7 @@
mod blur; mod blur;
mod grid; mod grid;
mod imgdata; // for storing image data
mod math;
pub mod model; pub mod model;
mod palette; mod palette;
mod util; mod util; // for math things
mod imgdata; // for storing image data
mod math; // for math things

View File

@ -17,18 +17,16 @@ fn main() {
// `n_populations` is the # of types of agents // `n_populations` is the # of types of agents
let n_populations = 1; let n_populations = 1;
// let n_populations = 1 + rng.gen_range(1..4); // make # of populations between 2 and 5 // let n_populations = 1 + rng.gen_range(1..4); // make # of populations between 2 and 5
let mut model = model::Model::new(width, height, n_particles, n_populations, diffusivity); // Create the model let mut model = model::Model::new(width, height, n_particles, n_populations, diffusivity); // Create the model
model.print_configurations(); // Print config for model model.print_configurations(); // Print config for model
model.run(n_iterations); // Actually run the model model.run(n_iterations); // Actually run the model
// export saved image data // export saved image data
println!("Rendering all saved image data...."); println!("Rendering all saved image data....");
model.render_all_imgdata(); model.render_all_imgdata();
model.flush_image_data(); model.flush_image_data();
println!("Done!"); println!("Done!");
} }

View File

@ -36,4 +36,4 @@ pub fn cos(mut x: f32) -> f32 {
#[inline(always)] #[inline(always)]
pub fn sin(x: f32) -> f32 { pub fn sin(x: f32) -> f32 {
return cos(x - std::f32::consts::FRAC_PI_2); return cos(x - std::f32::consts::FRAC_PI_2);
} }

View File

@ -1,19 +1,16 @@
use crate::{ use crate::{
grid::{combine, Grid, PopulationConfig}, grid::{combine, Grid, PopulationConfig},
palette::{random_palette, Palette},
imgdata::ImgData, imgdata::ImgData,
palette::{random_palette, Palette},
util::wrap, util::wrap,
}; };
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
use itertools::multizip;
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
use rand_distr::{Distribution, Normal}; use rand_distr::{Distribution, Normal};
use rayon::prelude::*; use rayon::{iter::ParallelIterator, prelude::*};
use itertools::multizip; use std::{f32::consts::TAU, path::Path, time::Instant};
use std::f32::consts::TAU;
use std::time::{Instant};
use rayon::iter::ParallelIterator;
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
use std::path::Path;
// A single Physarum agent. The x and y positions are continuous, hence we use floating point numbers instead of integers. // A single Physarum agent. The x and y positions are continuous, hence we use floating point numbers instead of integers.
#[derive(Debug)] #[derive(Debug)]
@ -39,7 +36,7 @@ impl Agent {
} }
#[inline] #[inline]
pub fn tick(&mut self, grid: &Grid) { pub fn tick(&mut self, grid: &Grid) {
let (width, height) = (grid.width, grid.height); let (width, height) = (grid.width, grid.height);
let PopulationConfig { let PopulationConfig {
sensor_distance, sensor_distance,
@ -51,7 +48,7 @@ impl Agent {
let xc = self.x + fastapprox::faster::cos(self.angle) * sensor_distance; let xc = self.x + fastapprox::faster::cos(self.angle) * sensor_distance;
let yc = self.y + fastapprox::faster::sin(self.angle) * sensor_distance; let yc = self.y + fastapprox::faster::sin(self.angle) * sensor_distance;
let agent_add_sens = self.angle + sensor_angle; let agent_add_sens = self.angle + sensor_angle;
let agent_sub_sens = self.angle - sensor_angle; let agent_sub_sens = self.angle - sensor_angle;
@ -68,7 +65,7 @@ impl Agent {
// Rotate and move logic // Rotate and move logic
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut direction: f32 = 0.0; let mut direction: f32 = 0.0;
if (center > left) && (center > right) { if (center > left) && (center > right) {
direction = 0.0; direction = 0.0;
} else if (center < left) && (center < right) { } else if (center < left) && (center < right) {
@ -82,8 +79,14 @@ impl Agent {
let delta_angle = rotation_angle * direction; let delta_angle = rotation_angle * direction;
self.angle = wrap(self.angle + delta_angle, TAU); self.angle = wrap(self.angle + delta_angle, TAU);
self.x = wrap(self.x + step_distance * fastapprox::faster::cos(self.angle), width as f32); self.x = wrap(
self.y = wrap(self.y + step_distance * fastapprox::faster::sin(self.angle), height as f32); self.x + step_distance * fastapprox::faster::cos(self.angle),
width as f32,
);
self.y = wrap(
self.y + step_distance * fastapprox::faster::sin(self.angle),
height as f32,
);
} }
} }
@ -95,17 +98,20 @@ impl Clone for Agent {
angle: self.angle, angle: self.angle,
population_id: self.population_id, population_id: self.population_id,
i: self.i, i: self.i,
} };
} }
} }
impl PartialEq for Agent { impl PartialEq for Agent {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
return self.x == other.x && self.y == other.y && self.angle == other.angle && self.population_id == other.population_id && self.i == other.i; return self.x == other.x
&& self.y == other.y
&& self.angle == other.angle
&& self.population_id == other.population_id
&& self.i == other.i;
} }
} }
// Top-level simulation class. // Top-level simulation class.
pub struct Model { pub struct Model {
// Physarum agents. // Physarum agents.
@ -188,7 +194,6 @@ impl Model {
} }
} }
// Simulates `steps` # of steps // Simulates `steps` # of steps
#[inline] #[inline]
pub fn run(&mut self, steps: usize) { pub fn run(&mut self, steps: usize) {
@ -206,7 +211,9 @@ impl Model {
let mut time_per_agent_list: Vec<f64> = Vec::new(); let mut time_per_agent_list: Vec<f64> = Vec::new();
let mut time_per_step_list: Vec<f64> = Vec::new(); let mut time_per_step_list: Vec<f64> = Vec::new();
for i in 0..steps { for i in 0..steps {
if debug {println!("Starting tick for all agents...")}; if debug {
println!("Starting tick for all agents...")
};
// Combine grids // Combine grids
let grids = &mut self.grids; let grids = &mut self.grids;
@ -237,16 +244,26 @@ impl Model {
time_per_agent_list.push(ms_per_agent); time_per_agent_list.push(ms_per_agent);
time_per_step_list.push(agents_tick_elapsed); time_per_step_list.push(agents_tick_elapsed);
if debug {println!("Finished tick for all agents. took {}ms\nTime per agent: {}ms\n", agents_tick_elapsed, ms_per_agent)}; if debug {
println!(
"Finished tick for all agents. took {}ms\nTime per agent: {}ms\n",
agents_tick_elapsed, ms_per_agent
)
};
self.iteration += 1; self.iteration += 1;
pb.set_position(i as u64); pb.set_position(i as u64);
} }
pb.finish(); pb.finish();
let avg_per_step: f64 = time_per_step_list.iter().sum::<f64>() as f64 / time_per_step_list.len() as f64; let avg_per_step: f64 =
let avg_per_agent: f64 = time_per_agent_list.iter().sum::<f64>() as f64 / time_per_agent_list.len() as f64; time_per_step_list.iter().sum::<f64>() as f64 / time_per_step_list.len() as f64;
println!("Average time per step: {}ms\nAverage time per agent: {}ms", avg_per_step, avg_per_agent); let avg_per_agent: f64 =
time_per_agent_list.iter().sum::<f64>() as f64 / time_per_agent_list.len() as f64;
println!(
"Average time per step: {}ms\nAverage time per agent: {}ms",
avg_per_step, avg_per_agent
);
} }
fn save_image_data(&mut self) { fn save_image_data(&mut self) {
@ -260,7 +277,6 @@ impl Model {
return; return;
} }
} }
} }
pub fn flush_image_data(&mut self) { pub fn flush_image_data(&mut self) {
@ -285,7 +301,9 @@ impl Model {
pb.finish(); pb.finish();
*/ */
(&self.img_data_vec).par_iter().progress_with(pb) (&self.img_data_vec)
.par_iter()
.progress_with(pb)
.for_each(|img| { .for_each(|img| {
Self::save_to_image(img.to_owned()); Self::save_to_image(img.to_owned());
}); });
@ -306,7 +324,8 @@ impl Model {
let i = y * width + x; let i = y * width + x;
let (mut r, mut g, mut b) = (0.0_f32, 0.0_f32, 0.0_f32); let (mut r, mut g, mut b) = (0.0_f32, 0.0_f32, 0.0_f32);
for (grid, max_value, color) in for (grid, max_value, color) in
multizip((&imgdata.grids, &max_values, &imgdata.palette.colors)) { multizip((&imgdata.grids, &max_values, &imgdata.palette.colors))
{
let mut t = (grid.data()[i] / max_value).clamp(0.0, 1.0); let mut t = (grid.data()[i] / max_value).clamp(0.0, 1.0);
t = t.powf(1.0 / 2.2); // gamma correction t = t.powf(1.0 / 2.2); // gamma correction
r += color.0[0] as f32 * t; r += color.0[0] as f32 * t;
@ -320,7 +339,7 @@ impl Model {
} }
} }
img.save(format!("./tmp/out_{}.png", imgdata.iteration).as_str())
img.save(format!("./tmp/out_{}.png", imgdata.iteration).as_str()).unwrap(); .unwrap();
} }
} }

View File

@ -1,4 +1,4 @@
#[inline(always)] #[inline(always)]
pub fn wrap(x: f32, max: f32) -> f32 { pub fn wrap(x: f32, max: f32) -> f32 {
return x - max * ((x > max) as i32 as f32 - (x < 0.0_f32) as i32 as f32); return x - max * ((x > max) as i32 as f32 - (x < 0.0_f32) as i32 as f32);
} }