conspire/physics/molecular/single_chain/ideal/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    math::Scalar,
6    physics::molecular::single_chain::{
7        Ensemble, Isometric, Isotensional, Legendre, SingleChain, SingleChainError, Thermodynamics,
8    },
9};
10use std::f64::consts::PI;
11
12/// The ideal chain model.
13#[derive(Clone, Debug)]
14pub struct IdealChain {
15    /// The link length $`\ell_b`$.
16    pub link_length: Scalar,
17    /// The number of links $`N_b`$.
18    pub number_of_links: u8,
19    /// The thermodynamic ensemble.
20    pub ensemble: Ensemble,
21}
22
23impl SingleChain for IdealChain {
24    fn link_length(&self) -> Scalar {
25        self.link_length
26    }
27    fn number_of_links(&self) -> u8 {
28        self.number_of_links
29    }
30}
31
32impl Thermodynamics for IdealChain {
33    fn ensemble(&self) -> Ensemble {
34        self.ensemble
35    }
36}
37
38impl Isometric for IdealChain {
39    /// ```math
40    /// \beta\psi(\gamma) = \frac{3}{2}\,N_b\gamma^2
41    /// ```
42    fn nondimensional_helmholtz_free_energy(
43        &self,
44        nondimensional_extension: Scalar,
45    ) -> Result<Scalar, SingleChainError> {
46        Ok(1.5 * self.number_of_links() as Scalar * nondimensional_extension.powi(2))
47    }
48    /// ```math
49    /// \eta(\gamma) = 3\gamma
50    /// ```
51    fn nondimensional_force(
52        &self,
53        nondimensional_extension: Scalar,
54    ) -> Result<Scalar, SingleChainError> {
55        Ok(3.0 * nondimensional_extension)
56    }
57    /// ```math
58    /// \kappa(\gamma) = 3
59    /// ```
60    fn nondimensional_stiffness(
61        &self,
62        _nondimensional_extension: Scalar,
63    ) -> Result<Scalar, SingleChainError> {
64        Ok(3.0)
65    }
66    /// ```math
67    /// \mathcal{P}(\gamma) = \left(\frac{3}{2\pi N_b}\right)^{3/2}\exp\left(-\frac{3}{2}\,N_b\gamma^2\right)
68    /// ```
69    fn nondimensional_spherical_distribution(
70        &self,
71        nondimensional_extension: Scalar,
72    ) -> Result<Scalar, SingleChainError> {
73        let number_of_links = self.number_of_links() as Scalar;
74        Ok((1.5 / PI / number_of_links).powf(1.5)
75            * (-1.5 * number_of_links * nondimensional_extension.powi(2)).exp())
76    }
77}
78
79impl Isotensional for IdealChain {
80    /// ```math
81    /// \beta\varphi(\eta) = \frac{1}{6}\,N_b\eta^2
82    /// ```
83    fn nondimensional_gibbs_free_energy(
84        &self,
85        nondimensional_force: Scalar,
86    ) -> Result<Scalar, SingleChainError> {
87        Ok(self.number_of_links() as Scalar / -6.0 * nondimensional_force.powi(2))
88    }
89    /// ```math
90    /// \gamma(\eta) = \frac{\eta}{3}
91    /// ```
92    fn nondimensional_extension(
93        &self,
94        nondimensional_force: Scalar,
95    ) -> Result<Scalar, SingleChainError> {
96        Ok(nondimensional_force / 3.0)
97    }
98    /// ```math
99    /// \zeta(\eta) = \frac{1}{3}
100    /// ```
101    fn nondimensional_compliance(
102        &self,
103        _nondimensional_force: Scalar,
104    ) -> Result<Scalar, SingleChainError> {
105        Ok(1.0 / 3.0)
106    }
107}
108
109impl Legendre for IdealChain {
110    /// ```math
111    /// \eta(\gamma) = 3\gamma
112    /// ```
113    fn nondimensional_force(
114        &self,
115        nondimensional_extension: Scalar,
116    ) -> Result<Scalar, SingleChainError> {
117        Isometric::nondimensional_force(self, nondimensional_extension)
118    }
119    /// ```math
120    /// \gamma(\eta) = \frac{\eta}{3}
121    /// ```
122    fn nondimensional_extension(
123        &self,
124        nondimensional_force: Scalar,
125    ) -> Result<Scalar, SingleChainError> {
126        Isotensional::nondimensional_extension(self, nondimensional_force)
127    }
128    /// ```math
129    /// \mathcal{P}(\gamma) = \left(\frac{3}{2\pi N_b}\right)^{3/2}\exp\left(-\frac{3}{2}\,N_b\gamma^2\right)
130    /// ```
131    fn nondimensional_spherical_distribution(
132        &self,
133        nondimensional_extension: Scalar,
134    ) -> Result<Scalar, SingleChainError> {
135        Isometric::nondimensional_spherical_distribution(self, nondimensional_extension)
136    }
137}