use super::mass::MassDistribution;
use super::WeightedProbabilityDistribution;
use crate::constant::{AMU, BOLTZCONST, EXP};
use rand;
use rand::distributions::Distribution;
use rand::distributions::WeightedIndex;
use rand::Rng;
use std::marker::PhantomData;
use specs::{Component, Entities, Entity, HashMapStorage, Join, ReadStorage, System, WriteStorage};
fn create_v_distribution(
temperature: f64,
mass: f64,
power: f64,
) -> WeightedProbabilityDistribution {
let max_velocity = 7.0 * (2.0 * BOLTZCONST * temperature / mass).powf(0.5);
let mut velocities = Vec::<f64>::new();
let mut weights = Vec::<f64>::new();
let n = 2000;
for i in 0..n {
let v = (i as f64 + 0.5) / (n as f64 + 1.0) * max_velocity;
let weight = probability_v(temperature, mass, v, power);
velocities.push(v);
weights.push(weight);
}
WeightedProbabilityDistribution::new(velocities, weights)
}
pub fn probability_v(temperature: f64, mass: f64, v: f64, power: f64) -> f64 {
let norm_v = v / (2.0 * BOLTZCONST * temperature / mass).powf(0.5); 2.0 * norm_v.powf(power) * EXP.powf(-norm_v.powf(2.0))
}
pub struct Species {
mass: f64,
v_distribution: WeightedProbabilityDistribution,
}
impl Species {
fn create(mass: f64, temperature: f64, power: f64) -> Self {
Species {
mass,
v_distribution: create_v_distribution(temperature, mass * AMU, power),
}
}
}
pub struct PrecalculatedSpeciesInformation {
species: Vec<Species>,
distribution: WeightedIndex<f64>,
}
impl PrecalculatedSpeciesInformation {
pub fn generate_random_mass_v<R: Rng + ?Sized>(&self, rng: &mut R) -> (f64, f64) {
let i = self.distribution.sample(rng);
let species = &self.species[i];
(species.mass, species.v_distribution.sample(rng))
}
fn create(temperature: f64, mass_distribution: &MassDistribution, power: f64) -> Self {
let mut species = Vec::<Species>::new();
let mut ratios = Vec::<f64>::new();
for mr in &mass_distribution.distribution {
ratios.push(mr.ratio);
species.push(Species::create(mr.mass, temperature, power));
}
PrecalculatedSpeciesInformation {
species,
distribution: WeightedIndex::new(&ratios).unwrap(),
}
}
}
impl Component for PrecalculatedSpeciesInformation {
type Storage = HashMapStorage<Self>;
}
pub trait MaxwellBoltzmannSource {
fn get_temperature(&self) -> f64;
fn get_v_dist_power(&self) -> f64;
}
#[derive(Default)]
pub struct PrecalculateForSpeciesSystem<T: MaxwellBoltzmannSource> {
pub marker: PhantomData<T>,
}
impl<'a, T> System<'a> for PrecalculateForSpeciesSystem<T>
where
T: MaxwellBoltzmannSource + Component,
{
type SystemData = (
Entities<'a>,
ReadStorage<'a, T>,
WriteStorage<'a, MassDistribution>,
WriteStorage<'a, PrecalculatedSpeciesInformation>,
);
fn run(&mut self, (entities, sources, mut mass_distributions, mut precalcs): Self::SystemData) {
let mut precalculated_data = Vec::<(Entity, PrecalculatedSpeciesInformation)>::new();
for (entity, source, mass_dist, _) in
(&entities, &sources, &mass_distributions, !&precalcs).join()
{
let precalculated = PrecalculatedSpeciesInformation::create(
source.get_temperature(),
mass_dist,
source.get_v_dist_power(),
);
precalculated_data.push((entity, precalculated));
println!("Precalculated velocity and mass distributions for an oven.");
}
for (entity, precalculated) in precalculated_data {
mass_distributions.remove(entity);
precalcs
.insert(entity, precalculated)
.expect("Could not add precalculated data to oven.");
}
}
}