Skip to main content

polysim_core/distribution/
schulz_zimm.rs

1use rand::RngCore;
2use rand_distr::{Distribution, Gamma};
3
4use super::ChainLengthDistribution;
5
6/// Schulz-Zimm (gamma) chain length distribution.
7///
8/// Generalization of the Flory distribution with shape parameter k:
9///   k = 1/(PDI − 1),  θ = Xn/k
10///
11/// Covers a wide range of dispersities:
12/// - k → ∞ : monodisperse (PDI → 1.0)
13/// - k = 1 : Flory distribution (PDI = 2.0)
14/// - k < 1 : broader than Flory (PDI > 2.0)
15pub struct SchulzZimm;
16
17impl ChainLengthDistribution for SchulzZimm {
18    fn sample(
19        &self,
20        mn: f64,
21        pdi: f64,
22        m0: f64,
23        num_chains: usize,
24        rng: &mut dyn RngCore,
25    ) -> Vec<usize> {
26        let xn = (mn / m0).max(1.0);
27        let pdi_clamped = pdi.max(1.0 + 1e-9);
28        let k = (1.0 / (pdi_clamped - 1.0)).min(1e6);
29        let theta = xn / k;
30
31        let gamma = Gamma::new(k, theta).expect("valid gamma parameters");
32        (0..num_chains)
33            .map(|_| {
34                let x: f64 = gamma.sample(rng);
35                (x.round() as usize).max(1)
36            })
37            .collect()
38    }
39
40    fn name(&self) -> &'static str {
41        "schulz_zimm"
42    }
43}