atomecs/atom_sources/
mass.rs1use crate::atom::Mass;
4use rand;
5use rand::Rng;
6extern crate specs;
7
8use serde::{Deserialize, Serialize};
9use specs::{Component, HashMapStorage};
10
11#[derive(Deserialize, Serialize, Clone)]
13pub struct MassRatio {
14 pub mass: f64,
16 pub ratio: f64,
18}
19
20#[derive(Deserialize, Serialize, Clone)]
24pub struct MassDistribution {
25 pub distribution: Vec<MassRatio>,
26 pub normalised: bool,
27}
28impl Component for MassDistribution {
29 type Storage = HashMapStorage<Self>;
30}
31impl MassDistribution {
32 pub fn new(distribution: Vec<MassRatio>) -> Self {
36 let mut mass_dist = MassDistribution {
37 distribution,
38 normalised: false,
39 };
40 mass_dist.normalise();
41 mass_dist
42 }
43
44 pub fn normalise(&mut self) {
46 let mut total = 0.;
47 for mr in self.distribution.iter() {
48 total += mr.ratio;
49 }
50
51 for mut mr in &mut self.distribution {
52 mr.ratio /= total;
53 }
54 self.normalised = true
55 }
56
57 pub fn draw_random_mass(&self) -> Mass {
59 assert!(self.normalised);
60 let mut level = 0.;
61 let mut rng = rand::thread_rng();
62 let luck = rng.gen_range(0.0..1.0);
63 let mut finalmass = 0.;
64 for masspercent in self.distribution.iter() {
65 level += masspercent.ratio;
66 if level > luck {
67 return Mass {
68 value: masspercent.mass,
69 };
70 }
71 finalmass = masspercent.mass;
72 }
73 Mass { value: finalmass }
74 }
75}
76
77pub mod tests {
78 #[allow(unused_imports)]
79 use super::*;
80 #[allow(unused_imports)]
81 use assert_approx_eq::assert_approx_eq;
82
83 #[test]
84 fn test_mass_distribution_normalised() {
85 let mass_distribution = MassDistribution::new(vec![
86 MassRatio {
87 mass: 1.0,
88 ratio: 10.0,
89 },
90 MassRatio {
91 mass: 2.0,
92 ratio: 1.0,
93 },
94 ]);
95
96 let mut total_ratio = 0.0;
97 for mr in &mass_distribution.distribution {
98 total_ratio += mr.ratio;
99 }
100
101 assert_approx_eq!(total_ratio, 1., 0.0001);
102 }
103}