atomecs/atom_sources/
gaussian.rs1use std::marker::PhantomData;
4
5use super::{WeightedProbabilityDistribution, species::AtomCreator};
6use crate::atom::*;
7use crate::atom_sources::emit::AtomNumberToEmit;
8use crate::constant::EXP;
9use crate::initiate::*;
10use nalgebra::Vector3;
11
12use rand;
13use rand::distributions::Distribution;
14use rand::Rng;
15
16use specs::{
17 Component, Entities, Entity, HashMapStorage, Join, LazyUpdate, Read, ReadStorage, System,
18 WriteStorage,
19};
20
21pub struct GaussianVelocityDistributionSourceDefinition<T> where T : AtomCreator {
22 pub mean: Vector3<f64>,
23 pub std: Vector3<f64>,
24 phantom: PhantomData<T>
25}
26impl<T> Component for GaussianVelocityDistributionSourceDefinition<T> where T : AtomCreator + 'static {
27 type Storage = HashMapStorage<Self>;
28}
29
30pub struct GaussianVelocityDistributionSource<T> where T : AtomCreator {
31 vx_distribution: WeightedProbabilityDistribution,
32 vy_distribution: WeightedProbabilityDistribution,
33 vz_distribution: WeightedProbabilityDistribution,
34 phantom: PhantomData<T>
35}
36impl<T> Component for GaussianVelocityDistributionSource<T> where T : AtomCreator + 'static {
37 type Storage = HashMapStorage<Self>;
38}
39impl<T> GaussianVelocityDistributionSource<T> where T : AtomCreator {
40 fn get_random_velocity<R: Rng + ?Sized>(&self, rng: &mut R) -> Vector3<f64> {
41 Vector3::new(
42 self.vx_distribution.sample(rng),
43 self.vy_distribution.sample(rng),
44 self.vz_distribution.sample(rng),
45 )
46 }
47}
48
49pub fn create_gaussian_velocity_distribution(
58 mean: f64,
59 std: f64,
60) -> WeightedProbabilityDistribution {
61 let mut velocities = Vec::<f64>::new();
63 let mut weights = Vec::<f64>::new();
64
65 let n = 1000;
67 for i in -n..n {
68 let v = (i as f64) / (n as f64) * 5.0 * std;
69 let weight = EXP.powf(-(v / std).powf(2.0) / 2.0);
70 velocities.push(v + mean);
71 weights.push(weight);
72 }
73
74 WeightedProbabilityDistribution::new(velocities, weights)
75}
76
77#[derive(Default)]
81pub struct PrecalculateForGaussianSourceSystem<T>(PhantomData<T>);
82impl<'a, T> System<'a> for PrecalculateForGaussianSourceSystem<T> where T : AtomCreator + 'static {
83 type SystemData = (
84 Entities<'a>,
85 ReadStorage<'a, GaussianVelocityDistributionSourceDefinition<T>>,
86 WriteStorage<'a, GaussianVelocityDistributionSource<T>>,
87 );
88
89 fn run(&mut self, (entities, definitions, mut calculated): Self::SystemData) {
90 let mut precalculated_data = Vec::<(Entity, GaussianVelocityDistributionSource<T>)>::new();
91 for (entity, definition, _) in (&entities, &definitions, !&calculated).join() {
92 let source = GaussianVelocityDistributionSource {
93 vx_distribution: create_gaussian_velocity_distribution(
94 definition.mean[0],
95 definition.std[0],
96 ),
97 vy_distribution: create_gaussian_velocity_distribution(
98 definition.mean[1],
99 definition.std[1],
100 ),
101 vz_distribution: create_gaussian_velocity_distribution(
102 definition.mean[2],
103 definition.std[2],
104 ),
105 phantom: PhantomData
106 };
107 precalculated_data.push((entity, source));
108 println!("Precalculated velocity and mass distributions for a gaussian source.");
109 }
110
111 for (entity, precalculated) in precalculated_data {
112 calculated
113 .insert(entity, precalculated)
114 .expect("Could not add precalculated gaussian source.");
115 }
116 }
117}
118
119#[derive(Default)]
120pub struct GaussianCreateAtomsSystem<T>(PhantomData<T>);
121impl<'a, T> System<'a> for GaussianCreateAtomsSystem<T> where T : AtomCreator + 'static {
122 type SystemData = (
123 Entities<'a>,
124 ReadStorage<'a, GaussianVelocityDistributionSource<T>>,
125 ReadStorage<'a, AtomNumberToEmit>,
126 ReadStorage<'a, Position>,
127 ReadStorage<'a, Mass>,
128 Read<'a, LazyUpdate>,
129 );
130
131 fn run(
132 &mut self,
133 (entities, sources, numbers_to_emits, positions, masses, updater): Self::SystemData,
134 ) {
135 let mut rng = rand::thread_rng();
136 for (source, number_to_emit, source_position, mass) in (
137 &sources,
138 &numbers_to_emits,
139 &positions,
140 &masses,
141 )
142 .join()
143 {
144 for _i in 0..number_to_emit.number {
145 let new_atom = entities.create();
146 let new_vel = source.get_random_velocity(&mut rng);
147 updater.insert(
148 new_atom,
149 Velocity {
150 vel: new_vel,
151 },
152 );
153 updater.insert(new_atom, source_position.clone());
154 updater.insert(new_atom, Force::new());
155 updater.insert(new_atom, mass.clone());
156 updater.insert(new_atom, Atom);
157 updater.insert(new_atom, InitialVelocity { vel: new_vel });
158 updater.insert(new_atom, NewlyCreated);
159 T::mutate(&updater, new_atom);
160 }
161 }
162 }
163}