Skip to main content

polysim_core/distribution/
flory.rs

1use rand::{Rng, RngCore};
2
3use super::ChainLengthDistribution;
4
5/// Flory (most probable) chain length distribution.
6///
7/// Characteristic of step-growth (polycondensation) polymers.
8/// The number distribution is geometric: P(n) = (1−p)·p^(n−1),
9/// where p = 1 − 1/Xn is the extent of reaction.
10///
11/// PDI is inherently ≈ 1+p (approaches 2.0 for high conversion);
12/// the `pdi` parameter is ignored.
13pub struct Flory;
14
15impl ChainLengthDistribution for Flory {
16    fn sample(
17        &self,
18        mn: f64,
19        _pdi: f64,
20        m0: f64,
21        num_chains: usize,
22        rng: &mut dyn RngCore,
23    ) -> Vec<usize> {
24        let xn = (mn / m0).max(1.0);
25        let p = 1.0 - 1.0 / xn;
26
27        (0..num_chains)
28            .map(|_| {
29                if p <= 0.0 {
30                    return 1;
31                }
32                // Geometric sampling: n = ceil(ln(U) / ln(p))
33                let u: f64 = rng.random_range(f64::EPSILON..1.0);
34                let n = (u.ln() / p.ln()).ceil() as usize;
35                n.max(1)
36            })
37            .collect()
38    }
39
40    fn name(&self) -> &'static str {
41        "flory"
42    }
43}