polysim_core/properties/
ensemble.rs1use std::fmt;
2
3use crate::polymer::PolymerEnsemble;
4
5#[derive(Debug, Clone)]
7pub struct EnsembleStats {
8 pub num_chains: usize,
9 pub mn: f64,
10 pub mw: f64,
11 pub pdi: f64,
12 pub mn_min: f64,
13 pub mn_max: f64,
14 pub mn_median: f64,
15 pub mn_std_dev: f64,
16}
17
18impl EnsembleStats {
19 pub fn from_ensemble(ensemble: &PolymerEnsemble) -> Self {
21 let mut masses: Vec<f64> = ensemble.chains().iter().map(|c| c.mn).collect();
22 masses.sort_by(|a, b| a.partial_cmp(b).unwrap());
23
24 let n = masses.len();
25 let mn = ensemble.mn();
26 let mw = ensemble.mw();
27
28 let mn_median = if n % 2 == 1 {
29 masses[n / 2]
30 } else {
31 (masses[n / 2 - 1] + masses[n / 2]) / 2.0
32 };
33
34 let variance = masses.iter().map(|m| (m - mn).powi(2)).sum::<f64>() / n as f64;
35 let mn_std_dev = variance.sqrt();
36
37 Self {
38 num_chains: n,
39 mn,
40 mw,
41 pdi: ensemble.pdi(),
42 mn_min: masses[0],
43 mn_max: masses[n - 1],
44 mn_median,
45 mn_std_dev,
46 }
47 }
48}
49
50impl fmt::Display for EnsembleStats {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 writeln!(f, "Ensemble Statistics")?;
53 writeln!(f, " Chains: {}", self.num_chains)?;
54 writeln!(f, " Mn: {:.1} g/mol", self.mn)?;
55 writeln!(f, " Mw: {:.1} g/mol", self.mw)?;
56 writeln!(f, " PDI: {:.3}", self.pdi)?;
57 writeln!(f, " Median: {:.1} g/mol", self.mn_median)?;
58 writeln!(f, " Std dev: {:.1} g/mol", self.mn_std_dev)?;
59 write!(
60 f,
61 " Mn range: {:.1} - {:.1} g/mol",
62 self.mn_min, self.mn_max
63 )
64 }
65}