From bf1db1858dd7640bedb00983a85a8c20faf79071 Mon Sep 17 00:00:00 2001 From: mrbuche Date: Fri, 14 Apr 2023 18:13:13 -0600 Subject: [PATCH 01/11] separate --- .../asymptotic/alternative/legendre/mod.rs | 171 ++++++ .../asymptotic/alternative/legendre/test.rs | 548 ++++++++++++++++++ .../isometric/asymptotic/alternative/mod.rs | 46 ++ .../isometric/asymptotic/alternative/test.rs | 0 .../isometric/asymptotic/legendre/mod.rs | 171 ++++++ .../isometric/asymptotic/legendre/test.rs | 548 ++++++++++++++++++ .../isometric/asymptotic/mod.rs | 60 ++ .../asymptotic/reduced/legendre/mod.rs | 171 ++++++ .../asymptotic/reduced/legendre/test.rs | 548 ++++++++++++++++++ .../isometric/asymptotic/reduced/mod.rs | 46 ++ .../isometric/asymptotic/reduced/test.rs | 0 .../isometric/asymptotic/test.rs | 0 .../efjc/thermodynamics/isometric/mod.rs | 46 ++ .../efjc/thermodynamics/isometric/test.rs | 0 .../single_chain/efjc/thermodynamics/mod.rs | 9 +- .../single_chain/efjc/thermodynamics/test.rs | 220 +++++++ 16 files changed, 2583 insertions(+), 1 deletion(-) create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/test.rs diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs new file mode 100644 index 00000000..4127180f --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs @@ -0,0 +1,171 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +use std::f64::consts::PI; +use crate::math:: +{ + inverse_langevin, + inverse_newton_raphson +}; +use crate::physics:: +{ + PLANCK_CONSTANT, + BOLTZMANN_CONSTANT, + single_chain::ZERO +}; + +/// The structure of the thermodynamics of the EFJC model thermodynamics in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64 +} + +/// The expected force as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn force(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature/link_length*nondimensional_force(&(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/((*number_of_links as f64)*link_length))) +} + +/// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link, parameterized by the nondimensional link stiffness. +pub fn nondimensional_force(nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + let guess: f64 = if nondimensional_end_to_end_length_per_link < &1.0 + { + inverse_langevin(nondimensional_end_to_end_length_per_link) + } + else + { + nondimensional_link_stiffness*(nondimensional_end_to_end_length_per_link - 1.0) + }; + inverse_newton_raphson(nondimensional_end_to_end_length_per_link, &|nondimensional_force: &f64| 1.0/nondimensional_force.tanh() - 1.0/nondimensional_force + (nondimensional_force + 1.0/nondimensional_force.tanh() - nondimensional_force/nondimensional_force.sinh().powi(2))/nondimensional_link_stiffness, &|nondimensional_force: &f64| 1.0/nondimensional_force.powi(2) - 1.0/nondimensional_force.sinh().powi(2) + (1.0 + 2.0*(nondimensional_force/nondimensional_force.tanh() - 1.0)/nondimensional_force.sinh().powi(2))/nondimensional_link_stiffness, &guess, &1e-2, &100) +} + +/// The Helmholtz free energy as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, hinge mass, and link stiffness. +pub fn helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature*nondimensional_helmholtz_free_energy(number_of_links, link_length, hinge_mass, &(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/(*number_of_links as f64)/link_length), temperature) +} + +/// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, hinge mass, and link stiffness. +pub fn helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature*nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, &(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/(*number_of_links as f64)/link_length), temperature) +} + +/// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn relative_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + helmholtz_free_energy(number_of_links, link_length, &1.0, link_stiffness, end_to_end_length, temperature) - helmholtz_free_energy(number_of_links, link_length, &1.0, link_stiffness, &(ZERO*(*number_of_links as f64)*link_length), temperature) +} + +/// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn relative_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, link_stiffness, end_to_end_length, temperature) - helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, link_stiffness, &(ZERO*(*number_of_links as f64)*link_length), temperature) +} + +/// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature, parameterized by the number of links, link length, hinge mass, and nondimensional link stiffness. +pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 +{ + (*number_of_links as f64)*nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, temperature) +} + +/// The nondimensional Helmholtz free energy per link as a function of the nondimensional end-to-end length per link and temperature, parameterized by the number of links, link length, hinge mass, and nondimensional link stiffness. +pub fn nondimensional_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 +{ + let nondimensional_force = nondimensional_force(nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link); + -(nondimensional_force.sinh()/nondimensional_force).ln() - (0.5*nondimensional_force.powi(2) + nondimensional_force/nondimensional_force.tanh())/(nondimensional_link_stiffness) + nondimensional_force*nondimensional_end_to_end_length_per_link + (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() - (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) +} + +/// The nondimensional relative Helmholtz free energy as a function of the nondimensional end-to-end length per link, parameterized by the number of links and nondimensional link stiffness. +pub fn nondimensional_relative_helmholtz_free_energy(number_of_links: &u8, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + nondimensional_helmholtz_free_energy(number_of_links, &1.0, &1.0, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, &300.0) - nondimensional_helmholtz_free_energy(number_of_links, &1.0, &1.0, nondimensional_link_stiffness, &ZERO, &300.0) +} + +/// The nondimensional relative Helmholtz free energy per link as a function of the nondimensional end-to-end length per link, parameterized by the nondimensional link stiffness. +pub fn nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + nondimensional_helmholtz_free_energy_per_link(&8, &1.0, &1.0, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, &300.0) - nondimensional_helmholtz_free_energy_per_link(&8, &1.0, &1.0, nondimensional_link_stiffness, &ZERO, &300.0) +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness + } + } + /// The expected force as a function of the applied end-to-end length and temperature. + pub fn force(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + force(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_force(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_force(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } + /// The Helmholtz free energy as a function of the applied end-to-end length and temperature. + pub fn helmholtz_free_energy(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, end_to_end_length, temperature) + } + /// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + pub fn helmholtz_free_energy_per_link(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, end_to_end_length, temperature) + } + /// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature. + pub fn relative_helmholtz_free_energy(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + relative_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + pub fn relative_helmholtz_free_energy_per_link(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + relative_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_helmholtz_free_energy(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link, temperature) + } + /// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_helmholtz_free_energy_per_link(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link, temperature) + } + /// The nondimensional relative Helmholtz free energy as a function of the applied nondimensional end-to-end length per link. + pub fn nondimensional_relative_helmholtz_free_energy(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_relative_helmholtz_free_energy(&self.number_of_links, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } + /// The nondimensional relative Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link. + pub fn nondimensional_relative_helmholtz_free_energy_per_link(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_relative_helmholtz_free_energy_per_link(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.rs new file mode 100644 index 00000000..94555024 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.rs @@ -0,0 +1,548 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} +mod nondimensional +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force = model.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let force = model.force(&end_to_end_length, &temperature); + let residual_abs = &force/BOLTZMANN_CONSTANT/temperature*link_length - &nondimensional_force; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy/BOLTZMANN_CONSTANT/temperature - &nondimensional_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link/BOLTZMANN_CONSTANT/temperature - &nondimensional_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy/BOLTZMANN_CONSTANT/temperature - &nondimensional_relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_per_link/BOLTZMANN_CONSTANT/temperature - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod per_link +{ + use super::*; + use rand::Rng; + #[test] + fn helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy/(number_of_links as f64) - &helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy/(number_of_links as f64) - &relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy/(number_of_links as f64) - &nondimensional_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy/(number_of_links as f64) - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod relative +{ + use super::*; + use rand::Rng; + #[test] + fn helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let helmholtz_free_energy_0 = model.helmholtz_free_energy(&(ZERO*(number_of_links as f64)*link_length), &temperature); + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy - &helmholtz_free_energy_0 - &relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&helmholtz_free_energy_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy_per_link() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let helmholtz_free_energy_per_link_0 = model.helmholtz_free_energy_per_link(&(ZERO*(number_of_links as f64)*link_length), &temperature); + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link - &helmholtz_free_energy_per_link_0 - &relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_0 = model.nondimensional_helmholtz_free_energy(&ZERO, &temperature); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy - &nondimensional_helmholtz_free_energy_0 - &nondimensional_relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_per_link_0 = model.nondimensional_helmholtz_free_energy_per_link(&ZERO, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_per_link - &nondimensional_helmholtz_free_energy_per_link_0 - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod zero +{ + use super::*; + use rand::Rng; + use crate::physics::single_chain::ZERO; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force_0 = model.force(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(force_0.abs() <= 3.1*BOLTZMANN_CONSTANT*temperature/link_length*ZERO); + } + } + #[test] + fn nondimensional_force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force_0 = model.nondimensional_force(&ZERO, &temperature); + assert!(nondimensional_force_0.abs() <= 3.1*ZERO); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(relative_helmholtz_free_energy_0.abs() <= ZERO); + } + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let relative_helmholtz_free_energy_per_link_0 = model.relative_helmholtz_free_energy_per_link(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(relative_helmholtz_free_energy_per_link_0.abs() <= ZERO); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_0 = model.nondimensional_relative_helmholtz_free_energy(&ZERO, &temperature); + assert!(nondimensional_relative_helmholtz_free_energy_0.abs() <= ZERO); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_per_link_0 = model.nondimensional_relative_helmholtz_free_energy_per_link(&ZERO, &temperature); + assert!(nondimensional_relative_helmholtz_free_energy_per_link_0.abs() <= ZERO); + } + } +} +mod connection +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + 0.5*parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = model.force(&end_to_end_length, &temperature); + let h = parameters.rel_tol*(number_of_links as f64)*link_length; + let force_from_derivative = (model.relative_helmholtz_free_energy(&(end_to_end_length + 0.5*h), &temperature) - model.relative_helmholtz_free_energy(&(end_to_end_length - 0.5*h), &temperature))/h; + let residual_abs = &force - &force_from_derivative; + let residual_rel = &residual_abs/&force; + assert!(residual_rel.abs() <= h); + } + } + #[test] + fn nondimensional_force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + 0.5*parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force = model.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let h = parameters.rel_tol; + let nondimensional_force_from_derivative = (model.nondimensional_relative_helmholtz_free_energy_per_link(&(nondimensional_end_to_end_length_per_link + 0.5*h), &temperature) - model.nondimensional_relative_helmholtz_free_energy_per_link(&(nondimensional_end_to_end_length_per_link - 0.5*h), &temperature))/h; + let residual_abs = &nondimensional_force - &nondimensional_force_from_derivative; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_rel.abs() <= h); + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs new file mode 100644 index 00000000..1c835718 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs @@ -0,0 +1,46 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an alternative alternative asymptotic approach and a Legendre transformation. +pub mod legendre; + +/// The structure of the thermodynamics of the EFJC model thermodynamics in the isometric ensemble approximated using an alternative asymptotic approach. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. + pub legendre: self::legendre::EFJC +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + legendre: self::legendre::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs new file mode 100644 index 00000000..0a512cc4 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs @@ -0,0 +1,171 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +use std::f64::consts::PI; +use crate::math:: +{ + inverse_langevin, + inverse_newton_raphson +}; +use crate::physics:: +{ + PLANCK_CONSTANT, + BOLTZMANN_CONSTANT, + single_chain::ZERO +}; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64 +} + +/// The expected force as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn force(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature/link_length*nondimensional_force(&(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/((*number_of_links as f64)*link_length))) +} + +/// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link, parameterized by the nondimensional link stiffness. +pub fn nondimensional_force(nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + let guess: f64 = if nondimensional_end_to_end_length_per_link < &1.0 + { + inverse_langevin(nondimensional_end_to_end_length_per_link) + } + else + { + nondimensional_link_stiffness*(nondimensional_end_to_end_length_per_link - 1.0) + }; + inverse_newton_raphson(nondimensional_end_to_end_length_per_link, &|nondimensional_force: &f64| 1.0/nondimensional_force.tanh() - 1.0/nondimensional_force + nondimensional_force/nondimensional_link_stiffness*(1.0 + (nondimensional_force.tanh() - 1.0/nondimensional_force.tanh() + 1.0/nondimensional_force)/(nondimensional_force.tanh() + nondimensional_force/nondimensional_link_stiffness)), &|nondimensional_force: &f64| 1.0/nondimensional_force.powi(2) - 1.0/nondimensional_force.sinh().powi(2) + (nondimensional_link_stiffness*nondimensional_force.powi(2)/nondimensional_force.sinh().powi(4) - (2.0*nondimensional_link_stiffness + 1.0)*(nondimensional_link_stiffness - nondimensional_force.powi(2))/nondimensional_force.sinh().powi(2) + 2.0*nondimensional_link_stiffness*nondimensional_force/nondimensional_force.tanh()*(nondimensional_link_stiffness/nondimensional_force.sinh().powi(2) + 1.0) + (nondimensional_link_stiffness - 1.0)*nondimensional_link_stiffness + nondimensional_force.powi(2))/(nondimensional_link_stiffness + nondimensional_force/nondimensional_force.tanh()).powi(2)/nondimensional_link_stiffness, &guess, &1e-2, &100) +} + +/// The Helmholtz free energy as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, hinge mass, and link stiffness. +pub fn helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature*nondimensional_helmholtz_free_energy(number_of_links, link_length, hinge_mass, &(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/(*number_of_links as f64)/link_length), temperature) +} + +/// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, hinge mass, and link stiffness. +pub fn helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature*nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, &(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/(*number_of_links as f64)/link_length), temperature) +} + +/// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn relative_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + helmholtz_free_energy(number_of_links, link_length, &1.0, link_stiffness, end_to_end_length, temperature) - helmholtz_free_energy(number_of_links, link_length, &1.0, link_stiffness, &(ZERO*(*number_of_links as f64)*link_length), temperature) +} + +/// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn relative_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, link_stiffness, end_to_end_length, temperature) - helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, link_stiffness, &(ZERO*(*number_of_links as f64)*link_length), temperature) +} + +/// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature, parameterized by the number of links, link length, hinge mass, and nondimensional link stiffness. +pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 +{ + (*number_of_links as f64)*nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, temperature) +} + +/// The nondimensional Helmholtz free energy per link as a function of the nondimensional end-to-end length per link and temperature, parameterized by the number of links, link length, hinge mass, and nondimensional link stiffness. +pub fn nondimensional_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 +{ + let nondimensional_force = nondimensional_force(nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link); + -(nondimensional_force.sinh()/nondimensional_force).ln() - 0.5*nondimensional_force.powi(2)/nondimensional_link_stiffness - (1.0 + nondimensional_force/nondimensional_force.tanh()/nondimensional_link_stiffness).ln() + nondimensional_force*nondimensional_end_to_end_length_per_link + (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() - (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) +} + +/// The nondimensional relative Helmholtz free energy as a function of the nondimensional end-to-end length per link, parameterized by the number of links and nondimensional link stiffness. +pub fn nondimensional_relative_helmholtz_free_energy(number_of_links: &u8, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + nondimensional_helmholtz_free_energy(number_of_links, &1.0, &1.0, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, &300.0) - nondimensional_helmholtz_free_energy(number_of_links, &1.0, &1.0, nondimensional_link_stiffness, &ZERO, &300.0) +} + +/// The nondimensional relative Helmholtz free energy per link as a function of the nondimensional end-to-end length per link, parameterized by the nondimensional link stiffness. +pub fn nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + nondimensional_helmholtz_free_energy_per_link(&8, &1.0, &1.0, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, &300.0) - nondimensional_helmholtz_free_energy_per_link(&8, &1.0, &1.0, nondimensional_link_stiffness, &ZERO, &300.0) +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness + } + } + /// The expected force as a function of the applied end-to-end length and temperature. + pub fn force(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + force(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_force(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_force(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } + /// The Helmholtz free energy as a function of the applied end-to-end length and temperature. + pub fn helmholtz_free_energy(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, end_to_end_length, temperature) + } + /// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + pub fn helmholtz_free_energy_per_link(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, end_to_end_length, temperature) + } + /// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature. + pub fn relative_helmholtz_free_energy(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + relative_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + pub fn relative_helmholtz_free_energy_per_link(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + relative_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_helmholtz_free_energy(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link, temperature) + } + /// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_helmholtz_free_energy_per_link(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link, temperature) + } + /// The nondimensional relative Helmholtz free energy as a function of the applied nondimensional end-to-end length per link. + pub fn nondimensional_relative_helmholtz_free_energy(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_relative_helmholtz_free_energy(&self.number_of_links, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } + /// The nondimensional relative Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link. + pub fn nondimensional_relative_helmholtz_free_energy_per_link(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_relative_helmholtz_free_energy_per_link(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.rs new file mode 100644 index 00000000..94555024 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.rs @@ -0,0 +1,548 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} +mod nondimensional +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force = model.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let force = model.force(&end_to_end_length, &temperature); + let residual_abs = &force/BOLTZMANN_CONSTANT/temperature*link_length - &nondimensional_force; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy/BOLTZMANN_CONSTANT/temperature - &nondimensional_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link/BOLTZMANN_CONSTANT/temperature - &nondimensional_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy/BOLTZMANN_CONSTANT/temperature - &nondimensional_relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_per_link/BOLTZMANN_CONSTANT/temperature - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod per_link +{ + use super::*; + use rand::Rng; + #[test] + fn helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy/(number_of_links as f64) - &helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy/(number_of_links as f64) - &relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy/(number_of_links as f64) - &nondimensional_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy/(number_of_links as f64) - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod relative +{ + use super::*; + use rand::Rng; + #[test] + fn helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let helmholtz_free_energy_0 = model.helmholtz_free_energy(&(ZERO*(number_of_links as f64)*link_length), &temperature); + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy - &helmholtz_free_energy_0 - &relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&helmholtz_free_energy_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy_per_link() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let helmholtz_free_energy_per_link_0 = model.helmholtz_free_energy_per_link(&(ZERO*(number_of_links as f64)*link_length), &temperature); + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link - &helmholtz_free_energy_per_link_0 - &relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_0 = model.nondimensional_helmholtz_free_energy(&ZERO, &temperature); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy - &nondimensional_helmholtz_free_energy_0 - &nondimensional_relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_per_link_0 = model.nondimensional_helmholtz_free_energy_per_link(&ZERO, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_per_link - &nondimensional_helmholtz_free_energy_per_link_0 - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod zero +{ + use super::*; + use rand::Rng; + use crate::physics::single_chain::ZERO; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force_0 = model.force(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(force_0.abs() <= 3.1*BOLTZMANN_CONSTANT*temperature/link_length*ZERO); + } + } + #[test] + fn nondimensional_force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force_0 = model.nondimensional_force(&ZERO, &temperature); + assert!(nondimensional_force_0.abs() <= 3.1*ZERO); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(relative_helmholtz_free_energy_0.abs() <= ZERO); + } + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let relative_helmholtz_free_energy_per_link_0 = model.relative_helmholtz_free_energy_per_link(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(relative_helmholtz_free_energy_per_link_0.abs() <= ZERO); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_0 = model.nondimensional_relative_helmholtz_free_energy(&ZERO, &temperature); + assert!(nondimensional_relative_helmholtz_free_energy_0.abs() <= ZERO); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_per_link_0 = model.nondimensional_relative_helmholtz_free_energy_per_link(&ZERO, &temperature); + assert!(nondimensional_relative_helmholtz_free_energy_per_link_0.abs() <= ZERO); + } + } +} +mod connection +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + 0.5*parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = model.force(&end_to_end_length, &temperature); + let h = parameters.rel_tol*(number_of_links as f64)*link_length; + let force_from_derivative = (model.relative_helmholtz_free_energy(&(end_to_end_length + 0.5*h), &temperature) - model.relative_helmholtz_free_energy(&(end_to_end_length - 0.5*h), &temperature))/h; + let residual_abs = &force - &force_from_derivative; + let residual_rel = &residual_abs/&force; + assert!(residual_rel.abs() <= h); + } + } + #[test] + fn nondimensional_force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + 0.5*parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force = model.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let h = parameters.rel_tol; + let nondimensional_force_from_derivative = (model.nondimensional_relative_helmholtz_free_energy_per_link(&(nondimensional_end_to_end_length_per_link + 0.5*h), &temperature) - model.nondimensional_relative_helmholtz_free_energy_per_link(&(nondimensional_end_to_end_length_per_link - 0.5*h), &temperature))/h; + let residual_abs = &nondimensional_force - &nondimensional_force_from_derivative; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_rel.abs() <= h); + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs new file mode 100644 index 00000000..9424e56b --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs @@ -0,0 +1,60 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an alternative asymptotic approach. +pub mod alternative; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach. +pub mod reduced; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. +pub mod legendre; + +/// The structure of the thermodynamics of the EFJC model thermodynamics in the isometric ensemble approximated using an asymptotic approach. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an alternative asymptotic approach. + pub alternative: self::alternative::EFJC, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using a reduced asymptotic approach. + pub reduced: self::reduced::EFJC, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. + pub legendre: self::legendre::EFJC +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + alternative: self::alternative::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), + reduced: self::reduced::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), + legendre: self::legendre::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs new file mode 100644 index 00000000..930bf367 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs @@ -0,0 +1,171 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +use std::f64::consts::PI; +use crate::math:: +{ + inverse_langevin, + inverse_newton_raphson +}; +use crate::physics:: +{ + PLANCK_CONSTANT, + BOLTZMANN_CONSTANT, + single_chain::ZERO +}; + +/// The structure of the thermodynamics of the EFJC model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64 +} + +/// The expected force as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn force(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature/link_length*nondimensional_force(&(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/((*number_of_links as f64)*link_length))) +} + +/// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link, parameterized by the nondimensional link stiffness. +pub fn nondimensional_force(nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + let guess: f64 = if nondimensional_end_to_end_length_per_link < &1.0 + { + inverse_langevin(nondimensional_end_to_end_length_per_link) + } + else + { + nondimensional_link_stiffness*(nondimensional_end_to_end_length_per_link - 1.0) + }; + inverse_newton_raphson(nondimensional_end_to_end_length_per_link, &|nondimensional_force: &f64| 1.0/nondimensional_force.tanh() - 1.0/nondimensional_force + nondimensional_force/nondimensional_link_stiffness, &|nondimensional_force: &f64| 1.0/nondimensional_force.powi(2) - 1.0/nondimensional_force.sinh().powi(2) + 1.0/nondimensional_link_stiffness, &guess, &1e-2, &100) +} + +/// The Helmholtz free energy as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, hinge mass, and link stiffness. +pub fn helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature*nondimensional_helmholtz_free_energy(number_of_links, link_length, hinge_mass, &(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/(*number_of_links as f64)/link_length), temperature) +} + +/// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, hinge mass, and link stiffness. +pub fn helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + BOLTZMANN_CONSTANT*temperature*nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, &(link_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &(end_to_end_length/(*number_of_links as f64)/link_length), temperature) +} + +/// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn relative_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + helmholtz_free_energy(number_of_links, link_length, &1.0, link_stiffness, end_to_end_length, temperature) - helmholtz_free_energy(number_of_links, link_length, &1.0, link_stiffness, &(ZERO*(*number_of_links as f64)*link_length), temperature) +} + +/// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature, parameterized by the number of links, link length, and link stiffness. +pub fn relative_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, link_stiffness: &f64, end_to_end_length: &f64, temperature: &f64) -> f64 +{ + helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, link_stiffness, end_to_end_length, temperature) - helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, link_stiffness, &(ZERO*(*number_of_links as f64)*link_length), temperature) +} + +/// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature, parameterized by the number of links, link length, hinge mass, and nondimensional link stiffness. +pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 +{ + (*number_of_links as f64)*nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, temperature) +} + +/// The nondimensional Helmholtz free energy per link as a function of the nondimensional end-to-end length per link and temperature, parameterized by the number of links, link length, hinge mass, and nondimensional link stiffness. +pub fn nondimensional_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 +{ + let nondimensional_force = nondimensional_force(nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link); + -(nondimensional_force.sinh()/nondimensional_force).ln() - 0.5*nondimensional_force.powi(2)/nondimensional_link_stiffness + nondimensional_force*nondimensional_end_to_end_length_per_link + (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() - (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) +} + +/// The nondimensional relative Helmholtz free energy as a function of the nondimensional end-to-end length per link, parameterized by the number of links and nondimensional link stiffness. +pub fn nondimensional_relative_helmholtz_free_energy(number_of_links: &u8, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + nondimensional_helmholtz_free_energy(number_of_links, &1.0, &1.0, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, &300.0) - nondimensional_helmholtz_free_energy(number_of_links, &1.0, &1.0, nondimensional_link_stiffness, &ZERO, &300.0) +} + +/// The nondimensional relative Helmholtz free energy per link as a function of the nondimensional end-to-end length per link, parameterized by the nondimensional link stiffness. +pub fn nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64) -> f64 +{ + nondimensional_helmholtz_free_energy_per_link(&8, &1.0, &1.0, nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link, &300.0) - nondimensional_helmholtz_free_energy_per_link(&8, &1.0, &1.0, nondimensional_link_stiffness, &ZERO, &300.0) +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness + } + } + /// The expected force as a function of the applied end-to-end length and temperature. + pub fn force(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + force(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_force(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_force(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } + /// The Helmholtz free energy as a function of the applied end-to-end length and temperature. + pub fn helmholtz_free_energy(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, end_to_end_length, temperature) + } + /// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + pub fn helmholtz_free_energy_per_link(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, end_to_end_length, temperature) + } + /// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature. + pub fn relative_helmholtz_free_energy(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + relative_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + pub fn relative_helmholtz_free_energy_per_link(&self, end_to_end_length: &f64, temperature: &f64) -> f64 + { + relative_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.link_stiffness, end_to_end_length, temperature) + } + /// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_helmholtz_free_energy(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link, temperature) + } + /// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link and temperature. + pub fn nondimensional_helmholtz_free_energy_per_link(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link, temperature) + } + /// The nondimensional relative Helmholtz free energy as a function of the applied nondimensional end-to-end length per link. + pub fn nondimensional_relative_helmholtz_free_energy(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_relative_helmholtz_free_energy(&self.number_of_links, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } + /// The nondimensional relative Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link. + pub fn nondimensional_relative_helmholtz_free_energy_per_link(&self, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 + { + nondimensional_relative_helmholtz_free_energy_per_link(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), nondimensional_end_to_end_length_per_link) + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.rs new file mode 100644 index 00000000..94555024 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.rs @@ -0,0 +1,548 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} +mod nondimensional +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force = model.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let force = model.force(&end_to_end_length, &temperature); + let residual_abs = &force/BOLTZMANN_CONSTANT/temperature*link_length - &nondimensional_force; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy/BOLTZMANN_CONSTANT/temperature - &nondimensional_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link/BOLTZMANN_CONSTANT/temperature - &nondimensional_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy/BOLTZMANN_CONSTANT/temperature - &nondimensional_relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_per_link/BOLTZMANN_CONSTANT/temperature - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod per_link +{ + use super::*; + use rand::Rng; + #[test] + fn helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy/(number_of_links as f64) - &helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy/(number_of_links as f64) - &relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy/(number_of_links as f64) - &nondimensional_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy/(number_of_links as f64) - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod relative +{ + use super::*; + use rand::Rng; + #[test] + fn helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy = model.helmholtz_free_energy(&end_to_end_length, &temperature); + let helmholtz_free_energy_0 = model.helmholtz_free_energy(&(ZERO*(number_of_links as f64)*link_length), &temperature); + let relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy - &helmholtz_free_energy_0 - &relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&helmholtz_free_energy_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn helmholtz_free_energy_per_link() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let helmholtz_free_energy_per_link_0 = model.helmholtz_free_energy_per_link(&(ZERO*(number_of_links as f64)*link_length), &temperature); + let relative_helmholtz_free_energy_per_link = model.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link - &helmholtz_free_energy_per_link_0 - &relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_0 = model.nondimensional_helmholtz_free_energy(&ZERO, &temperature); + let nondimensional_relative_helmholtz_free_energy = model.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy - &nondimensional_helmholtz_free_energy_0 - &nondimensional_relative_helmholtz_free_energy; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + let parameters = Parameters::default(); + let mut rng = rand::thread_rng(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_helmholtz_free_energy_per_link = model.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let nondimensional_helmholtz_free_energy_per_link_0 = model.nondimensional_helmholtz_free_energy_per_link(&ZERO, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link = model.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_per_link - &nondimensional_helmholtz_free_energy_per_link_0 - &nondimensional_relative_helmholtz_free_energy_per_link; + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link_0; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } + } +} +mod zero +{ + use super::*; + use rand::Rng; + use crate::physics::single_chain::ZERO; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force_0 = model.force(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(force_0.abs() <= 3.1*BOLTZMANN_CONSTANT*temperature/link_length*ZERO); + } + } + #[test] + fn nondimensional_force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force_0 = model.nondimensional_force(&ZERO, &temperature); + assert!(nondimensional_force_0.abs() <= 3.1*ZERO); + } + } + #[test] + fn relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(relative_helmholtz_free_energy_0.abs() <= ZERO); + } + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let relative_helmholtz_free_energy_per_link_0 = model.relative_helmholtz_free_energy_per_link(&(ZERO*(number_of_links as f64)*link_length), &temperature); + assert!(relative_helmholtz_free_energy_per_link_0.abs() <= ZERO); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_0 = model.nondimensional_relative_helmholtz_free_energy(&ZERO, &temperature); + assert!(nondimensional_relative_helmholtz_free_energy_0.abs() <= ZERO); + } + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_relative_helmholtz_free_energy_per_link_0 = model.nondimensional_relative_helmholtz_free_energy_per_link(&ZERO, &temperature); + assert!(nondimensional_relative_helmholtz_free_energy_per_link_0.abs() <= ZERO); + } + } +} +mod connection +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + 0.5*parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let end_to_end_length = nondimensional_end_to_end_length_per_link*(number_of_links as f64)*link_length; + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = model.force(&end_to_end_length, &temperature); + let h = parameters.rel_tol*(number_of_links as f64)*link_length; + let force_from_derivative = (model.relative_helmholtz_free_energy(&(end_to_end_length + 0.5*h), &temperature) - model.relative_helmholtz_free_energy(&(end_to_end_length - 0.5*h), &temperature))/h; + let residual_abs = &force - &force_from_derivative; + let residual_rel = &residual_abs/&force; + assert!(residual_rel.abs() <= h); + } + } + #[test] + fn nondimensional_force() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + 0.5*parameters.nondimensional_end_to_end_length_per_link_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_force = model.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let h = parameters.rel_tol; + let nondimensional_force_from_derivative = (model.nondimensional_relative_helmholtz_free_energy_per_link(&(nondimensional_end_to_end_length_per_link + 0.5*h), &temperature) - model.nondimensional_relative_helmholtz_free_energy_per_link(&(nondimensional_end_to_end_length_per_link - 0.5*h), &temperature))/h; + let residual_abs = &nondimensional_force - &nondimensional_force_from_derivative; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_rel.abs() <= h); + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs new file mode 100644 index 00000000..c4182857 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs @@ -0,0 +1,46 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. +pub mod legendre; + +/// The structure of the thermodynamics of the EFJC model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. + pub legendre: self::legendre::EFJC +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + legendre: self::legendre::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs new file mode 100644 index 00000000..ee769577 --- /dev/null +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs @@ -0,0 +1,46 @@ +#[cfg(feature = "extern")] +pub mod ex; + +#[cfg(feature = "python")] +pub mod py; + +mod test; + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach. +pub mod asymptotic; + +/// The structure of the thermodynamics of the EFJC model in the isometric ensemble. +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + pub link_length: f64, + + /// The number of links in the chain. + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an asymptotic approach. + pub asymptotic: self::asymptotic::EFJC +} + +/// The implemented functionality of the thermodynamics of the EFJC model in the isometric ensemble. +impl EFJC +{ + /// Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble. + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + asymptotic: self::asymptotic::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/test.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/mod.rs b/src/physics/single_chain/efjc/thermodynamics/mod.rs index b584eec9..3306c961 100644 --- a/src/physics/single_chain/efjc/thermodynamics/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/mod.rs @@ -3,6 +3,9 @@ pub mod py; mod test; +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble. +pub mod isometric; + /// The extensible freely-jointed chain (EFJC) model thermodynamics in the isotensional ensemble. pub mod isotensional; @@ -21,6 +24,9 @@ pub struct EFJC /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). pub link_stiffness: f64, + /// The thermodynamic functions of the model in the isometric ensemble. + pub isometric: isometric::EFJC, + /// The thermodynamic functions of the model in the isotensional ensemble. pub isotensional: isotensional::EFJC } @@ -37,7 +43,8 @@ impl EFJC link_length, number_of_links, link_stiffness, - isotensional: self::isotensional::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), + isometric: self::isometric::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), + isotensional: self::isotensional::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) } } } diff --git a/src/physics/single_chain/efjc/thermodynamics/test.rs b/src/physics/single_chain/efjc/thermodynamics/test.rs index ca53b0da..db598666 100644 --- a/src/physics/single_chain/efjc/thermodynamics/test.rs +++ b/src/physics/single_chain/efjc/thermodynamics/test.rs @@ -74,3 +74,223 @@ mod base } } } +mod legendre +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_force() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } +} +mod legendre_asymptotic +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_force() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } +} +mod legendre_asymptotic_alternative +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_force() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } +} +mod legendre_asymptotic_reduced +{ + use super::*; + use rand::Rng; + #[test] + fn force() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_force() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy() + { + assert!(0.0 == 1.0); + } + #[test] + fn nondimensional_relative_helmholtz_free_energy_per_link() + { + assert!(0.0 == 1.0); + } +} \ No newline at end of file From f403db727478748762561a616c5cda7033ea59e8 Mon Sep 17 00:00:00 2001 From: mrbuche Date: Tue, 18 Apr 2023 13:26:47 -0600 Subject: [PATCH 02/11] bump --- Cargo.toml | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d38bfe0..f5445b8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polymers" -version = "0.3.1" +version = "0.3.2" edition = "2021" description = "Polymers Modeling Library" license = "BSD-3-Clause" diff --git a/Project.toml b/Project.toml index 21185773..8d026124 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Polymers" uuid = "8aef037c-a721-4e8a-9d81-eb7093daef2c" authors = ["mrbuche "] -version = "0.3.1" +version = "0.3.2" [deps] DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" From 95c075ffea1ced2b2f90b39f078d8fb89877a13f Mon Sep 17 00:00:00 2001 From: mrbuche Date: Tue, 18 Apr 2023 13:31:58 -0600 Subject: [PATCH 03/11] test rust/python if testing julia --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 681f3281..1c785a39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,9 +4,11 @@ WORKDIR / RUN curl https://sh.rustup.rs -sSf | bash -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" COPY . . +RUN cargo test --verbose RUN pip install --no-cache-dir maturin && \ maturin build --all-features && \ - pip install --no-cache-dir target/wheels/*.whl + pip install --no-cache-dir target/wheels/*.whl && \ + pytest --verbose . COPY --from=julia /usr/local/julia/ /opt/julia/ ENV PATH "${PATH}:/opt/julia/bin" -RUN julia -e 'using Pkg; Pkg.develop(path="."); Pkg.build("Polymers"); Pkg.test("Polymers")' \ No newline at end of file +RUN julia -e 'using Pkg; Pkg.develop(path="."); Pkg.build("Polymers"); Pkg.test("Polymers")' From dedc54ad1cf18db2e66bb3192687d4467236ea65 Mon Sep 17 00:00:00 2001 From: mrbuche Date: Tue, 18 Apr 2023 13:42:48 -0600 Subject: [PATCH 04/11] docs fix --- .../single_chain/swfjc/thermodynamics.rst | 2 ++ .../swfjc/thermodynamics/isometric.rst | 15 ++++++++++++ .../thermodynamics/isometric/legendre.rst | 23 +++++++++++++++++++ .../single_chain/swfjc/thermodynamics.md | 1 + .../swfjc/thermodynamics/isometric.md | 7 ++++++ .../thermodynamics/isometric/legendre.md | 5 ++++ 6 files changed, 53 insertions(+) create mode 100644 docs/source/physics/single_chain/swfjc/thermodynamics/isometric.rst create mode 100644 docs/source/physics/single_chain/swfjc/thermodynamics/isometric/legendre.rst create mode 100644 docs/src/physics/single_chain/swfjc/thermodynamics/isometric.md create mode 100644 docs/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre.md diff --git a/docs/source/physics/single_chain/swfjc/thermodynamics.rst b/docs/source/physics/single_chain/swfjc/thermodynamics.rst index 9934f247..b4fb978c 100644 --- a/docs/source/physics/single_chain/swfjc/thermodynamics.rst +++ b/docs/source/physics/single_chain/swfjc/thermodynamics.rst @@ -4,6 +4,7 @@ SWFJC model thermodynamics .. toctree:: :maxdepth: 1 + Isometric Isotensional .. autoclass:: polymers.physics.single_chain.swfjc.thermodynamics::SWFJC(number_of_links, link_length, hinge_mass, well_width) @@ -12,4 +13,5 @@ SWFJC model thermodynamics .. autoattribute:: link_length .. autoattribute:: hinge_mass .. autoattribute:: well_width + .. autoattribute:: isometric .. autoattribute:: isotensional diff --git a/docs/source/physics/single_chain/swfjc/thermodynamics/isometric.rst b/docs/source/physics/single_chain/swfjc/thermodynamics/isometric.rst new file mode 100644 index 00000000..b57d82de --- /dev/null +++ b/docs/source/physics/single_chain/swfjc/thermodynamics/isometric.rst @@ -0,0 +1,15 @@ +SWFJC model thermodynamics (isometric) +====================================== + +.. toctree:: + :maxdepth: 1 + + Legendre + +.. autoclass:: polymers.physics.single_chain.swfjc.thermodynamics.isometric::SWFJC(number_of_links, link_length, hinge_mass, well_width) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: well_width + .. autoattribute:: legendre diff --git a/docs/source/physics/single_chain/swfjc/thermodynamics/isometric/legendre.rst b/docs/source/physics/single_chain/swfjc/thermodynamics/isometric/legendre.rst new file mode 100644 index 00000000..a0dcfac7 --- /dev/null +++ b/docs/source/physics/single_chain/swfjc/thermodynamics/isometric/legendre.rst @@ -0,0 +1,23 @@ +SWFJC model thermodynamics (isometric/legendre) +=============================================== + +.. autoclass:: polymers.physics.single_chain.swfjc.thermodynamics.isometric.legendre::SWFJC(number_of_links, link_length, hinge_mass, well_width) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: well_width + .. automethod:: force(end_to_end_length, temperature) + .. automethod:: nondimensional_force(nondimensional_end_to_end_length_per_link) + .. automethod:: helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: nondimensional_helmholtz_free_energy(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_relative_helmholtz_free_energy(nondimensional_end_to_end_length_per_link) + .. automethod:: nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link) + .. automethod:: equilibrium_distribution(end_to_end_length) + .. automethod:: nondimensional_equilibrium_distribution(nondimensional_end_to_end_length_per_link) + .. automethod:: equilibrium_radial_distribution(end_to_end_length) + .. automethod:: nondimensional_equilibrium_radial_distribution(nondimensional_end_to_end_length_per_link) diff --git a/docs/src/physics/single_chain/swfjc/thermodynamics.md b/docs/src/physics/single_chain/swfjc/thermodynamics.md index 9cde8984..99f00319 100644 --- a/docs/src/physics/single_chain/swfjc/thermodynamics.md +++ b/docs/src/physics/single_chain/swfjc/thermodynamics.md @@ -1,5 +1,6 @@ # SWFJC model thermodynamics + * [SWFJC model thermodynamics (isometric)](../../../isometric) * [SWFJC model thermodynamics (isotensional)](../../../isotensional) ```@autodocs diff --git a/docs/src/physics/single_chain/swfjc/thermodynamics/isometric.md b/docs/src/physics/single_chain/swfjc/thermodynamics/isometric.md new file mode 100644 index 00000000..df02f796 --- /dev/null +++ b/docs/src/physics/single_chain/swfjc/thermodynamics/isometric.md @@ -0,0 +1,7 @@ +# SWFJC model thermodynamics (isometric) + + * [SWFJC model thermodynamics (isometric/legendre)](../../../../legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Swfjc.Thermodynamics.Isometric] +``` diff --git a/docs/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre.md b/docs/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre.md new file mode 100644 index 00000000..e73c7e92 --- /dev/null +++ b/docs/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre.md @@ -0,0 +1,5 @@ +# SWFJC model thermodynamics (isometric/legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Swfjc.Thermodynamics.Isometric.Legendre] +``` From 88001417ea11595dd83f9db0b964b18825f3083b Mon Sep 17 00:00:00 2001 From: mrbuche Date: Tue, 18 Apr 2023 16:10:33 -0600 Subject: [PATCH 05/11] docs setup --- .../single_chain/efjc/thermodynamics.rst | 2 ++ .../efjc/thermodynamics/isometric.rst | 17 +++++++++++++++++ .../thermodynamics/isometric/asymptotic.rst | 19 +++++++++++++++++++ .../isometric/asymptotic/alternative.rst | 15 +++++++++++++++ .../asymptotic/alternative/legendre.rst | 19 +++++++++++++++++++ .../isometric/asymptotic/legendre.rst | 19 +++++++++++++++++++ .../isometric/asymptotic/reduced.rst | 15 +++++++++++++++ .../isometric/asymptotic/reduced/legendre.rst | 19 +++++++++++++++++++ .../thermodynamics/isometric/legendre.rst | 19 +++++++++++++++++++ .../single_chain/efjc/thermodynamics.md | 1 + .../efjc/thermodynamics/isometric.md | 8 ++++++++ .../thermodynamics/isometric/asymptotic.md | 9 +++++++++ .../isometric/asymptotic/alternative.md | 7 +++++++ .../asymptotic/alternative/legendre.md | 5 +++++ .../isometric/asymptotic/legendre.md | 5 +++++ .../isometric/asymptotic/reduced.md | 7 +++++++ .../isometric/asymptotic/reduced/legendre.md | 5 +++++ .../efjc/thermodynamics/isometric/legendre.md | 5 +++++ 18 files changed, 196 insertions(+) create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.rst create mode 100644 docs/source/physics/single_chain/efjc/thermodynamics/isometric/legendre.rst create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.md create mode 100644 docs/src/physics/single_chain/efjc/thermodynamics/isometric/legendre.md diff --git a/docs/source/physics/single_chain/efjc/thermodynamics.rst b/docs/source/physics/single_chain/efjc/thermodynamics.rst index 9f6fa24f..93c22ecc 100644 --- a/docs/source/physics/single_chain/efjc/thermodynamics.rst +++ b/docs/source/physics/single_chain/efjc/thermodynamics.rst @@ -4,6 +4,7 @@ EFJC model thermodynamics .. toctree:: :maxdepth: 1 + Isometric Isotensional .. autoclass:: polymers.physics.single_chain.efjc.thermodynamics::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) @@ -12,4 +13,5 @@ EFJC model thermodynamics .. autoattribute:: link_length .. autoattribute:: hinge_mass .. autoattribute:: link_stiffness + .. autoattribute:: isometric .. autoattribute:: isotensional diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric.rst new file mode 100644 index 00000000..a16da542 --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric.rst @@ -0,0 +1,17 @@ +EFJC model thermodynamics (isometric) +===================================== + +.. toctree:: + :maxdepth: 1 + + Asymptotic + Legendre + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. autoattribute:: asymptotic + .. autoattribute:: legendre diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.rst new file mode 100644 index 00000000..61e545fd --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.rst @@ -0,0 +1,19 @@ +EFJC model thermodynamics (isometric/asymptotic) +================================================ + +.. toctree:: + :maxdepth: 1 + + Alternative + Reduced + Legendre + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.asymptotic::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. autoattribute:: alternative + .. autoattribute:: reduced + .. autoattribute:: legendre diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.rst new file mode 100644 index 00000000..08d33c83 --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.rst @@ -0,0 +1,15 @@ +EFJC model thermodynamics (isometric/asymptotic/alternative) +============================================================ + +.. toctree:: + :maxdepth: 1 + + Legendre + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.asymptotic.alternative::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. autoattribute:: legendre diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.rst new file mode 100644 index 00000000..7b74c279 --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.rst @@ -0,0 +1,19 @@ +EFJC model thermodynamics (isometric/asymptotic/alternative/legendre) +===================================================================== + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.asymptotic.alternative.legendre::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. automethod:: force(end_to_end_length, temperature) + .. automethod:: nondimensional_force(nondimensional_end_to_end_length_per_link) + .. automethod:: helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: nondimensional_helmholtz_free_energy(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_relative_helmholtz_free_energy(nondimensional_end_to_end_length_per_link) + .. automethod:: nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link) diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.rst new file mode 100644 index 00000000..0fb4b07f --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.rst @@ -0,0 +1,19 @@ +EFJC model thermodynamics (isometric/asymptotic/legendre) +========================================================= + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.asymptotic.legendre::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. automethod:: force(end_to_end_length, temperature) + .. automethod:: nondimensional_force(nondimensional_end_to_end_length_per_link) + .. automethod:: helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: nondimensional_helmholtz_free_energy(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_relative_helmholtz_free_energy(nondimensional_end_to_end_length_per_link) + .. automethod:: nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link) diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.rst new file mode 100644 index 00000000..1330ef13 --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.rst @@ -0,0 +1,15 @@ +EFJC model thermodynamics (isometric/asymptotic/reduced) +======================================================== + +.. toctree:: + :maxdepth: 1 + + Legendre + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.asymptotic.reduced::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. autoattribute:: legendre diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.rst new file mode 100644 index 00000000..5260997f --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.rst @@ -0,0 +1,19 @@ +EFJC model thermodynamics (isometric/asymptotic/reduced/legendre) +================================================================= + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.asymptotic.reduced.legendre::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. automethod:: force(end_to_end_length, temperature) + .. automethod:: nondimensional_force(nondimensional_end_to_end_length_per_link) + .. automethod:: helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: nondimensional_helmholtz_free_energy(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_relative_helmholtz_free_energy(nondimensional_end_to_end_length_per_link) + .. automethod:: nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link) diff --git a/docs/source/physics/single_chain/efjc/thermodynamics/isometric/legendre.rst b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/legendre.rst new file mode 100644 index 00000000..c7fbf178 --- /dev/null +++ b/docs/source/physics/single_chain/efjc/thermodynamics/isometric/legendre.rst @@ -0,0 +1,19 @@ +EFJC model thermodynamics (isometric/legendre) +============================================== + +.. autoclass:: polymers.physics.single_chain.efjc.thermodynamics.isometric.legendre::EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + + .. autoattribute:: number_of_links + .. autoattribute:: link_length + .. autoattribute:: hinge_mass + .. autoattribute:: link_stiffness + .. automethod:: force(end_to_end_length, temperature) + .. automethod:: nondimensional_force(nondimensional_end_to_end_length_per_link) + .. automethod:: helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy(end_to_end_length, temperature) + .. automethod:: relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + .. automethod:: nondimensional_helmholtz_free_energy(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link, temperature) + .. automethod:: nondimensional_relative_helmholtz_free_energy(nondimensional_end_to_end_length_per_link) + .. automethod:: nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_end_to_end_length_per_link) diff --git a/docs/src/physics/single_chain/efjc/thermodynamics.md b/docs/src/physics/single_chain/efjc/thermodynamics.md index 9e851585..d302bb95 100644 --- a/docs/src/physics/single_chain/efjc/thermodynamics.md +++ b/docs/src/physics/single_chain/efjc/thermodynamics.md @@ -1,5 +1,6 @@ # EFJC model thermodynamics + * [EFJC model thermodynamics (isometric)](../../../isometric) * [EFJC model thermodynamics (isotensional)](../../../isotensional) ```@autodocs diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric.md new file mode 100644 index 00000000..f07184b3 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric.md @@ -0,0 +1,8 @@ +# EFJC model thermodynamics (isometric) + + * [EFJC model thermodynamics (isometric/asymptotic)](../../../../asymptotic) + * [EFJC model thermodynamics (isometric/legendre)](../../../../legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.md new file mode 100644 index 00000000..07fb8075 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic.md @@ -0,0 +1,9 @@ +# EFJC model thermodynamics (isometric/asymptotic) + + * [EFJC model thermodynamics (isometric/asymptotic/alternative)](../../../../../alternative) + * [EFJC model thermodynamics (isometric/asymptotic/reduced)](../../../../../reduced) + * [EFJC model thermodynamics (isometric/asymptotic/legendre)](../../../../../legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.md new file mode 100644 index 00000000..7209405d --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative.md @@ -0,0 +1,7 @@ +# EFJC model thermodynamics (isometric/asymptotic/alternative) + + * [EFJC model thermodynamics (isometric/asymptotic/alternative/legendre)](../../../../../../legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.md new file mode 100644 index 00000000..c430b555 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre.md @@ -0,0 +1,5 @@ +# EFJC model thermodynamics (isometric/asymptotic/alternative/legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative.Legendre] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.md new file mode 100644 index 00000000..fe4c72a5 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre.md @@ -0,0 +1,5 @@ +# EFJC model thermodynamics (isometric/asymptotic/legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Legendre] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.md new file mode 100644 index 00000000..871dce80 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced.md @@ -0,0 +1,7 @@ +# EFJC model thermodynamics (isometric/asymptotic/reduced) + + * [EFJC model thermodynamics (isometric/asymptotic/reduced/legendre)](../../../../../../legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Reduced] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.md new file mode 100644 index 00000000..75741e09 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre.md @@ -0,0 +1,5 @@ +# EFJC model thermodynamics (isometric/asymptotic/reduced/legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Reduced.Legendre] +``` diff --git a/docs/src/physics/single_chain/efjc/thermodynamics/isometric/legendre.md b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/legendre.md new file mode 100644 index 00000000..e77d3e78 --- /dev/null +++ b/docs/src/physics/single_chain/efjc/thermodynamics/isometric/legendre.md @@ -0,0 +1,5 @@ +# EFJC model thermodynamics (isometric/legendre) + +```@autodocs +Modules = [Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Legendre] +``` From daca970016952f77273f0526584c68f253b9082b Mon Sep 17 00:00:00 2001 From: mrbuche Date: Tue, 18 Apr 2023 16:36:09 -0600 Subject: [PATCH 06/11] files setup --- .../efjc/thermodynamics/isometric/__init__.py | 0 .../isometric/asymptotic/__init__.py | 0 .../asymptotic/alternative/__init__.py | 0 .../asymptotic/alternative/legendre/__init__.py | 0 .../asymptotic/alternative/legendre/ex.rs | 0 .../asymptotic/alternative/legendre/mod.jl | 0 .../asymptotic/alternative/legendre/py.rs | 0 .../asymptotic/alternative/legendre/test.jl | 0 .../asymptotic/alternative/legendre/test.py | 0 .../isometric/asymptotic/alternative/mod.jl | 0 .../isometric/asymptotic/alternative/py.rs | 0 .../isometric/asymptotic/alternative/test.jl | 0 .../isometric/asymptotic/alternative/test.py | 0 .../isometric/asymptotic/legendre/__init__.py | 0 .../isometric/asymptotic/legendre/ex.rs | 0 .../isometric/asymptotic/legendre/mod.jl | 0 .../isometric/asymptotic/legendre/py.rs | 0 .../isometric/asymptotic/legendre/test.jl | 0 .../isometric/asymptotic/legendre/test.py | 0 .../thermodynamics/isometric/asymptotic/mod.jl | 0 .../thermodynamics/isometric/asymptotic/py.rs | 0 .../isometric/asymptotic/reduced/__init__.py | 0 .../asymptotic/reduced/legendre/__init__.py | 0 .../isometric/asymptotic/reduced/legendre/ex.rs | 0 .../asymptotic/reduced/legendre/mod.jl | 0 .../isometric/asymptotic/reduced/legendre/py.rs | 0 .../asymptotic/reduced/legendre/test.jl | 0 .../asymptotic/reduced/legendre/test.py | 0 .../isometric/asymptotic/reduced/mod.jl | 0 .../isometric/asymptotic/reduced/py.rs | 0 .../isometric/asymptotic/reduced/test.jl | 0 .../isometric/asymptotic/reduced/test.py | 0 .../thermodynamics/isometric/asymptotic/test.jl | 0 .../thermodynamics/isometric/asymptotic/test.py | 0 .../efjc/thermodynamics/isometric/mod.jl | 0 .../efjc/thermodynamics/isometric/py.rs | 0 .../efjc/thermodynamics/isometric/test.jl | 0 .../efjc/thermodynamics/isometric/test.py | 0 test/runtests.jl | 17 +++++++++++++++++ 39 files changed, 17 insertions(+) create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/__init__.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/py.rs create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/test.jl create mode 100644 src/physics/single_chain/efjc/thermodynamics/isometric/test.py diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/__init__.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/py.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/test.py new file mode 100644 index 00000000..e69de29b diff --git a/test/runtests.jl b/test/runtests.jl index 12029146..9ed2dae4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,6 +24,23 @@ include( ) include("../src/physics/single_chain/efjc/test.jl") include("../src/physics/single_chain/efjc/thermodynamics/test.jl") +include("../src/physics/single_chain/efjc/thermodynamics/isometric/test.jl") +include("../src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl") +include( + "../src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl", +) +include( + "../src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl", +) +include( + "../src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl", +) +include( + "../src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl", +) +include( + "../src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl", +) include("../src/physics/single_chain/efjc/thermodynamics/isotensional/test.jl") include("../src/physics/single_chain/efjc/thermodynamics/isotensional/legendre/test.jl") include("../src/physics/single_chain/efjc/thermodynamics/isotensional/asymptotic/test.jl") From d58a7ccd8c6eee1a495c930e74f357530a90ccff Mon Sep 17 00:00:00 2001 From: mrbuche Date: Thu, 20 Apr 2023 14:25:02 -0600 Subject: [PATCH 07/11] tests --- .../asymptotic/alternative/legendre/mod.rs | 2 +- .../isometric/asymptotic/legendre/mod.rs | 2 +- .../asymptotic/reduced/legendre/mod.rs | 2 +- .../single_chain/efjc/thermodynamics/test.rs | 676 +++++++++++++++--- 4 files changed, 594 insertions(+), 88 deletions(-) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs index 4127180f..52cff29b 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.rs @@ -89,7 +89,7 @@ pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: & pub fn nondimensional_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 { let nondimensional_force = nondimensional_force(nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link); - -(nondimensional_force.sinh()/nondimensional_force).ln() - (0.5*nondimensional_force.powi(2) + nondimensional_force/nondimensional_force.tanh())/(nondimensional_link_stiffness) + nondimensional_force*nondimensional_end_to_end_length_per_link + (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() - (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) + -(nondimensional_force.sinh()/nondimensional_force).ln() - (0.5*nondimensional_force.powi(2) + nondimensional_force/nondimensional_force.tanh())/(nondimensional_link_stiffness) + nondimensional_force*nondimensional_end_to_end_length_per_link - (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) } /// The nondimensional relative Helmholtz free energy as a function of the nondimensional end-to-end length per link, parameterized by the number of links and nondimensional link stiffness. diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs index 0a512cc4..fbe7449f 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.rs @@ -89,7 +89,7 @@ pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: & pub fn nondimensional_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 { let nondimensional_force = nondimensional_force(nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link); - -(nondimensional_force.sinh()/nondimensional_force).ln() - 0.5*nondimensional_force.powi(2)/nondimensional_link_stiffness - (1.0 + nondimensional_force/nondimensional_force.tanh()/nondimensional_link_stiffness).ln() + nondimensional_force*nondimensional_end_to_end_length_per_link + (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() - (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) + -(nondimensional_force.sinh()/nondimensional_force).ln() - 0.5*nondimensional_force.powi(2)/nondimensional_link_stiffness - (1.0 + nondimensional_force/nondimensional_force.tanh()/nondimensional_link_stiffness).ln() + nondimensional_force*nondimensional_end_to_end_length_per_link - (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) } /// The nondimensional relative Helmholtz free energy as a function of the nondimensional end-to-end length per link, parameterized by the number of links and nondimensional link stiffness. diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs index 930bf367..b454231c 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.rs @@ -89,7 +89,7 @@ pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: & pub fn nondimensional_helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_link_stiffness: &f64, nondimensional_end_to_end_length_per_link: &f64, temperature: &f64) -> f64 { let nondimensional_force = nondimensional_force(nondimensional_link_stiffness, nondimensional_end_to_end_length_per_link); - -(nondimensional_force.sinh()/nondimensional_force).ln() - 0.5*nondimensional_force.powi(2)/nondimensional_link_stiffness + nondimensional_force*nondimensional_end_to_end_length_per_link + (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() - (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) + -(nondimensional_force.sinh()/nondimensional_force).ln() - 0.5*nondimensional_force.powi(2)/nondimensional_link_stiffness + nondimensional_force*nondimensional_end_to_end_length_per_link - (1.0 - 1.0/(*number_of_links as f64))*(0.5*(2.0*PI*link_length.powi(2)/nondimensional_link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()) } /// The nondimensional relative Helmholtz free energy as a function of the nondimensional end-to-end length per link, parameterized by the number of links and nondimensional link stiffness. diff --git a/src/physics/single_chain/efjc/thermodynamics/test.rs b/src/physics/single_chain/efjc/thermodynamics/test.rs index db598666..0db2bff0 100644 --- a/src/physics/single_chain/efjc/thermodynamics/test.rs +++ b/src/physics/single_chain/efjc/thermodynamics/test.rs @@ -1,6 +1,12 @@ #![cfg(test)] use super::*; +use crate::physics:: +{ + BOLTZMANN_CONSTANT, + PLANCK_CONSTANT +}; use crate::physics::single_chain::test::Parameters; +use std::f64::consts::PI; mod base { use super::*; @@ -74,61 +80,6 @@ mod base } } } -mod legendre -{ - use super::*; - use rand::Rng; - #[test] - fn force() - { - assert!(0.0 == 1.0); - } - #[test] - fn nondimensional_force() - { - assert!(0.0 == 1.0); - } - #[test] - fn helmholtz_free_energy() - { - assert!(0.0 == 1.0); - } - #[test] - fn helmholtz_free_energy_per_link() - { - assert!(0.0 == 1.0); - } - #[test] - fn relative_helmholtz_free_energy() - { - assert!(0.0 == 1.0); - } - #[test] - fn relative_helmholtz_free_energy_per_link() - { - assert!(0.0 == 1.0); - } - #[test] - fn nondimensional_helmholtz_free_energy() - { - assert!(0.0 == 1.0); - } - #[test] - fn nondimensional_helmholtz_free_energy_per_link() - { - assert!(0.0 == 1.0); - } - #[test] - fn nondimensional_relative_helmholtz_free_energy() - { - assert!(0.0 == 1.0); - } - #[test] - fn nondimensional_relative_helmholtz_free_energy_per_link() - { - assert!(0.0 == 1.0); - } -} mod legendre_asymptotic { use super::*; @@ -136,52 +87,237 @@ mod legendre_asymptotic #[test] fn force() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.end_to_end_length(&force, &temperature); + let force_out = model.isometric.asymptotic.legendre.force(&end_to_end_length, &temperature); + let residual_abs = &force - &force_out; + let residual_rel = &residual_abs/&force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_force() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link= model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_force_out = model.isometric.asymptotic.legendre.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_force - &nondimensional_force_out; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.end_to_end_length(&force, &temperature); + let helmholtz_free_energy_legendre = model.isotensional.asymptotic.gibbs_free_energy(&force, &temperature) + force*end_to_end_length; + let helmholtz_free_energy_legendre_out = model.isometric.asymptotic.legendre.helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_legendre - &helmholtz_free_energy_legendre_out + BOLTZMANN_CONSTANT*temperature*(0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()); + let residual_rel = &residual_abs/&helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.end_to_end_length(&force, &temperature); + let end_to_end_length_per_link = model.isotensional.asymptotic.end_to_end_length_per_link(&force, &temperature); + let helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.gibbs_free_energy_per_link(&force, &temperature) + force*end_to_end_length_per_link; + let helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.legendre.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link_legendre - &helmholtz_free_energy_per_link_legendre_out + BOLTZMANN_CONSTANT*temperature*(0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln())/(number_of_links as f64); + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn relative_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.end_to_end_length(&force, &temperature); + let relative_helmholtz_free_energy_legendre = model.isotensional.asymptotic.relative_gibbs_free_energy(&force, &temperature) + force*end_to_end_length; + let relative_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.legendre.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_legendre - &relative_helmholtz_free_energy_legendre_out; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_legendre; + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn relative_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.end_to_end_length(&force, &temperature); + let end_to_end_length_per_link = model.isotensional.asymptotic.end_to_end_length_per_link(&force, &temperature); + let relative_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.relative_gibbs_free_energy_per_link(&force, &temperature) + force*end_to_end_length_per_link; + let relative_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.legendre.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_per_link_legendre - &relative_helmholtz_free_energy_per_link_legendre_out; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_per_link_legendre; + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length = model.isotensional.asymptotic.nondimensional_end_to_end_length(&nondimensional_force, &temperature); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_helmholtz_free_energy_legendre = model.isotensional.asymptotic.nondimensional_gibbs_free_energy(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length; + let nondimensional_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.legendre.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_legendre - &nondimensional_helmholtz_free_energy_legendre_out + 0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln(); + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.nondimensional_gibbs_free_energy_per_link(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length_per_link; + let nondimensional_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.legendre.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_per_link_legendre - &nondimensional_helmholtz_free_energy_per_link_legendre_out + (0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln())/(number_of_links as f64); + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_relative_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length = model.isotensional.asymptotic.nondimensional_end_to_end_length(&nondimensional_force, &temperature); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_relative_helmholtz_free_energy_legendre = model.isotensional.asymptotic.nondimensional_relative_gibbs_free_energy(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length; + let nondimensional_relative_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.legendre.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy_legendre - &nondimensional_relative_helmholtz_free_energy_legendre_out; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_relative_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.nondimensional_relative_gibbs_free_energy_per_link(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length_per_link; + let nondimensional_relative_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.legendre.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy_per_link_legendre - &nondimensional_relative_helmholtz_free_energy_per_link_legendre_out; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } } mod legendre_asymptotic_alternative @@ -191,52 +327,237 @@ mod legendre_asymptotic_alternative #[test] fn force() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.alternative.end_to_end_length(&force, &temperature); + let force_out = model.isometric.asymptotic.alternative.legendre.force(&end_to_end_length, &temperature); + let residual_abs = &force - &force_out; + let residual_rel = &residual_abs/&force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_force() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link= model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_force_out = model.isometric.asymptotic.alternative.legendre.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_force - &nondimensional_force_out; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.alternative.end_to_end_length(&force, &temperature); + let helmholtz_free_energy_legendre = model.isotensional.asymptotic.alternative.gibbs_free_energy(&force, &temperature) + force*end_to_end_length; + let helmholtz_free_energy_legendre_out = model.isometric.asymptotic.alternative.legendre.helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_legendre - &helmholtz_free_energy_legendre_out + BOLTZMANN_CONSTANT*temperature*(0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()); + let residual_rel = &residual_abs/&helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.alternative.end_to_end_length(&force, &temperature); + let end_to_end_length_per_link = model.isotensional.asymptotic.alternative.end_to_end_length_per_link(&force, &temperature); + let helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.alternative.gibbs_free_energy_per_link(&force, &temperature) + force*end_to_end_length_per_link; + let helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.alternative.legendre.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link_legendre - &helmholtz_free_energy_per_link_legendre_out + BOLTZMANN_CONSTANT*temperature*(0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln())/(number_of_links as f64); + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn relative_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.alternative.end_to_end_length(&force, &temperature); + let relative_helmholtz_free_energy_legendre = model.isotensional.asymptotic.alternative.relative_gibbs_free_energy(&force, &temperature) + force*end_to_end_length; + let relative_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.alternative.legendre.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_legendre - &relative_helmholtz_free_energy_legendre_out; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_legendre; + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn relative_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.alternative.end_to_end_length(&force, &temperature); + let end_to_end_length_per_link = model.isotensional.asymptotic.alternative.end_to_end_length_per_link(&force, &temperature); + let relative_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.alternative.relative_gibbs_free_energy_per_link(&force, &temperature) + force*end_to_end_length_per_link; + let relative_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.alternative.legendre.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_per_link_legendre - &relative_helmholtz_free_energy_per_link_legendre_out; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_per_link_legendre; + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length = model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length(&nondimensional_force, &temperature); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_helmholtz_free_energy_legendre = model.isotensional.asymptotic.alternative.nondimensional_gibbs_free_energy(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length; + let nondimensional_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.alternative.legendre.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_legendre - &nondimensional_helmholtz_free_energy_legendre_out + 0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln(); + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.alternative.nondimensional_gibbs_free_energy_per_link(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length_per_link; + let nondimensional_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.alternative.legendre.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_per_link_legendre - &nondimensional_helmholtz_free_energy_per_link_legendre_out + (0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln())/(number_of_links as f64); + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_relative_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length = model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length(&nondimensional_force, &temperature); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_relative_helmholtz_free_energy_legendre = model.isotensional.asymptotic.alternative.nondimensional_relative_gibbs_free_energy(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length; + let nondimensional_relative_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.alternative.legendre.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy_legendre - &nondimensional_relative_helmholtz_free_energy_legendre_out; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_relative_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.alternative.nondimensional_relative_gibbs_free_energy_per_link(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length_per_link; + let nondimensional_relative_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.alternative.legendre.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy_per_link_legendre - &nondimensional_relative_helmholtz_free_energy_per_link_legendre_out; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } } mod legendre_asymptotic_reduced @@ -246,51 +567,236 @@ mod legendre_asymptotic_reduced #[test] fn force() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.reduced.end_to_end_length(&force, &temperature); + let force_out = model.isometric.asymptotic.reduced.legendre.force(&end_to_end_length, &temperature); + let residual_abs = &force - &force_out; + let residual_rel = &residual_abs/&force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_force() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link= model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_force_out = model.isometric.asymptotic.reduced.legendre.nondimensional_force(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_force - &nondimensional_force_out; + let residual_rel = &residual_abs/&nondimensional_force; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.reduced.end_to_end_length(&force, &temperature); + let helmholtz_free_energy_legendre = model.isotensional.asymptotic.reduced.gibbs_free_energy(&force, &temperature) + force*end_to_end_length; + let helmholtz_free_energy_legendre_out = model.isometric.asymptotic.reduced.legendre.helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_legendre - &helmholtz_free_energy_legendre_out + BOLTZMANN_CONSTANT*temperature*(0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln()); + let residual_rel = &residual_abs/&helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.reduced.end_to_end_length(&force, &temperature); + let end_to_end_length_per_link = model.isotensional.asymptotic.reduced.end_to_end_length_per_link(&force, &temperature); + let helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.reduced.gibbs_free_energy_per_link(&force, &temperature) + force*end_to_end_length_per_link; + let helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.reduced.legendre.helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &helmholtz_free_energy_per_link_legendre - &helmholtz_free_energy_per_link_legendre_out + BOLTZMANN_CONSTANT*temperature*(0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln())/(number_of_links as f64); + let residual_rel = &residual_abs/&helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn relative_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.reduced.end_to_end_length(&force, &temperature); + let relative_helmholtz_free_energy_legendre = model.isotensional.asymptotic.reduced.relative_gibbs_free_energy(&force, &temperature) + force*end_to_end_length; + let relative_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.reduced.legendre.relative_helmholtz_free_energy(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_legendre - &relative_helmholtz_free_energy_legendre_out; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_legendre; + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn relative_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let force = nondimensional_force*BOLTZMANN_CONSTANT*temperature/link_length; + let end_to_end_length = model.isotensional.asymptotic.reduced.end_to_end_length(&force, &temperature); + let end_to_end_length_per_link = model.isotensional.asymptotic.reduced.end_to_end_length_per_link(&force, &temperature); + let relative_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.reduced.relative_gibbs_free_energy_per_link(&force, &temperature) + force*end_to_end_length_per_link; + let relative_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.reduced.legendre.relative_helmholtz_free_energy_per_link(&end_to_end_length, &temperature); + let residual_abs = &relative_helmholtz_free_energy_per_link_legendre - &relative_helmholtz_free_energy_per_link_legendre_out; + let residual_rel = &residual_abs/&relative_helmholtz_free_energy_per_link_legendre; + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length = model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length(&nondimensional_force, &temperature); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_helmholtz_free_energy_legendre = model.isotensional.asymptotic.reduced.nondimensional_gibbs_free_energy(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length; + let nondimensional_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.reduced.legendre.nondimensional_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_legendre - &nondimensional_helmholtz_free_energy_legendre_out + 0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln(); + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.reduced.nondimensional_gibbs_free_energy_per_link(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length_per_link; + let nondimensional_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.reduced.legendre.nondimensional_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_helmholtz_free_energy_per_link_legendre - &nondimensional_helmholtz_free_energy_per_link_legendre_out + (0.5*(2.0*PI*BOLTZMANN_CONSTANT*temperature/link_stiffness).ln() + (8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln())/(number_of_links as f64); + let residual_rel = &residual_abs/&nondimensional_helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_relative_helmholtz_free_energy() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length = model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length(&nondimensional_force, &temperature); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_relative_helmholtz_free_energy_legendre = model.isotensional.asymptotic.reduced.nondimensional_relative_gibbs_free_energy(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length; + let nondimensional_relative_helmholtz_free_energy_legendre_out = model.isometric.asymptotic.reduced.legendre.nondimensional_relative_helmholtz_free_energy(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy_legendre - &nondimensional_relative_helmholtz_free_energy_legendre_out; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } #[test] fn nondimensional_relative_helmholtz_free_energy_per_link() { - assert!(0.0 == 1.0); + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + let nondimensional_force = parameters.nondimensional_force_reference + parameters.nondimensional_force_scale*(0.5 - rng.gen::()); + let temperature = parameters.temperature_reference + parameters.temperature_scale*(0.5 - rng.gen::()); + let nondimensional_end_to_end_length_per_link = model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link(&nondimensional_force, &temperature); + let nondimensional_relative_helmholtz_free_energy_per_link_legendre = model.isotensional.asymptotic.reduced.nondimensional_relative_gibbs_free_energy_per_link(&nondimensional_force, &temperature) + nondimensional_force*nondimensional_end_to_end_length_per_link; + let nondimensional_relative_helmholtz_free_energy_per_link_legendre_out = model.isometric.asymptotic.reduced.legendre.nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_end_to_end_length_per_link, &temperature); + let residual_abs = &nondimensional_relative_helmholtz_free_energy_per_link_legendre - &nondimensional_relative_helmholtz_free_energy_per_link_legendre_out; + let residual_rel = &residual_abs/&nondimensional_relative_helmholtz_free_energy_per_link_legendre; + assert!(residual_abs.abs() <= parameters.abs_tol); + assert!(residual_rel.abs() <= parameters.rel_tol); + } } } \ No newline at end of file From 23ff9e24a7b6675079befc0fa81791b5f3ecc61e Mon Sep 17 00:00:00 2001 From: mrbuche Date: Thu, 20 Apr 2023 15:25:38 -0600 Subject: [PATCH 08/11] python --- .../asymptotic/alternative/legendre/py.rs | 186 ++ .../asymptotic/alternative/legendre/test.py | 1346 +++++++++++ .../isometric/asymptotic/alternative/py.rs | 53 + .../isometric/asymptotic/alternative/test.py | 144 ++ .../isometric/asymptotic/alternative/test.rs | 76 + .../isometric/asymptotic/legendre/py.rs | 186 ++ .../isometric/asymptotic/legendre/test.py | 1346 +++++++++++ .../thermodynamics/isometric/asymptotic/py.rs | 65 + .../asymptotic/reduced/legendre/py.rs | 186 ++ .../asymptotic/reduced/legendre/test.py | 1346 +++++++++++ .../isometric/asymptotic/reduced/py.rs | 53 + .../isometric/asymptotic/reduced/test.py | 144 ++ .../isometric/asymptotic/reduced/test.rs | 76 + .../isometric/asymptotic/test.py | 143 ++ .../isometric/asymptotic/test.rs | 76 + .../efjc/thermodynamics/isometric/py.rs | 53 + .../efjc/thermodynamics/isometric/test.py | 143 ++ .../efjc/thermodynamics/isometric/test.rs | 76 + .../single_chain/efjc/thermodynamics/py.rs | 6 + .../single_chain/efjc/thermodynamics/test.py | 2016 +++++++++++++++++ 20 files changed, 7720 insertions(+) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs index e69de29b..2afb98a8 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/py.rs @@ -0,0 +1,186 @@ +use pyo3::prelude::*; +use numpy:: +{ + IntoPyArray, + PyArrayDyn, + PyReadonlyArrayDyn +}; +use crate::physics::BOLTZMANN_CONSTANT; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let legendre = PyModule::new(py, "legendre")?; + parent_module.add_submodule(legendre)?; + legendre.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64 +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness + } + } + /// The expected force as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The force :math:`f`. + /// + pub fn force<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::force(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional force :math:`\eta\equiv\beta f\ell_b`. + /// + pub fn nondimensional_force<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_force(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } + /// The Helmholtz free energy as a function of the applied end-to-end length and temperature, + /// + /// .. math:: + /// \psi(\xi, T) \sim \varphi\left[f(\xi, T)\right] + \xi f(\xi, T) \quad \text{for } N_b\gg 1, + /// + /// where :math:`f(\xi, T)` is given by the Legendre transformation approximation above. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The Helmholtz free energy :math:`\psi`. + /// + pub fn helmholtz_free_energy<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The Helmholtz free energy per link :math:`\psi/N_b`. + /// + pub fn helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The relative Helmholtz free energy :math:`\Delta\psi\equiv\psi(\xi,T)-\psi(0,T)`. + /// + pub fn relative_helmholtz_free_energy<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::relative_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The relative Helmholtz free energy per link :math:`\Delta\psi/N_b`. + /// + pub fn relative_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::relative_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional Helmholtz free energy :math:`\beta\psi=N_b\vartheta`. + /// + pub fn nondimensional_helmholtz_free_energy<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link, &temperature)).into_pyarray(py) + } + /// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link and temperature. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional Helmholtz free energy per link :math:`\vartheta\equiv\beta\psi/N_b`. + /// + pub fn nondimensional_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link, &temperature)).into_pyarray(py) + } + /// The nondimensional relative Helmholtz free energy as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional relative Helmholtz free energy :math:`\beta\Delta\psi=N_b\Delta\vartheta`. + /// + pub fn nondimensional_relative_helmholtz_free_energy<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_relative_helmholtz_free_energy(&self.number_of_links, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } + /// The nondimensional relative Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional relative Helmholtz free energy per link :math:`\Delta\vartheta\equiv\beta\Delta\psi/N_b`. + /// + pub fn nondimensional_relative_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_relative_helmholtz_free_energy_per_link(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py index e69de29b..89e07d08 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.py @@ -0,0 +1,1346 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc. \ + thermodynamics.isometric.asymptotic.alternative.legendre.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) + + +class Nondimensional(unittest.TestCase): + """Class for nondimensionalization tests. + + """ + def test_force(self): + """Function to test the nondimensionalization + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force = \ + model.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + force = \ + model.force( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + force / \ + parameters.boltzmann_constant/temperature*link_length \ + - nondimensional_force + residual_rel = \ + residual_abs / \ + nondimensional_force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy(self): + """Function to test the nondimensionalization + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the nondimensionalization + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the nondimensionalization + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the nondimensionalization + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_per_link / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class PerLink(unittest.TestCase): + """Class for per-linkness tests. + + """ + def test_helmholtz_free_energy(self): + """Function to test the per-linkness + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy / \ + number_of_links \ + - helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the per-linkness + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy / \ + number_of_links \ + - relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the per-linkness + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy / \ + number_of_links \ + - nondimensional_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the per-linkness + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_relative_helmholtz_free_energy / \ + number_of_links \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class Relative(unittest.TestCase): + """Class for relativeness tests. + + """ + def test_helmholtz_free_energy(self): + """Function to test the relativeness + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_0 = \ + model.helmholtz_free_energy( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy \ + - helmholtz_free_energy_0 \ + - relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the relativeness + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_per_link_0 = \ + model.helmholtz_free_energy_per_link( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link \ + - helmholtz_free_energy_per_link_0 \ + - relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the relativeness + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_0 = \ + model.nondimensional_helmholtz_free_energy( + np.array(parameters.zero), + temperature + ) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy \ + - nondimensional_helmholtz_free_energy_0 \ + - nondimensional_relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy_per_link(self): + """Function to test the relativeness + of the nondimensional Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_per_link_0 = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(parameters.zero), + temperature + ) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_per_link \ + - nondimensional_helmholtz_free_energy_per_link_0 \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class Zero(unittest.TestCase): + """Class for zero tests. + + """ + def test_force(self): + """Function to test the zero + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force_0 = \ + model.force( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(force_0), + number_of_links*parameters.boltzmann_constant*temperature / + link_length*parameters.zero + ) + + def test_nondimensional_force(self): + """Function to test the zero + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force_0 = \ + model.nondimensional_force( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs(nondimensional_force_0), + number_of_links*parameters.zero + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the zero + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + relative_helmholtz_free_energy_0 = \ + model.relative_helmholtz_free_energy( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(relative_helmholtz_free_energy_0), + parameters.boltzmann_constant*temperature * + number_of_links*parameters.zero + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the zero + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + relative_helmholtz_free_energy_per_link_0 = \ + model.relative_helmholtz_free_energy_per_link( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(relative_helmholtz_free_energy_per_link_0), + parameters.boltzmann_constant*temperature * + parameters.zero + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the zero + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_0 = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs(nondimensional_relative_helmholtz_free_energy_0), + number_of_links*parameters.zero + ) + + def test_nondimensional_relative_helmholtz_free_energy_per_link(self): + """Function to test the zero + of the nondimensional relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_per_link_0 = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs( + nondimensional_relative_helmholtz_free_energy_per_link_0 + ), parameters.zero + ) + + +class Connection(unittest.TestCase): + """Class for connection tests. + + """ + def test_force(self): + """Function to test the connection + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + force = \ + model.force( + np.array(end_to_end_length), + temperature + ) + h_step = parameters.rel_tol * \ + number_of_links*link_length + force_from_derivative = ( + model.relative_helmholtz_free_energy( + np.array(end_to_end_length + 0.5*h_step), + temperature + ) + - model.relative_helmholtz_free_energy( + np.array(end_to_end_length - 0.5*h_step), + temperature + ))/h_step + residual_abs = \ + force \ + - force_from_derivative + residual_rel = residual_abs/force + self.assertLessEqual( + np.abs(residual_rel), h_step + ) + + def test_nondimensional_force(self): + """Function to test the connection + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force = \ + model.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + h_step = parameters.rel_tol * \ + number_of_links*link_length + nondimensional_force_from_derivative = ( + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array( + nondimensional_end_to_end_length_per_link + 0.5*h_step + ), + temperature + ) + - model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array( + nondimensional_end_to_end_length_per_link - 0.5*h_step + ), + temperature + ))/h_step + residual_abs = \ + nondimensional_force \ + - nondimensional_force_from_derivative + residual_rel = residual_abs/nondimensional_force + self.assertLessEqual( + np.abs(residual_rel), h_step + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs index e69de29b..00d8877a 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/py.rs @@ -0,0 +1,53 @@ +use pyo3::prelude::*; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let alternative = PyModule::new(py, "alternative")?; + super::legendre::py::register_module(py, alternative)?; + parent_module.add_submodule(alternative)?; + alternative.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a alternative asymptotic approach. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using a alternative asymptotic approach and a Legendre transformation. + #[pyo3(get)] + pub legendre: super::legendre::py::EFJC +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + legendre: super::legendre::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py index e69de29b..9d5c8d6e 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.py @@ -0,0 +1,144 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc. \ + thermodynamics.isometric.asymptotic.alternative.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs index e69de29b..f50ed5a9 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.rs @@ -0,0 +1,76 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs index e69de29b..cefd4b19 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/py.rs @@ -0,0 +1,186 @@ +use pyo3::prelude::*; +use numpy:: +{ + IntoPyArray, + PyArrayDyn, + PyReadonlyArrayDyn +}; +use crate::physics::BOLTZMANN_CONSTANT; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let legendre = PyModule::new(py, "legendre")?; + parent_module.add_submodule(legendre)?; + legendre.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64 +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness + } + } + /// The expected force as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The force :math:`f`. + /// + pub fn force<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::force(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional force :math:`\eta\equiv\beta f\ell_b`. + /// + pub fn nondimensional_force<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_force(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } + /// The Helmholtz free energy as a function of the applied end-to-end length and temperature, + /// + /// .. math:: + /// \psi(\xi, T) \sim \varphi\left[f(\xi, T)\right] + \xi f(\xi, T) \quad \text{for } N_b\gg 1, + /// + /// where :math:`f(\xi, T)` is given by the Legendre transformation approximation above. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The Helmholtz free energy :math:`\psi`. + /// + pub fn helmholtz_free_energy<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The Helmholtz free energy per link :math:`\psi/N_b`. + /// + pub fn helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The relative Helmholtz free energy :math:`\Delta\psi\equiv\psi(\xi,T)-\psi(0,T)`. + /// + pub fn relative_helmholtz_free_energy<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::relative_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The relative Helmholtz free energy per link :math:`\Delta\psi/N_b`. + /// + pub fn relative_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::relative_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional Helmholtz free energy :math:`\beta\psi=N_b\vartheta`. + /// + pub fn nondimensional_helmholtz_free_energy<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link, &temperature)).into_pyarray(py) + } + /// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link and temperature. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional Helmholtz free energy per link :math:`\vartheta\equiv\beta\psi/N_b`. + /// + pub fn nondimensional_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link, &temperature)).into_pyarray(py) + } + /// The nondimensional relative Helmholtz free energy as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional relative Helmholtz free energy :math:`\beta\Delta\psi=N_b\Delta\vartheta`. + /// + pub fn nondimensional_relative_helmholtz_free_energy<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_relative_helmholtz_free_energy(&self.number_of_links, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } + /// The nondimensional relative Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional relative Helmholtz free energy per link :math:`\Delta\vartheta\equiv\beta\Delta\psi/N_b`. + /// + pub fn nondimensional_relative_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_relative_helmholtz_free_energy_per_link(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py index e69de29b..c7364ead 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.py @@ -0,0 +1,1346 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc. \ + thermodynamics.isometric.asymptotic.legendre.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) + + +class Nondimensional(unittest.TestCase): + """Class for nondimensionalization tests. + + """ + def test_force(self): + """Function to test the nondimensionalization + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force = \ + model.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + force = \ + model.force( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + force / \ + parameters.boltzmann_constant/temperature*link_length \ + - nondimensional_force + residual_rel = \ + residual_abs / \ + nondimensional_force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy(self): + """Function to test the nondimensionalization + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the nondimensionalization + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the nondimensionalization + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the nondimensionalization + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_per_link / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class PerLink(unittest.TestCase): + """Class for per-linkness tests. + + """ + def test_helmholtz_free_energy(self): + """Function to test the per-linkness + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy / \ + number_of_links \ + - helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the per-linkness + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy / \ + number_of_links \ + - relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the per-linkness + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy / \ + number_of_links \ + - nondimensional_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the per-linkness + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_relative_helmholtz_free_energy / \ + number_of_links \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class Relative(unittest.TestCase): + """Class for relativeness tests. + + """ + def test_helmholtz_free_energy(self): + """Function to test the relativeness + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_0 = \ + model.helmholtz_free_energy( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy \ + - helmholtz_free_energy_0 \ + - relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the relativeness + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_per_link_0 = \ + model.helmholtz_free_energy_per_link( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link \ + - helmholtz_free_energy_per_link_0 \ + - relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the relativeness + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_0 = \ + model.nondimensional_helmholtz_free_energy( + np.array(parameters.zero), + temperature + ) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy \ + - nondimensional_helmholtz_free_energy_0 \ + - nondimensional_relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy_per_link(self): + """Function to test the relativeness + of the nondimensional Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_per_link_0 = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(parameters.zero), + temperature + ) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_per_link \ + - nondimensional_helmholtz_free_energy_per_link_0 \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class Zero(unittest.TestCase): + """Class for zero tests. + + """ + def test_force(self): + """Function to test the zero + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force_0 = \ + model.force( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(force_0), + number_of_links*parameters.boltzmann_constant*temperature / + link_length*parameters.zero + ) + + def test_nondimensional_force(self): + """Function to test the zero + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force_0 = \ + model.nondimensional_force( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs(nondimensional_force_0), + number_of_links*parameters.zero + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the zero + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + relative_helmholtz_free_energy_0 = \ + model.relative_helmholtz_free_energy( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(relative_helmholtz_free_energy_0), + parameters.boltzmann_constant*temperature * + number_of_links*parameters.zero + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the zero + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + relative_helmholtz_free_energy_per_link_0 = \ + model.relative_helmholtz_free_energy_per_link( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(relative_helmholtz_free_energy_per_link_0), + parameters.boltzmann_constant*temperature * + parameters.zero + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the zero + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_0 = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs(nondimensional_relative_helmholtz_free_energy_0), + number_of_links*parameters.zero + ) + + def test_nondimensional_relative_helmholtz_free_energy_per_link(self): + """Function to test the zero + of the nondimensional relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_per_link_0 = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs( + nondimensional_relative_helmholtz_free_energy_per_link_0 + ), parameters.zero + ) + + +class Connection(unittest.TestCase): + """Class for connection tests. + + """ + def test_force(self): + """Function to test the connection + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + force = \ + model.force( + np.array(end_to_end_length), + temperature + ) + h_step = parameters.rel_tol * \ + number_of_links*link_length + force_from_derivative = ( + model.relative_helmholtz_free_energy( + np.array(end_to_end_length + 0.5*h_step), + temperature + ) + - model.relative_helmholtz_free_energy( + np.array(end_to_end_length - 0.5*h_step), + temperature + ))/h_step + residual_abs = \ + force \ + - force_from_derivative + residual_rel = residual_abs/force + self.assertLessEqual( + np.abs(residual_rel), h_step + ) + + def test_nondimensional_force(self): + """Function to test the connection + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force = \ + model.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + h_step = parameters.rel_tol * \ + number_of_links*link_length + nondimensional_force_from_derivative = ( + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array( + nondimensional_end_to_end_length_per_link + 0.5*h_step + ), + temperature + ) + - model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array( + nondimensional_end_to_end_length_per_link - 0.5*h_step + ), + temperature + ))/h_step + residual_abs = \ + nondimensional_force \ + - nondimensional_force_from_derivative + residual_rel = residual_abs/nondimensional_force + self.assertLessEqual( + np.abs(residual_rel), h_step + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs index e69de29b..5559647a 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/py.rs @@ -0,0 +1,65 @@ +use pyo3::prelude::*; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let asymptotic = PyModule::new(py, "asymptotic")?; + super::alternative::py::register_module(py, asymptotic)?; + super::reduced::py::register_module(py, asymptotic)?; + super::legendre::py::register_module(py, asymptotic)?; + parent_module.add_submodule(asymptotic)?; + asymptotic.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an alternative asymptotic approach. + #[pyo3(get)] + pub alternative: super::alternative::py::EFJC, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using a reduced asymptotic approach. + #[pyo3(get)] + pub reduced: super::reduced::py::EFJC, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. + #[pyo3(get)] + pub legendre: super::legendre::py::EFJC +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + alternative: super::alternative::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), + reduced: super::reduced::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), + legendre: super::legendre::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs index e69de29b..a9c64408 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/py.rs @@ -0,0 +1,186 @@ +use pyo3::prelude::*; +use numpy:: +{ + IntoPyArray, + PyArrayDyn, + PyReadonlyArrayDyn +}; +use crate::physics::BOLTZMANN_CONSTANT; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let legendre = PyModule::new(py, "legendre")?; + parent_module.add_submodule(legendre)?; + legendre.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64 +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness + } + } + /// The expected force as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The force :math:`f`. + /// + pub fn force<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::force(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The expected nondimensional force as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional force :math:`\eta\equiv\beta f\ell_b`. + /// + pub fn nondimensional_force<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_force(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } + /// The Helmholtz free energy as a function of the applied end-to-end length and temperature, + /// + /// .. math:: + /// \psi(\xi, T) \sim \varphi\left[f(\xi, T)\right] + \xi f(\xi, T) \quad \text{for } N_b\gg 1, + /// + /// where :math:`f(\xi, T)` is given by the Legendre transformation approximation above. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The Helmholtz free energy :math:`\psi`. + /// + pub fn helmholtz_free_energy<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The Helmholtz free energy per link :math:`\psi/N_b`. + /// + pub fn helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The relative Helmholtz free energy as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The relative Helmholtz free energy :math:`\Delta\psi\equiv\psi(\xi,T)-\psi(0,T)`. + /// + pub fn relative_helmholtz_free_energy<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::relative_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The relative Helmholtz free energy per link as a function of the applied end-to-end length and temperature. + /// + /// Args: + /// end_to_end_length (numpy.ndarray): The end-to-end length :math:`\xi`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The relative Helmholtz free energy per link :math:`\Delta\psi/N_b`. + /// + pub fn relative_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, end_to_end_length: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + end_to_end_length.as_array().mapv(|end_to_end_length: f64| super::relative_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.link_stiffness, &end_to_end_length, &temperature)).into_pyarray(py) + } + /// The nondimensional Helmholtz free energy as a function of the applied nondimensional end-to-end length per link and temperature. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional Helmholtz free energy :math:`\beta\psi=N_b\vartheta`. + /// + pub fn nondimensional_helmholtz_free_energy<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_helmholtz_free_energy(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link, &temperature)).into_pyarray(py) + } + /// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link and temperature. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// temperature (float): The temperature :math:`T`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional Helmholtz free energy per link :math:`\vartheta\equiv\beta\psi/N_b`. + /// + pub fn nondimensional_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_helmholtz_free_energy_per_link(&self.number_of_links, &self.link_length, &self.hinge_mass, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link, &temperature)).into_pyarray(py) + } + /// The nondimensional relative Helmholtz free energy as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional relative Helmholtz free energy :math:`\beta\Delta\psi=N_b\Delta\vartheta`. + /// + pub fn nondimensional_relative_helmholtz_free_energy<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_relative_helmholtz_free_energy(&self.number_of_links, &(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } + /// The nondimensional relative Helmholtz free energy per link as a function of the applied nondimensional end-to-end length per link. + /// + /// Args: + /// nondimensional_end_to_end_length_per_link (numpy.ndarray): The nondimensional end-to-end length per link :math:`\gamma\equiv \xi/N_b\ell_b`. + /// + /// Returns: + /// numpy.ndarray: The nondimensional relative Helmholtz free energy per link :math:`\Delta\vartheta\equiv\beta\Delta\psi/N_b`. + /// + pub fn nondimensional_relative_helmholtz_free_energy_per_link<'py>(&self, py: Python<'py>, nondimensional_end_to_end_length_per_link: PyReadonlyArrayDyn, temperature: f64) -> &'py PyArrayDyn + { + nondimensional_end_to_end_length_per_link.as_array().mapv(|nondimensional_end_to_end_length_per_link: f64| super::nondimensional_relative_helmholtz_free_energy_per_link(&(self.link_stiffness*self.link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), &nondimensional_end_to_end_length_per_link)).into_pyarray(py) + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py index e69de29b..be5c3ff1 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.py @@ -0,0 +1,1346 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc. \ + thermodynamics.isometric.asymptotic.reduced.legendre.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) + + +class Nondimensional(unittest.TestCase): + """Class for nondimensionalization tests. + + """ + def test_force(self): + """Function to test the nondimensionalization + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force = \ + model.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + force = \ + model.force( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + force / \ + parameters.boltzmann_constant/temperature*link_length \ + - nondimensional_force + residual_rel = \ + residual_abs / \ + nondimensional_force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy(self): + """Function to test the nondimensionalization + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the nondimensionalization + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the nondimensionalization + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the nondimensionalization + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_per_link / \ + parameters.boltzmann_constant/temperature \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class PerLink(unittest.TestCase): + """Class for per-linkness tests. + + """ + def test_helmholtz_free_energy(self): + """Function to test the per-linkness + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy / \ + number_of_links \ + - helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the per-linkness + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy / \ + number_of_links \ + - relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the per-linkness + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy / \ + number_of_links \ + - nondimensional_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the per-linkness + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_relative_helmholtz_free_energy / \ + number_of_links \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class Relative(unittest.TestCase): + """Class for relativeness tests. + + """ + def test_helmholtz_free_energy(self): + """Function to test the relativeness + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy = \ + model.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_0 = \ + model.helmholtz_free_energy( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + relative_helmholtz_free_energy = \ + model.relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy \ + - helmholtz_free_energy_0 \ + - relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the relativeness + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + helmholtz_free_energy_per_link = \ + model.helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + helmholtz_free_energy_per_link_0 = \ + model.helmholtz_free_energy_per_link( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + relative_helmholtz_free_energy_per_link = \ + model.relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link \ + - helmholtz_free_energy_per_link_0 \ + - relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the relativeness + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy = \ + model.nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_0 = \ + model.nondimensional_helmholtz_free_energy( + np.array(parameters.zero), + temperature + ) + nondimensional_relative_helmholtz_free_energy = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy \ + - nondimensional_helmholtz_free_energy_0 \ + - nondimensional_relative_helmholtz_free_energy + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy_per_link(self): + """Function to test the relativeness + of the nondimensional Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_helmholtz_free_energy_per_link = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + nondimensional_helmholtz_free_energy_per_link_0 = \ + model.nondimensional_helmholtz_free_energy_per_link( + np.array(parameters.zero), + temperature + ) + nondimensional_relative_helmholtz_free_energy_per_link = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_per_link \ + - nondimensional_helmholtz_free_energy_per_link_0 \ + - nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = \ + residual_abs / \ + nondimensional_relative_helmholtz_free_energy_per_link + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + +class Zero(unittest.TestCase): + """Class for zero tests. + + """ + def test_force(self): + """Function to test the zero + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force_0 = \ + model.force( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(force_0), + number_of_links*parameters.boltzmann_constant*temperature / + link_length*parameters.zero + ) + + def test_nondimensional_force(self): + """Function to test the zero + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force_0 = \ + model.nondimensional_force( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs(nondimensional_force_0), + number_of_links*parameters.zero + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the zero + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + relative_helmholtz_free_energy_0 = \ + model.relative_helmholtz_free_energy( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(relative_helmholtz_free_energy_0), + parameters.boltzmann_constant*temperature * + number_of_links*parameters.zero + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the zero + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + relative_helmholtz_free_energy_per_link_0 = \ + model.relative_helmholtz_free_energy_per_link( + np.array(parameters.zero*number_of_links*link_length), + temperature + ) + self.assertLessEqual( + np.abs(relative_helmholtz_free_energy_per_link_0), + parameters.boltzmann_constant*temperature * + parameters.zero + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the zero + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_0 = \ + model.nondimensional_relative_helmholtz_free_energy( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs(nondimensional_relative_helmholtz_free_energy_0), + number_of_links*parameters.zero + ) + + def test_nondimensional_relative_helmholtz_free_energy_per_link(self): + """Function to test the zero + of the nondimensional relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_relative_helmholtz_free_energy_per_link_0 = \ + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array(parameters.zero), + temperature + ) + self.assertLessEqual( + np.abs( + nondimensional_relative_helmholtz_free_energy_per_link_0 + ), parameters.zero + ) + + +class Connection(unittest.TestCase): + """Class for connection tests. + + """ + def test_force(self): + """Function to test the connection + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + end_to_end_length = nondimensional_end_to_end_length_per_link * \ + number_of_links*link_length + force = \ + model.force( + np.array(end_to_end_length), + temperature + ) + h_step = parameters.rel_tol * \ + number_of_links*link_length + force_from_derivative = ( + model.relative_helmholtz_free_energy( + np.array(end_to_end_length + 0.5*h_step), + temperature + ) + - model.relative_helmholtz_free_energy( + np.array(end_to_end_length - 0.5*h_step), + temperature + ))/h_step + residual_abs = \ + force \ + - force_from_derivative + residual_rel = residual_abs/force + self.assertLessEqual( + np.abs(residual_rel), h_step + ) + + def test_nondimensional_force(self): + """Function to test the connection + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_end_to_end_length_per_link = \ + parameters. \ + nondimensional_end_to_end_length_per_link_reference + \ + parameters. \ + nondimensional_end_to_end_length_per_link_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_force = \ + model.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + h_step = parameters.rel_tol * \ + number_of_links*link_length + nondimensional_force_from_derivative = ( + model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array( + nondimensional_end_to_end_length_per_link + 0.5*h_step + ), + temperature + ) + - model.nondimensional_relative_helmholtz_free_energy_per_link( + np.array( + nondimensional_end_to_end_length_per_link - 0.5*h_step + ), + temperature + ))/h_step + residual_abs = \ + nondimensional_force \ + - nondimensional_force_from_derivative + residual_rel = residual_abs/nondimensional_force + self.assertLessEqual( + np.abs(residual_rel), h_step + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs index e69de29b..3ce924e6 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/py.rs @@ -0,0 +1,53 @@ +use pyo3::prelude::*; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let reduced = PyModule::new(py, "reduced")?; + super::legendre::py::register_module(py, reduced)?; + parent_module.add_submodule(reduced)?; + reduced.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. + #[pyo3(get)] + pub legendre: super::legendre::py::EFJC +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + legendre: super::legendre::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py index e69de29b..4fb223d5 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.py @@ -0,0 +1,144 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc. \ + thermodynamics.isometric.asymptotic.reduced.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs index e69de29b..f50ed5a9 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.rs @@ -0,0 +1,76 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py index e69de29b..91402662 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.py @@ -0,0 +1,143 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc.thermodynamics.isometric.asymptotic.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs index e69de29b..f50ed5a9 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.rs @@ -0,0 +1,76 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/py.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/py.rs index e69de29b..dfa59528 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/py.rs @@ -0,0 +1,53 @@ +use pyo3::prelude::*; + +pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> +{ + let isometric = PyModule::new(py, "isometric")?; + super::asymptotic::py::register_module(py, isometric)?; + parent_module.add_submodule(isometric)?; + isometric.add_class::()?; + Ok(()) +} + +/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble. +#[pyclass] +#[derive(Copy, Clone)] +pub struct EFJC +{ + /// The mass of each hinge in the chain in units of kg/mol. + #[pyo3(get)] + pub hinge_mass: f64, + + /// The length of each link in the chain in units of nm. + #[pyo3(get)] + pub link_length: f64, + + /// The number of links in the chain. + #[pyo3(get)] + pub number_of_links: u8, + + /// The stiffness of each link in the chain in units of J/(mol⋅nm^2). + #[pyo3(get)] + pub link_stiffness: f64, + + /// The thermodynamic functions of the model in the isometric ensemble approximated using an asymptotic approach. + #[pyo3(get)] + pub asymptotic: super::asymptotic::py::EFJC +} + +#[pymethods] +impl EFJC +{ + #[new] + pub fn init(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64) -> Self + { + EFJC + { + hinge_mass, + link_length, + number_of_links, + link_stiffness, + asymptotic: super::asymptotic::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.py b/src/physics/single_chain/efjc/thermodynamics/isometric/test.py index e69de29b..c66b21dc 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/test.py @@ -0,0 +1,143 @@ +"""Module to test the local module. + +""" +import unittest +import numpy as np +from polymers import physics +from ..test import Parameters + +parameters = Parameters() +EFJC = physics.single_chain.efjc.thermodynamics.isometric.EFJC + + +class Base(unittest.TestCase): + """Class for basic tests. + + """ + def test_init(self): + """Function to test instantiation. + + """ + for _ in range(parameters.number_of_loops): + _ = EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ) + + def test_number_of_links(self): + """Function to test the number of links during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + self.assertEqual( + number_of_links, + EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).number_of_links + ) + + def test_link_length(self): + """Function to test the link length during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_length, + EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference + ).link_length + ) + + def test_hinge_mass(self): + """Function to test the hinge mass during instantiation. + + """ + for _ in range(parameters.number_of_loops): + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + self.assertEqual( + hinge_mass, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference + ).hinge_mass + ) + + def test_link_stiffness(self): + """Function to test the well width during instantiation. + + """ + for _ in range(parameters.number_of_loops): + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + self.assertEqual( + link_stiffness, + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness + ).link_stiffness + ) + + def test_all_parameters(self): + """Function to test all parameters during instantiation. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = \ + np.random.randint( + parameters.number_of_links_minimum, + high=parameters.number_of_links_maximum + ) + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + self.assertEqual( + number_of_links, + model.number_of_links + ) + self.assertEqual( + link_length, + model.link_length + ) + self.assertEqual( + hinge_mass, + model.hinge_mass + ) + self.assertEqual( + link_stiffness, + model.link_stiffness + ) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/test.rs index e69de29b..f50ed5a9 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/test.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/test.rs @@ -0,0 +1,76 @@ +#![cfg(test)] +use super::*; +use crate::physics::single_chain::test::Parameters; +mod base +{ + use super::*; + use rand::Rng; + #[test] + fn init() + { + let parameters = Parameters::default(); + let _ = EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference); + } + #[test] + fn number_of_links() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + assert_eq!(number_of_links, EFJC::init(number_of_links, parameters.link_length_reference, parameters.hinge_mass_reference, parameters.link_stiffness_reference).number_of_links); + } + } + #[test] + fn link_length() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + assert_eq!(link_length, EFJC::init(parameters.number_of_links_minimum, link_length, parameters.hinge_mass_reference, parameters.link_stiffness_reference).link_length); + } + } + #[test] + fn hinge_mass() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + assert_eq!(hinge_mass, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, hinge_mass, parameters.link_stiffness_reference).hinge_mass); + } + } + #[test] + fn link_stiffness() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + assert_eq!(link_stiffness, EFJC::init(parameters.number_of_links_minimum, parameters.link_length_reference, parameters.hinge_mass_reference, link_stiffness).link_stiffness); + } + } + #[test] + fn all_parameters() + { + let mut rng = rand::thread_rng(); + let parameters = Parameters::default(); + for _ in 0..parameters.number_of_loops + { + let number_of_links: u8 = rng.gen_range(parameters.number_of_links_minimum..parameters.number_of_links_maximum); + let hinge_mass = parameters.hinge_mass_reference + parameters.hinge_mass_scale*(0.5 - rng.gen::()); + let link_length = parameters.link_length_reference + parameters.link_length_scale*(0.5 - rng.gen::()); + let link_stiffness = parameters.link_stiffness_reference + parameters.link_stiffness_scale*(0.5 - rng.gen::()); + let model = EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness); + assert_eq!(number_of_links, model.number_of_links); + assert_eq!(link_length, model.link_length); + assert_eq!(hinge_mass, model.hinge_mass); + assert_eq!(link_stiffness, model.link_stiffness); + } + } +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/py.rs b/src/physics/single_chain/efjc/thermodynamics/py.rs index 5fca3d9d..39fc75e5 100644 --- a/src/physics/single_chain/efjc/thermodynamics/py.rs +++ b/src/physics/single_chain/efjc/thermodynamics/py.rs @@ -3,6 +3,7 @@ use pyo3::prelude::*; pub fn register_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> { let thermodynamics = PyModule::new(py, "thermodynamics")?; + super::isometric::py::register_module(py, thermodynamics)?; super::isotensional::py::register_module(py, thermodynamics)?; parent_module.add_submodule(thermodynamics)?; thermodynamics.add_class::()?; @@ -30,6 +31,10 @@ pub struct EFJC #[pyo3(get)] pub link_stiffness: f64, + /// The thermodynamic functions of the model in the isometric ensemble. + #[pyo3(get)] + pub isometric: super::isometric::py::EFJC, + /// The thermodynamic functions of the model in the isotensional ensemble. #[pyo3(get)] pub isotensional: super::isotensional::py::EFJC @@ -47,6 +52,7 @@ impl EFJC link_length, number_of_links, link_stiffness, + isometric: super::isometric::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness), isotensional: super::isotensional::py::EFJC::init(number_of_links, link_length, hinge_mass, link_stiffness) } } diff --git a/src/physics/single_chain/efjc/thermodynamics/test.py b/src/physics/single_chain/efjc/thermodynamics/test.py index 238bb239..2fd4a3b7 100644 --- a/src/physics/single_chain/efjc/thermodynamics/test.py +++ b/src/physics/single_chain/efjc/thermodynamics/test.py @@ -141,3 +141,2019 @@ def test_all_parameters(self): link_stiffness, model.link_stiffness ) + + +class LegendreAsymptotic(unittest.TestCase): + """Class for Legendre transformation tests. + + """ + def test_force(self): + """Function to test the Legendre transformation + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.end_to_end_length( + np.array(force), + temperature + ) + force_out = \ + model.isometric.asymptotic.legendre.force( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + force \ + - force_out + residual_rel = residual_abs/force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_force(self): + """Function to test the Legendre transformation + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force_out = \ + model.isometric.asymptotic.legendre.nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_force \ + - nondimensional_force_out + residual_rel = residual_abs/nondimensional_force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.end_to_end_length( + np.array(force), + temperature + ) + helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.gibbs_free_energy( + np.array(force), + temperature + ) + force*end_to_end_length + helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.legendre.helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_legendre \ + - helmholtz_free_energy_legendre_out \ + + parameters.boltzmann_constant*temperature*( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + ) + residual_rel = residual_abs/helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.end_to_end_length( + np.array(force), + temperature + ) + end_to_end_length_per_link = \ + model.isotensional.asymptotic.end_to_end_length_per_link( + np.array(force), + temperature + ) + helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.gibbs_free_energy_per_link( + np.array(force), + temperature + ) + force*end_to_end_length_per_link + helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.legendre. \ + helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link_legendre \ + - helmholtz_free_energy_per_link_legendre_out \ + + parameters.boltzmann_constant*temperature*( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + )/number_of_links + residual_rel = residual_abs/helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.end_to_end_length( + np.array(force), + temperature + ) + relative_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.relative_gibbs_free_energy( + np.array(force), + temperature + ) + force*end_to_end_length + relative_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.legendre. \ + relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_legendre \ + - relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs/relative_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.end_to_end_length( + np.array(force), + temperature + ) + end_to_end_length_per_link = \ + model.isotensional.asymptotic.end_to_end_length_per_link( + np.array(force), + temperature + ) + relative_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic. \ + relative_gibbs_free_energy_per_link( + np.array(force), + temperature + ) + force*end_to_end_length_per_link + relative_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.legendre. \ + relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_per_link_legendre \ + - relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / \ + relative_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length = \ + model.isotensional.asymptotic.nondimensional_end_to_end_length( + np.array(nondimensional_force), + temperature + ) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.nondimensional_gibbs_free_energy( + np.array(nondimensional_force), + temperature + ) + nondimensional_force*nondimensional_end_to_end_length + nondimensional_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.legendre. \ + nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_legendre \ + - nondimensional_helmholtz_free_energy_legendre_out \ + + ( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + ) + residual_rel = residual_abs / \ + nondimensional_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the nondimensional Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic. \ + nondimensional_gibbs_free_energy_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force * \ + nondimensional_end_to_end_length_per_link + nondimensional_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.legendre. \ + nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_per_link_legendre \ + - nondimensional_helmholtz_free_energy_per_link_legendre_out \ + + ( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + )/number_of_links + residual_rel = residual_abs / \ + nondimensional_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length = \ + model.isotensional.asymptotic.nondimensional_end_to_end_length( + np.array(nondimensional_force), + temperature + ) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_relative_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic. \ + nondimensional_relative_gibbs_free_energy( + np.array(nondimensional_force), + temperature + ) + nondimensional_force*nondimensional_end_to_end_length + nondimensional_relative_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.legendre. \ + nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_relative_helmholtz_free_energy_legendre \ + - nondimensional_relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / \ + nondimensional_relative_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the nondimensional relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondim_relative_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic. \ + nondimensional_relative_gibbs_free_energy_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force * \ + nondimensional_end_to_end_length_per_link + nondim_relative_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.legendre. \ + nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondim_relative_helmholtz_free_energy_per_link_legendre \ + - nondim_relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / \ + nondim_relative_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + +class LegendreAsymptoticAlternative(unittest.TestCase): + """Class for Legendre transformation tests. + + """ + def test_force(self): + """Function to test the Legendre transformation + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.reduced.end_to_end_length( + np.array(force), + temperature + ) + force_out = \ + model.isometric.asymptotic.reduced.legendre.force( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + force \ + - force_out + residual_rel = residual_abs/force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_force(self): + """Function to test the Legendre transformation + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force_out = \ + model.isometric.asymptotic.reduced.legendre. \ + nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_force \ + - nondimensional_force_out + residual_rel = residual_abs/nondimensional_force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.reduced.end_to_end_length( + np.array(force), + temperature + ) + helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.reduced.gibbs_free_energy( + np.array(force), + temperature + ) + force*end_to_end_length + helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_legendre \ + - helmholtz_free_energy_legendre_out \ + + parameters.boltzmann_constant*temperature*( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + ) + residual_rel = residual_abs/helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.reduced.end_to_end_length( + np.array(force), + temperature + ) + end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + end_to_end_length_per_link( + np.array(force), + temperature + ) + helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.reduced. \ + gibbs_free_energy_per_link( + np.array(force), + temperature + ) + force*end_to_end_length_per_link + helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link_legendre \ + - helmholtz_free_energy_per_link_legendre_out \ + + parameters.boltzmann_constant*temperature*( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + )/number_of_links + residual_rel = residual_abs/helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.reduced.end_to_end_length( + np.array(force), + temperature + ) + relative_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.reduced. \ + relative_gibbs_free_energy( + np.array(force), + temperature + ) + force*end_to_end_length + relative_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_legendre \ + - relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs/relative_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.reduced.end_to_end_length( + np.array(force), + temperature + ) + end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + end_to_end_length_per_link( + np.array(force), + temperature + ) + relative_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.reduced. \ + relative_gibbs_free_energy_per_link( + np.array(force), + temperature + ) + force*end_to_end_length_per_link + relative_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_per_link_legendre \ + - relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / \ + relative_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length( + np.array(nondimensional_force), + temperature + ) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_gibbs_free_energy( + np.array(nondimensional_force), + temperature + ) + nondimensional_force*nondimensional_end_to_end_length + nondimensional_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_legendre \ + - nondimensional_helmholtz_free_energy_legendre_out \ + + ( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + ) + residual_rel = residual_abs / \ + nondimensional_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the nondimensional Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_gibbs_free_energy_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force * \ + nondimensional_end_to_end_length_per_link + nondimensional_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_per_link_legendre \ + - nondimensional_helmholtz_free_energy_per_link_legendre_out \ + + ( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + )/number_of_links + residual_rel = residual_abs / \ + nondimensional_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length( + np.array(nondimensional_force), + temperature + ) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_relative_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_relative_gibbs_free_energy( + np.array(nondimensional_force), + temperature + ) + nondimensional_force*nondimensional_end_to_end_length + nondimensional_relative_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_relative_helmholtz_free_energy_legendre \ + - nondimensional_relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / \ + nondimensional_relative_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the nondimensional relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondim_relative_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.reduced. \ + nondimensional_relative_gibbs_free_energy_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force * \ + nondimensional_end_to_end_length_per_link + nondim_relative_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.reduced.legendre. \ + nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondim_relative_helmholtz_free_energy_per_link_legendre \ + - nondim_relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / \ + nondim_relative_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + +class LegendreAsymptoticReduced(unittest.TestCase): + """Class for Legendre transformation tests. + + """ + def test_force(self): + """Function to test the Legendre transformation + of the force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.alternative.end_to_end_length( + np.array(force), + temperature + ) + force_out = \ + model.isometric.asymptotic.alternative.legendre.force( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + force \ + - force_out + residual_rel = residual_abs/force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_force(self): + """Function to test the Legendre transformation + of the nondimensional force. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force_out = \ + model.isometric.asymptotic.alternative.legendre. \ + nondimensional_force( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_force \ + - nondimensional_force_out + residual_rel = residual_abs/nondimensional_force + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.alternative.end_to_end_length( + np.array(force), + temperature + ) + helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.alternative.gibbs_free_energy( + np.array(force), + temperature + ) + force*end_to_end_length + helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_legendre \ + - helmholtz_free_energy_legendre_out \ + + parameters.boltzmann_constant*temperature*( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + ) + residual_rel = residual_abs/helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.alternative.end_to_end_length( + np.array(force), + temperature + ) + end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + end_to_end_length_per_link( + np.array(force), + temperature + ) + helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.alternative. \ + gibbs_free_energy_per_link( + np.array(force), + temperature + ) + force*end_to_end_length_per_link + helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + helmholtz_free_energy_per_link_legendre \ + - helmholtz_free_energy_per_link_legendre_out \ + + parameters.boltzmann_constant*temperature*( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + )/number_of_links + residual_rel = residual_abs/helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.alternative.end_to_end_length( + np.array(force), + temperature + ) + relative_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.alternative. \ + relative_gibbs_free_energy( + np.array(force), + temperature + ) + force*end_to_end_length + relative_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + relative_helmholtz_free_energy( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_legendre \ + - relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs/relative_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_relative_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + force = nondimensional_force * \ + parameters.boltzmann_constant*temperature/link_length + end_to_end_length = \ + model.isotensional.asymptotic.alternative.end_to_end_length( + np.array(force), + temperature + ) + end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + end_to_end_length_per_link( + np.array(force), + temperature + ) + relative_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.alternative. \ + relative_gibbs_free_energy_per_link( + np.array(force), + temperature + ) + force*end_to_end_length_per_link + relative_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + relative_helmholtz_free_energy_per_link( + np.array(end_to_end_length), + temperature + ) + residual_abs = \ + relative_helmholtz_free_energy_per_link_legendre \ + - relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / \ + relative_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the nondimensional Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length( + np.array(nondimensional_force), + temperature + ) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_gibbs_free_energy( + np.array(nondimensional_force), + temperature + ) + nondimensional_force*nondimensional_end_to_end_length + nondimensional_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + nondimensional_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_legendre \ + - nondimensional_helmholtz_free_energy_legendre_out \ + + ( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + ) + residual_rel = residual_abs / \ + nondimensional_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the nondimensional Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_gibbs_free_energy_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force * \ + nondimensional_end_to_end_length_per_link + nondimensional_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + nondimensional_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_helmholtz_free_energy_per_link_legendre \ + - nondimensional_helmholtz_free_energy_per_link_legendre_out \ + + ( + 0.5*np.log( + 2.0*np.pi*parameters.boltzmann_constant * + temperature/link_stiffness + ) + + np.log( + 8*np.pi**2*hinge_mass*link_length**2 * + parameters.boltzmann_constant*temperature / + parameters.planck_constant**2 + ) + )/number_of_links + residual_rel = residual_abs / \ + nondimensional_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_abs), + parameters.abs_tol + ) + self.assertLessEqual( + np.abs(residual_rel), + parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy(self): + """Function to test the Legendre transformation + of the nondimensional relative Helmholtz free energy. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length( + np.array(nondimensional_force), + temperature + ) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_relative_helmholtz_free_energy_legendre = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_relative_gibbs_free_energy( + np.array(nondimensional_force), + temperature + ) + nondimensional_force*nondimensional_end_to_end_length + nondimensional_relative_helmholtz_free_energy_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + nondimensional_relative_helmholtz_free_energy( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondimensional_relative_helmholtz_free_energy_legendre \ + - nondimensional_relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / \ + nondimensional_relative_helmholtz_free_energy_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) + + def test_nondimensional_relative_helmholtz_free_energy_per_link(self): + """Function to test the Legendre transformation + of the nondimensional relative Helmholtz free energy per link. + + """ + for _ in range(parameters.number_of_loops): + number_of_links = parameters.number_of_links_maximum + link_length = \ + parameters.link_length_reference + \ + parameters.link_length_scale*(0.5 - np.random.rand()) + hinge_mass = \ + parameters.hinge_mass_reference + \ + parameters.hinge_mass_scale*(0.5 - np.random.rand()) + link_stiffness = \ + parameters.link_stiffness_reference + \ + parameters.link_stiffness_scale*(0.5 - np.random.rand()) + model = EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness + ) + nondimensional_force = \ + parameters. \ + nondimensional_force_reference + \ + parameters. \ + nondimensional_force_scale * \ + (0.5 - np.random.rand()) + temperature = \ + parameters.temperature_reference + \ + parameters.temperature_scale*(0.5 - np.random.rand()) + nondimensional_end_to_end_length_per_link = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_end_to_end_length_per_link( + np.array(nondimensional_force), + temperature + ) + nondim_relative_helmholtz_free_energy_per_link_legendre = \ + model.isotensional.asymptotic.alternative. \ + nondimensional_relative_gibbs_free_energy_per_link( + np.array(nondimensional_force), + temperature + ) + nondimensional_force * \ + nondimensional_end_to_end_length_per_link + nondim_relative_helmholtz_free_energy_per_link_legendre_out = \ + model.isometric.asymptotic.alternative.legendre. \ + nondimensional_relative_helmholtz_free_energy_per_link( + np.array(nondimensional_end_to_end_length_per_link), + temperature + ) + residual_abs = \ + nondim_relative_helmholtz_free_energy_per_link_legendre \ + - nondim_relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / \ + nondim_relative_helmholtz_free_energy_per_link_legendre + self.assertLessEqual( + np.abs(residual_rel), + 3e1 * parameters.rel_tol + ) From f07cfae2ab57e85a2be7c60c8d94c6f2363e829f Mon Sep 17 00:00:00 2001 From: mrbuche Date: Thu, 20 Apr 2023 16:11:26 -0600 Subject: [PATCH 09/11] julia setup --- .../asymptotic/alternative/legendre/mod.jl | 54 ++++++++++ .../asymptotic/alternative/legendre/test.jl | 101 ++++++++++++++++++ .../isometric/asymptotic/alternative/mod.jl | 59 ++++++++++ .../isometric/asymptotic/alternative/mod.rs | 3 - .../isometric/asymptotic/alternative/test.jl | 100 +++++++++++++++++ .../isometric/asymptotic/legendre/mod.jl | 54 ++++++++++ .../isometric/asymptotic/legendre/test.jl | 101 ++++++++++++++++++ .../isometric/asymptotic/mod.jl | 71 ++++++++++++ .../isometric/asymptotic/mod.rs | 3 - .../asymptotic/reduced/legendre/mod.jl | 54 ++++++++++ .../asymptotic/reduced/legendre/test.jl | 101 ++++++++++++++++++ .../isometric/asymptotic/reduced/mod.jl | 59 ++++++++++ .../isometric/asymptotic/reduced/mod.rs | 3 - .../isometric/asymptotic/reduced/test.jl | 100 +++++++++++++++++ .../isometric/asymptotic/test.jl | 100 +++++++++++++++++ .../efjc/thermodynamics/isometric/mod.jl | 59 ++++++++++ .../efjc/thermodynamics/isometric/mod.rs | 3 - .../efjc/thermodynamics/isometric/test.jl | 100 +++++++++++++++++ .../single_chain/efjc/thermodynamics/mod.jl | 6 ++ 19 files changed, 1119 insertions(+), 12 deletions(-) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl index e69de29b..00606186 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl @@ -0,0 +1,54 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. +""" +module Legendre + +using DocStringExtensions +using .........Polymers: PROJECT_ROOT + +import ........Physics: BOLTZMANN_CONSTANT + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + BOLTZMANN_CONSTANT::Float64 = 8.314462618 + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ) +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl index e69de29b..1a52ca12 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl @@ -0,0 +1,101 @@ +module Test + +using Test +using Polymers.Physics: BOLTZMANN_CONSTANT +using Polymers.Physics.SingleChain: ZERO, parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative.Legendre: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl index e69de29b..8ea693a9 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl @@ -0,0 +1,59 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an alternative asymptotic approach. +""" +module Alternative + +using DocStringExtensions +using ........Polymers: PROJECT_ROOT + +include("legendre/mod.jl") + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach. + +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 + """ + The thermodynamic functions of the model in the isometric ensemble approximated using an alternative asymptotic approach and a Legendre transformation. + """ + legendre::Any +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an alternative asymptotic approach. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + Legendre.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), + ) +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs index 1c835718..9e2d9dd9 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "extern")] -pub mod ex; - #[cfg(feature = "python")] pub mod py; diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl index e69de29b..3ccc5784 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl @@ -0,0 +1,100 @@ +module Test + +using Test +using Polymers.Physics.SingleChain: parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl index e69de29b..b33cdfbf 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl @@ -0,0 +1,54 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. +""" +module Legendre + +using DocStringExtensions +using ........Polymers: PROJECT_ROOT + +import .......Physics: BOLTZMANN_CONSTANT + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + BOLTZMANN_CONSTANT::Float64 = 8.314462618 + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ) +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl index e69de29b..8a5741cf 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl @@ -0,0 +1,101 @@ +module Test + +using Test +using Polymers.Physics: BOLTZMANN_CONSTANT +using Polymers.Physics.SingleChain: ZERO, parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Legendre: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl index e69de29b..a70aea53 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl @@ -0,0 +1,71 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach. +""" +module Asymptotic + +using DocStringExtensions +using .......Polymers: PROJECT_ROOT + +include("alternative/mod.jl") +include("reduced/mod.jl") +include("legendre/mod.jl") + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach. + +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 + """ + The thermodynamic functions of the model in the isometric ensemble approximated using an alternative asymptotic approach. + """ + alternative::Any + """ + The thermodynamic functions of the model in the isometric ensemble approximated using a reduced asymptotic approach. + """ + reduced::Any + """ + The thermodynamic functions of the model in the isometric ensemble approximated using an asymptotic approach and a Legendre transformation. + """ + legendre::Any +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using an asymptotic approach. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + Alternative.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), + Reduced.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), + Legendre.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), + ) +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs index 9424e56b..dc1df5a2 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "extern")] -pub mod ex; - #[cfg(feature = "python")] pub mod py; diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl index e69de29b..89c72400 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl @@ -0,0 +1,54 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. +""" +module Legendre + +using DocStringExtensions +using .........Polymers: PROJECT_ROOT + +import ........Physics: BOLTZMANN_CONSTANT + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + BOLTZMANN_CONSTANT::Float64 = 8.314462618 + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ) +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl index e69de29b..a039b32e 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl @@ -0,0 +1,101 @@ +module Test + +using Test +using Polymers.Physics: BOLTZMANN_CONSTANT +using Polymers.Physics.SingleChain: ZERO, parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Reduced.Legendre: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl index e69de29b..20961094 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl @@ -0,0 +1,59 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using a reduced asymptotic approach. +""" +module Reduced + +using DocStringExtensions +using ........Polymers: PROJECT_ROOT + +include("legendre/mod.jl") + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach. + +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 + """ + The thermodynamic functions of the model in the isometric ensemble approximated using a reduced asymptotic approach and a Legendre transformation. + """ + legendre::Any +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble approximated using a reduced asymptotic approach. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + Legendre.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), + ) +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs index c4182857..7d1185ab 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "extern")] -pub mod ex; - #[cfg(feature = "python")] pub mod py; diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl index e69de29b..dcc1adc7 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl @@ -0,0 +1,100 @@ +module Test + +using Test +using Polymers.Physics.SingleChain: parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Reduced: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl index e69de29b..b13c3ce8 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl @@ -0,0 +1,100 @@ +module Test + +using Test +using Polymers.Physics.SingleChain: parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl index e69de29b..350c016a 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.jl @@ -0,0 +1,59 @@ +""" +The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble. +""" +module Isometric + +using DocStringExtensions +using ......Polymers: PROJECT_ROOT + +include("asymptotic/mod.jl") + +""" +The structure of the thermodynamics of the EFJC model in the isometric ensemble. + +$(FIELDS) +""" +struct EFJC + """ + The number of links in the chain ``N_b``. + """ + number_of_links::UInt8 + """ + The length of each link in the chain ``\\ell_b`` in units of nm. + """ + link_length::Float64 + """ + The mass of each hinge in the chain ``m`` in units of kg/mol. + """ + hinge_mass::Float64 + """ + The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). + """ + link_stiffness::Float64 + """ + The thermodynamic functions of the model in the isometric ensemble approximated using an asymptotic approach. + """ + asymptotic::Any +end + +""" +Initializes and returns an instance of the thermodynamics of the EFJC model in the isometric ensemble. + +$(TYPEDSIGNATURES) +""" +function EFJC( + number_of_links::UInt8, + link_length::Float64, + hinge_mass::Float64, + link_stiffness::Float64, +) + return EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + Asymptotic.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), + ) +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs index ee769577..b826a9b4 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "extern")] -pub mod ex; - #[cfg(feature = "python")] pub mod py; diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl index e69de29b..a2f2e101 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl @@ -0,0 +1,100 @@ +module Test + +using Test +using Polymers.Physics.SingleChain: parameters +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric: EFJC + +@testset "physics::single_chain::efjc::thermodynamics::isometric::test::base::init" begin + @test isa( + EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ), + Any, + ) +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::test::base::number_of_links" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + @test EFJC( + number_of_links, + parameters.link_length_reference, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).number_of_links == number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::test::base::link_length" begin + for _ = 1:parameters.number_of_loops + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + link_length, + parameters.hinge_mass_reference, + parameters.link_stiffness_reference, + ).link_length == link_length + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::test::base::hinge_mass" begin + for _ = 1:parameters.number_of_loops + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + hinge_mass, + parameters.link_stiffness_reference, + ).hinge_mass == hinge_mass + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::test::base::link_stiffness" begin + for _ = 1:parameters.number_of_loops + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test EFJC( + parameters.number_of_links_minimum, + parameters.link_length_reference, + parameters.hinge_mass_reference, + link_stiffness, + ).link_stiffness == link_stiffness + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::test::base::all_parameters" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + @test all( + EFJC( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + ).number_of_links == number_of_links && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_length == + link_length && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).hinge_mass == + hinge_mass && + EFJC(number_of_links, link_length, hinge_mass, link_stiffness).link_stiffness == + link_stiffness, + ) + end +end + +end \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/mod.jl b/src/physics/single_chain/efjc/thermodynamics/mod.jl index f59779f3..c46bbf76 100644 --- a/src/physics/single_chain/efjc/thermodynamics/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/mod.jl @@ -5,6 +5,7 @@ module Thermodynamics using DocStringExtensions +include("isometric/mod.jl") include("isotensional/mod.jl") """ @@ -30,6 +31,10 @@ struct EFJC """ link_stiffness::Float64 """ + The thermodynamic functions of the model in the isometric ensemble. + """ + isometric::Any + """ The thermodynamic functions of the model in the isotensional ensemble. """ isotensional::Any @@ -51,6 +56,7 @@ function EFJC( link_length, hinge_mass, link_stiffness, + Isometric.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), Isotensional.EFJC(number_of_links, link_length, hinge_mass, link_stiffness), ) end From a1eb3d9040388427ddabc221eb39267ea1d28db4 Mon Sep 17 00:00:00 2001 From: mrbuche Date: Thu, 20 Apr 2023 16:52:32 -0600 Subject: [PATCH 10/11] julia --- .../asymptotic/alternative/legendre/ex.rs | 50 + .../asymptotic/alternative/legendre/mod.jl | 506 +++++++ .../asymptotic/alternative/legendre/test.jl | 649 +++++++- .../isometric/asymptotic/alternative/mod.jl | 2 +- .../isometric/asymptotic/alternative/test.jl | 5 +- .../isometric/asymptotic/legendre/ex.rs | 50 + .../isometric/asymptotic/legendre/mod.jl | 506 +++++++ .../isometric/asymptotic/legendre/test.jl | 646 +++++++- .../isometric/asymptotic/mod.jl | 2 +- .../asymptotic/reduced/legendre/ex.rs | 50 + .../asymptotic/reduced/legendre/mod.jl | 506 +++++++ .../asymptotic/reduced/legendre/test.jl | 649 +++++++- .../isometric/asymptotic/reduced/mod.jl | 2 +- .../isometric/asymptotic/reduced/test.jl | 2 +- .../isometric/asymptotic/test.jl | 2 +- .../efjc/thermodynamics/isometric/test.jl | 2 +- .../single_chain/efjc/thermodynamics/test.jl | 1328 +++++++++++++++++ .../thermodynamics/isometric/legendre/ex.rs | 16 +- .../thermodynamics/isometric/legendre/ex.rs | 8 +- .../thermodynamics/isometric/legendre/test.jl | 2 - 20 files changed, 4956 insertions(+), 27 deletions(-) diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs index e69de29b..a2d7c60b 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/ex.rs @@ -0,0 +1,50 @@ +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_force(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::force(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_force(nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_force(&nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_relative_helmholtz_free_energy(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::relative_helmholtz_free_energy(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_relative_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::relative_helmholtz_free_energy_per_link(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 +{ + super::nondimensional_helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 +{ + super::nondimensional_helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_relative_helmholtz_free_energy(number_of_links: u8, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_relative_helmholtz_free_energy(&number_of_links, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl index 00606186..bfcc5c84 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/mod.jl @@ -29,6 +29,442 @@ struct EFJC The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). """ link_stiffness::Float64 + """ + The expected force ``f`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + force::Function + """ + The expected nondimensional force ``\\eta`` as a function of the applied nondimensional end-to-end length per link ``\\gamma``. + """ + nondimensional_force::Function + """ + The Helmholtz free energy ``\\psi`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + helmholtz_free_energy::Function + """ + The Helmholtz free energy per link ``\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + helmholtz_free_energy_per_link::Function + """ + The relative Helmholtz free energy ``\\Delta\\psi\\equiv\\psi(\\xi,T)-\\psi(0,T)`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + relative_helmholtz_free_energy::Function + """ + The relative Helmholtz free energy per link ``\\Delta\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + relative_helmholtz_free_energy_per_link::Function + """ + The nondimensional Helmholtz free energy ``N_b\\vartheta=\\beta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``. + """ + nondimensional_helmholtz_free_energy::Function + """ + The nondimensional Helmholtz free energy per link ``\\vartheta\\equiv\\beta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``. + """ + nondimensional_helmholtz_free_energy_per_link::Function + """ + The nondimensional relative Helmholtz free energy ``N_b\\Delta\\vartheta=\\beta\\Delta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma``. + """ + nondimensional_relative_helmholtz_free_energy::Function + """ + The nondimensional relative Helmholtz free energy per link ``\\Delta\\vartheta\\equiv\\beta\\Delta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` + """ + nondimensional_relative_helmholtz_free_energy_per_link::Function +end + +""" +The expected force as a function ``f`` of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function force( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_force, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The expected nondimensional force as a function ``\\eta`` of the applied nondimensional end-to-end length per link ``\\gamma``, +parameterized by the link length ``\\ell_b`` and nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_force( + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + (nondimensional_link_stiffness_i, nondimensional_end_to_end_length_per_link_i) -> + ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_force, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (Float64, Float64), + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) +end + +""" +The Helmholtz free energy ``\\psi`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, link stiffness ``k_0``, and hinge mass ``m``, + +```math +\\psi(\\xi, T) \\sim \\varphi\\left[f(\\xi, T)\\right] + \\xi f(\\xi, T) \\quad \\text{for } N_b\\gg 1, +``` + +where ``f(\\xi, T)`` is given by the Legendre transformation approximation above. + +$(TYPEDSIGNATURES) +""" +function helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The Helmholtz free energy per link ``\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, link stiffness ``k_0``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The relative Helmholtz free energy ``\\Delta\\psi\\equiv\\psi(\\xi,T)-\\psi(0,T)`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function relative_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_relative_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The relative Helmholtz free energy per link ``\\Delta\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function relative_helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_relative_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The nondimensional Helmholtz free energy ``N_b\\vartheta=\\beta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + temperature, + ) +end + +""" +The nondimensional Helmholtz free energy per link ``\\vartheta\\equiv\\beta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + temperature, + ) +end + +""" +The nondimensional relative Helmholtz free energy ``N_b\\Delta\\vartheta=\\beta\\Delta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b`` and nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_relative_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_relative_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64), + number_of_links_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + number_of_links, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) +end + +""" +The nondimensional relative Helmholtz free energy per link ``\\Delta\\vartheta\\equiv\\beta\\Delta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + (nondimensional_link_stiffness_i, nondimensional_end_to_end_length_per_link_i) -> + ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_alternative_legendre_nondimensional_relative_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (Float64, Float64), + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) end """ @@ -48,6 +484,76 @@ function EFJC( link_length, hinge_mass, link_stiffness, + (end_to_end_length, temperature) -> force( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> nondimensional_force( + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), + (end_to_end_length, temperature) -> helmholtz_free_energy( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> helmholtz_free_energy_per_link( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> relative_helmholtz_free_energy( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> relative_helmholtz_free_energy_per_link( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_helmholtz_free_energy( + number_of_links, + link_length, + hinge_mass, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_helmholtz_free_energy_per_link( + number_of_links, + link_length, + hinge_mass, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_relative_helmholtz_free_energy( + number_of_links, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_relative_helmholtz_free_energy_per_link( + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), ) end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl index 1a52ca12..6363e25c 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/legendre/test.jl @@ -3,7 +3,8 @@ module Test using Test using Polymers.Physics: BOLTZMANN_CONSTANT using Polymers.Physics.SingleChain: ZERO, parameters -using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative.Legendre: EFJC +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative.Legendre: + EFJC @testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::base::init" begin @test isa( @@ -98,4 +99,648 @@ end end end -end \ No newline at end of file +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::nondimensional::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force = model.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + force = model.force(end_to_end_length, temperature) + residual_abs = + force / BOLTZMANN_CONSTANT / temperature * link_length - nondimensional_force + residual_rel = residual_abs / nondimensional_force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::nondimensional::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy / BOLTZMANN_CONSTANT / temperature - + nondimensional_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_helmholtz_free_energy + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::nondimensional::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy_per_link / BOLTZMANN_CONSTANT / temperature - + nondimensional_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::nondimensional::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy / BOLTZMANN_CONSTANT / temperature - + nondimensional_relative_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::nondimensional::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy_per_link / BOLTZMANN_CONSTANT / temperature - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::per_link::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy / number_of_links - helmholtz_free_energy_per_link + residual_rel = residual_abs / helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::per_link::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy / number_of_links - + relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::per_link::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy / number_of_links - + nondimensional_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::per_link::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy / number_of_links - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::relative::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + helmholtz_free_energy_0 = + model.helmholtz_free_energy(ZERO * number_of_links * link_length, temperature) + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy - helmholtz_free_energy_0 - relative_helmholtz_free_energy + residual_rel = residual_abs / relative_helmholtz_free_energy + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::relative::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + helmholtz_free_energy_per_link_0 = model.helmholtz_free_energy_per_link( + ZERO * number_of_links * link_length, + temperature, + ) + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy_per_link - helmholtz_free_energy_per_link_0 - + relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::relative::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_0 = + model.nondimensional_helmholtz_free_energy(ZERO, temperature) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy - nondimensional_helmholtz_free_energy_0 - + nondimensional_relative_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::relative::nondimensional_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link_0 = + model.nondimensional_helmholtz_free_energy_per_link(ZERO, temperature) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_per_link - + nondimensional_helmholtz_free_energy_per_link_0 - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::zero::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force_0 = model.force(ZERO * number_of_links * link_length, temperature) + @test abs(force_0) <= + 3.1 * ZERO * number_of_links * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::zero::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force_0 = model.nondimensional_force(ZERO, temperature) + @test abs(nondimensional_force_0) <= 3.1 * ZERO + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::zero::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy( + ZERO * number_of_links * link_length, + temperature, + ) + @test abs(relative_helmholtz_free_energy_0) <= + ZERO * number_of_links * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::zero::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + relative_helmholtz_free_energy_per_link_0 = + model.relative_helmholtz_free_energy_per_link( + ZERO * number_of_links * link_length, + temperature, + ) + @test abs(relative_helmholtz_free_energy_per_link_0) <= + ZERO * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::zero::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_0 = + model.nondimensional_relative_helmholtz_free_energy(ZERO, temperature) + @test abs(nondimensional_relative_helmholtz_free_energy_0) <= ZERO * number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::zero::nondimensional_relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_per_link_0 = + model.nondimensional_relative_helmholtz_free_energy_per_link(ZERO, temperature) + @test abs(nondimensional_relative_helmholtz_free_energy_per_link_0) <= ZERO + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::connection::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + force = model.force(end_to_end_length, temperature) + h = parameters.rel_tol * number_of_links * link_length + force_from_derivative = + ( + model.relative_helmholtz_free_energy( + end_to_end_length + 0.5 * h, + temperature, + ) - model.relative_helmholtz_free_energy( + end_to_end_length - 0.5 * h, + temperature, + ) + ) / h + residual_abs = force - force_from_derivative + residual_rel = residual_abs / force + @test abs(residual_rel) <= h + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::legendre::test::connection::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force = model.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + h = parameters.rel_tol + nondimensional_force_from_derivative = + ( + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link + 0.5 * h, + temperature, + ) - model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link - 0.5 * h, + temperature, + ) + ) / h + residual_abs = nondimensional_force - nondimensional_force_from_derivative + residual_rel = residual_abs / nondimensional_force + @test abs(residual_rel) <= h + end +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl index 8ea693a9..5e7cc89b 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/mod.jl @@ -56,4 +56,4 @@ function EFJC( ) end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl index 3ccc5784..a23544ab 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/alternative/test.jl @@ -2,7 +2,8 @@ module Test using Test using Polymers.Physics.SingleChain: parameters -using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative: EFJC +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Alternative: + EFJC @testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::alternative::test::base::init" begin @test isa( @@ -97,4 +98,4 @@ end end end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs index e69de29b..ee4da5be 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/ex.rs @@ -0,0 +1,50 @@ +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_force(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::force(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_force(nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_force(&nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_relative_helmholtz_free_energy(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::relative_helmholtz_free_energy(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_relative_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::relative_helmholtz_free_energy_per_link(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 +{ + super::nondimensional_helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 +{ + super::nondimensional_helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_relative_helmholtz_free_energy(number_of_links: u8, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_relative_helmholtz_free_energy(&number_of_links, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl index b33cdfbf..cb0a0539 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/mod.jl @@ -29,6 +29,442 @@ struct EFJC The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). """ link_stiffness::Float64 + """ + The expected force ``f`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + force::Function + """ + The expected nondimensional force ``\\eta`` as a function of the applied nondimensional end-to-end length per link ``\\gamma``. + """ + nondimensional_force::Function + """ + The Helmholtz free energy ``\\psi`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + helmholtz_free_energy::Function + """ + The Helmholtz free energy per link ``\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + helmholtz_free_energy_per_link::Function + """ + The relative Helmholtz free energy ``\\Delta\\psi\\equiv\\psi(\\xi,T)-\\psi(0,T)`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + relative_helmholtz_free_energy::Function + """ + The relative Helmholtz free energy per link ``\\Delta\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + relative_helmholtz_free_energy_per_link::Function + """ + The nondimensional Helmholtz free energy ``N_b\\vartheta=\\beta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``. + """ + nondimensional_helmholtz_free_energy::Function + """ + The nondimensional Helmholtz free energy per link ``\\vartheta\\equiv\\beta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``. + """ + nondimensional_helmholtz_free_energy_per_link::Function + """ + The nondimensional relative Helmholtz free energy ``N_b\\Delta\\vartheta=\\beta\\Delta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma``. + """ + nondimensional_relative_helmholtz_free_energy::Function + """ + The nondimensional relative Helmholtz free energy per link ``\\Delta\\vartheta\\equiv\\beta\\Delta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` + """ + nondimensional_relative_helmholtz_free_energy_per_link::Function +end + +""" +The expected force as a function ``f`` of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function force( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_force, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The expected nondimensional force as a function ``\\eta`` of the applied nondimensional end-to-end length per link ``\\gamma``, +parameterized by the link length ``\\ell_b`` and nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_force( + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + (nondimensional_link_stiffness_i, nondimensional_end_to_end_length_per_link_i) -> + ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_force, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (Float64, Float64), + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) +end + +""" +The Helmholtz free energy ``\\psi`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, link stiffness ``k_0``, and hinge mass ``m``, + +```math +\\psi(\\xi, T) \\sim \\varphi\\left[f(\\xi, T)\\right] + \\xi f(\\xi, T) \\quad \\text{for } N_b\\gg 1, +``` + +where ``f(\\xi, T)`` is given by the Legendre transformation approximation above. + +$(TYPEDSIGNATURES) +""" +function helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The Helmholtz free energy per link ``\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, link stiffness ``k_0``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The relative Helmholtz free energy ``\\Delta\\psi\\equiv\\psi(\\xi,T)-\\psi(0,T)`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function relative_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_relative_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The relative Helmholtz free energy per link ``\\Delta\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function relative_helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_relative_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The nondimensional Helmholtz free energy ``N_b\\vartheta=\\beta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + temperature, + ) +end + +""" +The nondimensional Helmholtz free energy per link ``\\vartheta\\equiv\\beta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + temperature, + ) +end + +""" +The nondimensional relative Helmholtz free energy ``N_b\\Delta\\vartheta=\\beta\\Delta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b`` and nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_relative_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_relative_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64), + number_of_links_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + number_of_links, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) +end + +""" +The nondimensional relative Helmholtz free energy per link ``\\Delta\\vartheta\\equiv\\beta\\Delta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + (nondimensional_link_stiffness_i, nondimensional_end_to_end_length_per_link_i) -> + ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_legendre_nondimensional_relative_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (Float64, Float64), + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) end """ @@ -48,6 +484,76 @@ function EFJC( link_length, hinge_mass, link_stiffness, + (end_to_end_length, temperature) -> force( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> nondimensional_force( + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), + (end_to_end_length, temperature) -> helmholtz_free_energy( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> helmholtz_free_energy_per_link( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> relative_helmholtz_free_energy( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> relative_helmholtz_free_energy_per_link( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_helmholtz_free_energy( + number_of_links, + link_length, + hinge_mass, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_helmholtz_free_energy_per_link( + number_of_links, + link_length, + hinge_mass, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_relative_helmholtz_free_energy( + number_of_links, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_relative_helmholtz_free_energy_per_link( + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), ) end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl index 8a5741cf..d6ec975c 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/legendre/test.jl @@ -98,4 +98,648 @@ end end end -end \ No newline at end of file +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::nondimensional::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force = model.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + force = model.force(end_to_end_length, temperature) + residual_abs = + force / BOLTZMANN_CONSTANT / temperature * link_length - nondimensional_force + residual_rel = residual_abs / nondimensional_force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::nondimensional::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy / BOLTZMANN_CONSTANT / temperature - + nondimensional_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_helmholtz_free_energy + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::nondimensional::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy_per_link / BOLTZMANN_CONSTANT / temperature - + nondimensional_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::nondimensional::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy / BOLTZMANN_CONSTANT / temperature - + nondimensional_relative_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::nondimensional::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy_per_link / BOLTZMANN_CONSTANT / temperature - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::per_link::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy / number_of_links - helmholtz_free_energy_per_link + residual_rel = residual_abs / helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::per_link::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy / number_of_links - + relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::per_link::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy / number_of_links - + nondimensional_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::per_link::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy / number_of_links - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::relative::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + helmholtz_free_energy_0 = + model.helmholtz_free_energy(ZERO * number_of_links * link_length, temperature) + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy - helmholtz_free_energy_0 - relative_helmholtz_free_energy + residual_rel = residual_abs / relative_helmholtz_free_energy + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::relative::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + helmholtz_free_energy_per_link_0 = model.helmholtz_free_energy_per_link( + ZERO * number_of_links * link_length, + temperature, + ) + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy_per_link - helmholtz_free_energy_per_link_0 - + relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::relative::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_0 = + model.nondimensional_helmholtz_free_energy(ZERO, temperature) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy - nondimensional_helmholtz_free_energy_0 - + nondimensional_relative_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::relative::nondimensional_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link_0 = + model.nondimensional_helmholtz_free_energy_per_link(ZERO, temperature) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_per_link - + nondimensional_helmholtz_free_energy_per_link_0 - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::zero::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force_0 = model.force(ZERO * number_of_links * link_length, temperature) + @test abs(force_0) <= + 3.1 * ZERO * number_of_links * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::zero::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force_0 = model.nondimensional_force(ZERO, temperature) + @test abs(nondimensional_force_0) <= 3.1 * ZERO + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::zero::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy( + ZERO * number_of_links * link_length, + temperature, + ) + @test abs(relative_helmholtz_free_energy_0) <= + ZERO * number_of_links * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::zero::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + relative_helmholtz_free_energy_per_link_0 = + model.relative_helmholtz_free_energy_per_link( + ZERO * number_of_links * link_length, + temperature, + ) + @test abs(relative_helmholtz_free_energy_per_link_0) <= + ZERO * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::zero::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_0 = + model.nondimensional_relative_helmholtz_free_energy(ZERO, temperature) + @test abs(nondimensional_relative_helmholtz_free_energy_0) <= ZERO * number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::zero::nondimensional_relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_per_link_0 = + model.nondimensional_relative_helmholtz_free_energy_per_link(ZERO, temperature) + @test abs(nondimensional_relative_helmholtz_free_energy_per_link_0) <= ZERO + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::connection::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + force = model.force(end_to_end_length, temperature) + h = parameters.rel_tol * number_of_links * link_length + force_from_derivative = + ( + model.relative_helmholtz_free_energy( + end_to_end_length + 0.5 * h, + temperature, + ) - model.relative_helmholtz_free_energy( + end_to_end_length - 0.5 * h, + temperature, + ) + ) / h + residual_abs = force - force_from_derivative + residual_rel = residual_abs / force + @test abs(residual_rel) <= h + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::legendre::test::connection::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force = model.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + h = parameters.rel_tol + nondimensional_force_from_derivative = + ( + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link + 0.5 * h, + temperature, + ) - model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link - 0.5 * h, + temperature, + ) + ) / h + residual_abs = nondimensional_force - nondimensional_force_from_derivative + residual_rel = residual_abs / nondimensional_force + @test abs(residual_rel) <= h + end +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl index a70aea53..1bc6a1fc 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/mod.jl @@ -68,4 +68,4 @@ function EFJC( ) end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs index e69de29b..b82ecbfd 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/ex.rs @@ -0,0 +1,50 @@ +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_force(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::force(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_force(nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_force(&nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_relative_helmholtz_free_energy(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::relative_helmholtz_free_energy(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_relative_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, link_stiffness: f64, end_to_end_length: f64, temperature: f64) -> f64 +{ + super::relative_helmholtz_free_energy_per_link(&number_of_links, &link_length, &link_stiffness, &end_to_end_length, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 +{ + super::nondimensional_helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 +{ + super::nondimensional_helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link, &temperature) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_relative_helmholtz_free_energy(number_of_links: u8, nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_relative_helmholtz_free_energy(&number_of_links, &nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} +#[no_mangle] +pub extern fn physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_relative_helmholtz_free_energy_per_link(nondimensional_link_stiffness: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 +{ + super::nondimensional_relative_helmholtz_free_energy_per_link(&nondimensional_link_stiffness, &nondimensional_end_to_end_length_per_link) +} \ No newline at end of file diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl index 89c72400..04ee06ef 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/mod.jl @@ -29,6 +29,442 @@ struct EFJC The stiffness of each link in the chain ``k_0`` in units of J/(mol⋅nm^2). """ link_stiffness::Float64 + """ + The expected force ``f`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + force::Function + """ + The expected nondimensional force ``\\eta`` as a function of the applied nondimensional end-to-end length per link ``\\gamma``. + """ + nondimensional_force::Function + """ + The Helmholtz free energy ``\\psi`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + helmholtz_free_energy::Function + """ + The Helmholtz free energy per link ``\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + helmholtz_free_energy_per_link::Function + """ + The relative Helmholtz free energy ``\\Delta\\psi\\equiv\\psi(\\xi,T)-\\psi(0,T)`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + relative_helmholtz_free_energy::Function + """ + The relative Helmholtz free energy per link ``\\Delta\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``. + """ + relative_helmholtz_free_energy_per_link::Function + """ + The nondimensional Helmholtz free energy ``N_b\\vartheta=\\beta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``. + """ + nondimensional_helmholtz_free_energy::Function + """ + The nondimensional Helmholtz free energy per link ``\\vartheta\\equiv\\beta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``. + """ + nondimensional_helmholtz_free_energy_per_link::Function + """ + The nondimensional relative Helmholtz free energy ``N_b\\Delta\\vartheta=\\beta\\Delta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma``. + """ + nondimensional_relative_helmholtz_free_energy::Function + """ + The nondimensional relative Helmholtz free energy per link ``\\Delta\\vartheta\\equiv\\beta\\Delta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` + """ + nondimensional_relative_helmholtz_free_energy_per_link::Function +end + +""" +The expected force as a function ``f`` of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function force( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_force, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The expected nondimensional force as a function ``\\eta`` of the applied nondimensional end-to-end length per link ``\\gamma``, +parameterized by the link length ``\\ell_b`` and nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_force( + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + (nondimensional_link_stiffness_i, nondimensional_end_to_end_length_per_link_i) -> + ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_force, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (Float64, Float64), + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) +end + +""" +The Helmholtz free energy ``\\psi`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, link stiffness ``k_0``, and hinge mass ``m``, + +```math +\\psi(\\xi, T) \\sim \\varphi\\left[f(\\xi, T)\\right] + \\xi f(\\xi, T) \\quad \\text{for } N_b\\gg 1, +``` + +where ``f(\\xi, T)`` is given by the Legendre transformation approximation above. + +$(TYPEDSIGNATURES) +""" +function helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The Helmholtz free energy per link ``\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, link stiffness ``k_0``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The relative Helmholtz free energy ``\\Delta\\psi\\equiv\\psi(\\xi,T)-\\psi(0,T)`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function relative_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_relative_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The relative Helmholtz free energy per link ``\\Delta\\psi/N_b`` as a function of the applied end-to-end length ``\\xi`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, and link stiffness ``k_0``. + +$(TYPEDSIGNATURES) +""" +function relative_helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + link_stiffness::Union{Float64,Vector,Matrix,Array}, + end_to_end_length::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_relative_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + link_stiffness_i, + end_to_end_length_i, + temperature_i, + ), + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ) +end + +""" +The nondimensional Helmholtz free energy ``N_b\\vartheta=\\beta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + temperature, + ) +end + +""" +The nondimensional Helmholtz free energy per link ``\\vartheta\\equiv\\beta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b``, link length ``\\ell_b``, nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``, and hinge mass ``m``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_helmholtz_free_energy_per_link( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + link_length::Union{Float64,Vector,Matrix,Array}, + hinge_mass::Union{Float64,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, + temperature::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64, Float64, Float64, Float64), + number_of_links_i, + link_length_i, + hinge_mass_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + temperature_i, + ), + number_of_links, + link_length, + hinge_mass, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + temperature, + ) +end + +""" +The nondimensional relative Helmholtz free energy ``N_b\\Delta\\vartheta=\\beta\\Delta\\psi`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the number of links ``N_b`` and nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_relative_helmholtz_free_energy( + number_of_links::Union{UInt8,Vector,Matrix,Array}, + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + ( + number_of_links_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ) -> ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_relative_helmholtz_free_energy, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (UInt8, Float64, Float64), + number_of_links_i, + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + number_of_links, + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) +end + +""" +The nondimensional relative Helmholtz free energy per link ``\\Delta\\vartheta\\equiv\\beta\\Delta\\psi/N_b`` as a function of the applied nondimensional end-to-end length per link ``\\gamma`` and temperature ``T``, +parameterized by the nondimensional link stiffness ``\\kappa\\equiv\\beta k_0\\ell_b^2``. + +$(TYPEDSIGNATURES) +""" +function nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_link_stiffness::Union{Float64,Vector,Matrix,Array}, + nondimensional_end_to_end_length_per_link::Union{Float64,Vector,Matrix,Array}, +)::Union{Float64,Vector,Matrix,Array} + return broadcast( + (nondimensional_link_stiffness_i, nondimensional_end_to_end_length_per_link_i) -> + ccall( + ( + :physics_single_chain_efjc_thermodynamics_isometric_asymptotic_reduced_legendre_nondimensional_relative_helmholtz_free_energy_per_link, + string(PROJECT_ROOT, "target/debug/libpolymers"), + ), + Float64, + (Float64, Float64), + nondimensional_link_stiffness_i, + nondimensional_end_to_end_length_per_link_i, + ), + nondimensional_link_stiffness, + nondimensional_end_to_end_length_per_link, + ) end """ @@ -48,6 +484,76 @@ function EFJC( link_length, hinge_mass, link_stiffness, + (end_to_end_length, temperature) -> force( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> nondimensional_force( + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), + (end_to_end_length, temperature) -> helmholtz_free_energy( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> helmholtz_free_energy_per_link( + number_of_links, + link_length, + hinge_mass, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> relative_helmholtz_free_energy( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (end_to_end_length, temperature) -> relative_helmholtz_free_energy_per_link( + number_of_links, + link_length, + link_stiffness, + end_to_end_length, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_helmholtz_free_energy( + number_of_links, + link_length, + hinge_mass, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_helmholtz_free_energy_per_link( + number_of_links, + link_length, + hinge_mass, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + temperature, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_relative_helmholtz_free_energy( + number_of_links, + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), + (nondimensional_end_to_end_length_per_link, temperature) -> + nondimensional_relative_helmholtz_free_energy_per_link( + link_stiffness * link_length^2 / BOLTZMANN_CONSTANT / temperature, + nondimensional_end_to_end_length_per_link, + ), ) end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl index a039b32e..6a191a95 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/legendre/test.jl @@ -3,7 +3,8 @@ module Test using Test using Polymers.Physics: BOLTZMANN_CONSTANT using Polymers.Physics.SingleChain: ZERO, parameters -using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Reduced.Legendre: EFJC +using Polymers.Physics.SingleChain.Efjc.Thermodynamics.Isometric.Asymptotic.Reduced.Legendre: + EFJC @testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::base::init" begin @test isa( @@ -98,4 +99,648 @@ end end end -end \ No newline at end of file +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::nondimensional::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force = model.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + force = model.force(end_to_end_length, temperature) + residual_abs = + force / BOLTZMANN_CONSTANT / temperature * link_length - nondimensional_force + residual_rel = residual_abs / nondimensional_force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::nondimensional::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy / BOLTZMANN_CONSTANT / temperature - + nondimensional_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_helmholtz_free_energy + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::nondimensional::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy_per_link / BOLTZMANN_CONSTANT / temperature - + nondimensional_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::nondimensional::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy / BOLTZMANN_CONSTANT / temperature - + nondimensional_relative_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::nondimensional::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy_per_link / BOLTZMANN_CONSTANT / temperature - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::per_link::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy / number_of_links - helmholtz_free_energy_per_link + residual_rel = residual_abs / helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::per_link::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + relative_helmholtz_free_energy / number_of_links - + relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::per_link::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy / number_of_links - + nondimensional_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::per_link::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy / number_of_links - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::relative::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy = model.helmholtz_free_energy(end_to_end_length, temperature) + helmholtz_free_energy_0 = + model.helmholtz_free_energy(ZERO * number_of_links * link_length, temperature) + relative_helmholtz_free_energy = + model.relative_helmholtz_free_energy(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy - helmholtz_free_energy_0 - relative_helmholtz_free_energy + residual_rel = residual_abs / relative_helmholtz_free_energy + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::relative::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + helmholtz_free_energy_per_link = + model.helmholtz_free_energy_per_link(end_to_end_length, temperature) + helmholtz_free_energy_per_link_0 = model.helmholtz_free_energy_per_link( + ZERO * number_of_links * link_length, + temperature, + ) + relative_helmholtz_free_energy_per_link = + model.relative_helmholtz_free_energy_per_link(end_to_end_length, temperature) + residual_abs = + helmholtz_free_energy_per_link - helmholtz_free_energy_per_link_0 - + relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::relative::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy = model.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_0 = + model.nondimensional_helmholtz_free_energy(ZERO, temperature) + nondimensional_relative_helmholtz_free_energy = + model.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy - nondimensional_helmholtz_free_energy_0 - + nondimensional_relative_helmholtz_free_energy + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::relative::nondimensional_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_helmholtz_free_energy_per_link = + model.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link_0 = + model.nondimensional_helmholtz_free_energy_per_link(ZERO, temperature) + nondimensional_relative_helmholtz_free_energy_per_link = + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_per_link - + nondimensional_helmholtz_free_energy_per_link_0 - + nondimensional_relative_helmholtz_free_energy_per_link + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_per_link + @test abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::zero::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force_0 = model.force(ZERO * number_of_links * link_length, temperature) + @test abs(force_0) <= + 3.1 * ZERO * number_of_links * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::zero::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force_0 = model.nondimensional_force(ZERO, temperature) + @test abs(nondimensional_force_0) <= 3.1 * ZERO + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::zero::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy( + ZERO * number_of_links * link_length, + temperature, + ) + @test abs(relative_helmholtz_free_energy_0) <= + ZERO * number_of_links * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::zero::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + relative_helmholtz_free_energy_per_link_0 = + model.relative_helmholtz_free_energy_per_link( + ZERO * number_of_links * link_length, + temperature, + ) + @test abs(relative_helmholtz_free_energy_per_link_0) <= + ZERO * BOLTZMANN_CONSTANT * temperature + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::zero::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_0 = + model.nondimensional_relative_helmholtz_free_energy(ZERO, temperature) + @test abs(nondimensional_relative_helmholtz_free_energy_0) <= ZERO * number_of_links + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::zero::nondimensional_relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_relative_helmholtz_free_energy_per_link_0 = + model.nondimensional_relative_helmholtz_free_energy_per_link(ZERO, temperature) + @test abs(nondimensional_relative_helmholtz_free_energy_per_link_0) <= ZERO + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::connection::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + end_to_end_length = + nondimensional_end_to_end_length_per_link * number_of_links * link_length + force = model.force(end_to_end_length, temperature) + h = parameters.rel_tol * number_of_links * link_length + force_from_derivative = + ( + model.relative_helmholtz_free_energy( + end_to_end_length + 0.5 * h, + temperature, + ) - model.relative_helmholtz_free_energy( + end_to_end_length - 0.5 * h, + temperature, + ) + ) / h + residual_abs = force - force_from_derivative + residual_rel = residual_abs / force + @test abs(residual_rel) <= h + end +end + +@testset "physics::single_chain::efjc::thermodynamics::isometric::asymptotic::reduced::legendre::test::connection::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_end_to_end_length_per_link = + parameters.nondimensional_end_to_end_length_per_link_reference + + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_force = model.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + h = parameters.rel_tol + nondimensional_force_from_derivative = + ( + model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link + 0.5 * h, + temperature, + ) - model.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link - 0.5 * h, + temperature, + ) + ) / h + residual_abs = nondimensional_force - nondimensional_force_from_derivative + residual_rel = residual_abs / nondimensional_force + @test abs(residual_rel) <= h + end +end + +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl index 20961094..28291db2 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/mod.jl @@ -56,4 +56,4 @@ function EFJC( ) end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl index dcc1adc7..e7a9ed2c 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/reduced/test.jl @@ -97,4 +97,4 @@ end end end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl index b13c3ce8..5421e6cc 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/asymptotic/test.jl @@ -97,4 +97,4 @@ end end end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl b/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl index a2f2e101..2bdf730b 100644 --- a/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/isometric/test.jl @@ -97,4 +97,4 @@ end end end -end \ No newline at end of file +end diff --git a/src/physics/single_chain/efjc/thermodynamics/test.jl b/src/physics/single_chain/efjc/thermodynamics/test.jl index 0b049a00..468d8959 100644 --- a/src/physics/single_chain/efjc/thermodynamics/test.jl +++ b/src/physics/single_chain/efjc/thermodynamics/test.jl @@ -1,6 +1,7 @@ module Test using Test +using Polymers.Physics: BOLTZMANN_CONSTANT, PLANCK_CONSTANT using Polymers.Physics.SingleChain: parameters using Polymers.Physics.SingleChain.Efjc.Thermodynamics: EFJC @@ -97,4 +98,1331 @@ end end end +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.end_to_end_length(force, temperature) + force_out = + model.isometric.asymptotic.legendre.force(end_to_end_length, temperature) + residual_abs = force - force_out + residual_rel = residual_abs / force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force_out = model.isometric.asymptotic.legendre.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = nondimensional_force - nondimensional_force_out + residual_rel = residual_abs / nondimensional_force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.end_to_end_length(force, temperature) + helmholtz_free_energy_legendre = + model.isotensional.asymptotic.gibbs_free_energy(force, temperature) + + force * end_to_end_length + helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.legendre.helmholtz_free_energy( + end_to_end_length, + temperature, + ) + residual_abs = + helmholtz_free_energy_legendre - helmholtz_free_energy_legendre_out + + BOLTZMANN_CONSTANT * + temperature * + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) + residual_rel = residual_abs / helmholtz_free_energy_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.end_to_end_length(force, temperature) + end_to_end_length_per_link = + model.isotensional.asymptotic.end_to_end_length_per_link(force, temperature) + helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.gibbs_free_energy_per_link(force, temperature) + + force * end_to_end_length_per_link + helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.legendre.helmholtz_free_energy_per_link( + end_to_end_length, + temperature, + ) + residual_abs = + helmholtz_free_energy_per_link_legendre - + helmholtz_free_energy_per_link_legendre_out + + BOLTZMANN_CONSTANT * + temperature * + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) / number_of_links + residual_rel = residual_abs / helmholtz_free_energy_per_link_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.end_to_end_length(force, temperature) + relative_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.relative_gibbs_free_energy(force, temperature) + + force * end_to_end_length + relative_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.legendre.relative_helmholtz_free_energy( + end_to_end_length, + temperature, + ) + residual_abs = + relative_helmholtz_free_energy_legendre - + relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / relative_helmholtz_free_energy_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.end_to_end_length(force, temperature) + end_to_end_length_per_link = + model.isotensional.asymptotic.end_to_end_length_per_link(force, temperature) + relative_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.relative_gibbs_free_energy_per_link( + force, + temperature, + ) + force * end_to_end_length_per_link + relative_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.legendre.relative_helmholtz_free_energy_per_link( + end_to_end_length, + temperature, + ) + residual_abs = + relative_helmholtz_free_energy_per_link_legendre - + relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length = + model.isotensional.asymptotic.nondimensional_end_to_end_length( + nondimensional_force, + temperature, + ) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.nondimensional_gibbs_free_energy( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length + nondimensional_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.legendre.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_legendre - + nondimensional_helmholtz_free_energy_legendre_out + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::nondimensional_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.nondimensional_gibbs_free_energy_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length_per_link + nondimensional_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.legendre.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_per_link_legendre - + nondimensional_helmholtz_free_energy_per_link_legendre_out + + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) / number_of_links + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length = + model.isotensional.asymptotic.nondimensional_end_to_end_length( + nondimensional_force, + temperature, + ) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.nondimensional_relative_gibbs_free_energy( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length + nondimensional_relative_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.legendre.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy_legendre - + nondimensional_relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic::nondimensional_relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.nondimensional_relative_gibbs_free_energy_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length_per_link + nondimensional_relative_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.legendre.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy_per_link_legendre - + nondimensional_relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = + residual_abs / nondimensional_relative_helmholtz_free_energy_per_link_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.alternative.end_to_end_length(force, temperature) + force_out = model.isometric.asymptotic.alternative.legendre.force( + end_to_end_length, + temperature, + ) + residual_abs = force - force_out + residual_rel = residual_abs / force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force_out = + model.isometric.asymptotic.alternative.legendre.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = nondimensional_force - nondimensional_force_out + residual_rel = residual_abs / nondimensional_force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.alternative.end_to_end_length(force, temperature) + helmholtz_free_energy_legendre = + model.isotensional.asymptotic.alternative.gibbs_free_energy( + force, + temperature, + ) + force * end_to_end_length + helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.alternative.legendre.helmholtz_free_energy( + end_to_end_length, + temperature, + ) + residual_abs = + helmholtz_free_energy_legendre - helmholtz_free_energy_legendre_out + + BOLTZMANN_CONSTANT * + temperature * + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) + residual_rel = residual_abs / helmholtz_free_energy_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.alternative.end_to_end_length(force, temperature) + end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.end_to_end_length_per_link( + force, + temperature, + ) + helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.alternative.gibbs_free_energy_per_link( + force, + temperature, + ) + force * end_to_end_length_per_link + helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.alternative.legendre.helmholtz_free_energy_per_link( + end_to_end_length, + temperature, + ) + residual_abs = + helmholtz_free_energy_per_link_legendre - + helmholtz_free_energy_per_link_legendre_out + + BOLTZMANN_CONSTANT * + temperature * + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) / number_of_links + residual_rel = residual_abs / helmholtz_free_energy_per_link_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.alternative.end_to_end_length(force, temperature) + relative_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.alternative.relative_gibbs_free_energy( + force, + temperature, + ) + force * end_to_end_length + relative_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.alternative.legendre.relative_helmholtz_free_energy( + end_to_end_length, + temperature, + ) + residual_abs = + relative_helmholtz_free_energy_legendre - + relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / relative_helmholtz_free_energy_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.alternative.end_to_end_length(force, temperature) + end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.end_to_end_length_per_link( + force, + temperature, + ) + relative_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.alternative.relative_gibbs_free_energy_per_link( + force, + temperature, + ) + force * end_to_end_length_per_link + relative_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.alternative.legendre.relative_helmholtz_free_energy_per_link( + end_to_end_length, + temperature, + ) + residual_abs = + relative_helmholtz_free_energy_per_link_legendre - + relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length( + nondimensional_force, + temperature, + ) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.alternative.nondimensional_gibbs_free_energy( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length + nondimensional_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.alternative.legendre.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_legendre - + nondimensional_helmholtz_free_energy_legendre_out + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::nondimensional_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.alternative.nondimensional_gibbs_free_energy_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length_per_link + nondimensional_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.alternative.legendre.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_per_link_legendre - + nondimensional_helmholtz_free_energy_per_link_legendre_out + + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) / number_of_links + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length( + nondimensional_force, + temperature, + ) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.alternative.nondimensional_relative_gibbs_free_energy( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length + nondimensional_relative_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.alternative.legendre.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy_legendre - + nondimensional_relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_alternative::nondimensional_relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.alternative.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.alternative.nondimensional_relative_gibbs_free_energy_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length_per_link + nondimensional_relative_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.alternative.legendre.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy_per_link_legendre - + nondimensional_relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = + residual_abs / nondimensional_relative_helmholtz_free_energy_per_link_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.reduced.end_to_end_length(force, temperature) + force_out = model.isometric.asymptotic.reduced.legendre.force( + end_to_end_length, + temperature, + ) + residual_abs = force - force_out + residual_rel = residual_abs / force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::nondimensional_force" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force_out = + model.isometric.asymptotic.reduced.legendre.nondimensional_force( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = nondimensional_force - nondimensional_force_out + residual_rel = residual_abs / nondimensional_force + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.reduced.end_to_end_length(force, temperature) + helmholtz_free_energy_legendre = + model.isotensional.asymptotic.reduced.gibbs_free_energy(force, temperature) + + force * end_to_end_length + helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.reduced.legendre.helmholtz_free_energy( + end_to_end_length, + temperature, + ) + residual_abs = + helmholtz_free_energy_legendre - helmholtz_free_energy_legendre_out + + BOLTZMANN_CONSTANT * + temperature * + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) + residual_rel = residual_abs / helmholtz_free_energy_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.reduced.end_to_end_length(force, temperature) + end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.end_to_end_length_per_link( + force, + temperature, + ) + helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.reduced.gibbs_free_energy_per_link( + force, + temperature, + ) + force * end_to_end_length_per_link + helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.reduced.legendre.helmholtz_free_energy_per_link( + end_to_end_length, + temperature, + ) + residual_abs = + helmholtz_free_energy_per_link_legendre - + helmholtz_free_energy_per_link_legendre_out + + BOLTZMANN_CONSTANT * + temperature * + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) / number_of_links + residual_rel = residual_abs / helmholtz_free_energy_per_link_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.reduced.end_to_end_length(force, temperature) + relative_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.reduced.relative_gibbs_free_energy( + force, + temperature, + ) + force * end_to_end_length + relative_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.reduced.legendre.relative_helmholtz_free_energy( + end_to_end_length, + temperature, + ) + residual_abs = + relative_helmholtz_free_energy_legendre - + relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / relative_helmholtz_free_energy_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + force = nondimensional_force * BOLTZMANN_CONSTANT * temperature / link_length + end_to_end_length = + model.isotensional.asymptotic.reduced.end_to_end_length(force, temperature) + end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.end_to_end_length_per_link( + force, + temperature, + ) + relative_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.reduced.relative_gibbs_free_energy_per_link( + force, + temperature, + ) + force * end_to_end_length_per_link + relative_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.reduced.legendre.relative_helmholtz_free_energy_per_link( + end_to_end_length, + temperature, + ) + residual_abs = + relative_helmholtz_free_energy_per_link_legendre - + relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = residual_abs / relative_helmholtz_free_energy_per_link_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::nondimensional_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length( + nondimensional_force, + temperature, + ) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.reduced.nondimensional_gibbs_free_energy( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length + nondimensional_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.reduced.legendre.nondimensional_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_legendre - + nondimensional_helmholtz_free_energy_legendre_out + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::nondimensional_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.reduced.nondimensional_gibbs_free_energy_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length_per_link + nondimensional_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.reduced.legendre.nondimensional_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_helmholtz_free_energy_per_link_legendre - + nondimensional_helmholtz_free_energy_per_link_legendre_out + + ( + 0.5 * log(2.0 * pi * BOLTZMANN_CONSTANT * temperature / link_stiffness) + + log( + 8.0 * + pi^2 * + hinge_mass * + link_length^2 * + BOLTZMANN_CONSTANT * + temperature / PLANCK_CONSTANT^2, + ) + ) / number_of_links + residual_rel = residual_abs / nondimensional_helmholtz_free_energy_per_link_legendre + @test abs(residual_abs) <= parameters.abs_tol && + abs(residual_rel) <= parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::nondimensional_relative_helmholtz_free_energy" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length( + nondimensional_force, + temperature, + ) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_legendre = + model.isotensional.asymptotic.reduced.nondimensional_relative_gibbs_free_energy( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length + nondimensional_relative_helmholtz_free_energy_legendre_out = + model.isometric.asymptotic.reduced.legendre.nondimensional_relative_helmholtz_free_energy( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy_legendre - + nondimensional_relative_helmholtz_free_energy_legendre_out + residual_rel = residual_abs / nondimensional_relative_helmholtz_free_energy_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + +@testset "physics::single_chain::efjc::thermodynamics::test::legendre_asymptotic_reduced::nondimensional_relative_helmholtz_free_energy_per_link" begin + for _ = 1:parameters.number_of_loops + number_of_links = + rand(parameters.number_of_links_minimum:parameters.number_of_links_maximum) + link_length = + parameters.link_length_reference + parameters.link_length_scale * (0.5 - rand()) + hinge_mass = + parameters.hinge_mass_reference + parameters.hinge_mass_scale * (0.5 - rand()) + link_stiffness = + parameters.link_stiffness_reference + + parameters.link_stiffness_scale * (0.5 - rand()) + model = EFJC(number_of_links, link_length, hinge_mass, link_stiffness) + nondimensional_force = + parameters.nondimensional_force_reference + + parameters.nondimensional_force_scale * (0.5 - rand()) + temperature = + parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) + nondimensional_end_to_end_length_per_link = + model.isotensional.asymptotic.reduced.nondimensional_end_to_end_length_per_link( + nondimensional_force, + temperature, + ) + nondimensional_relative_helmholtz_free_energy_per_link_legendre = + model.isotensional.asymptotic.reduced.nondimensional_relative_gibbs_free_energy_per_link( + nondimensional_force, + temperature, + ) + nondimensional_force * nondimensional_end_to_end_length_per_link + nondimensional_relative_helmholtz_free_energy_per_link_legendre_out = + model.isometric.asymptotic.reduced.legendre.nondimensional_relative_helmholtz_free_energy_per_link( + nondimensional_end_to_end_length_per_link, + temperature, + ) + residual_abs = + nondimensional_relative_helmholtz_free_energy_per_link_legendre - + nondimensional_relative_helmholtz_free_energy_per_link_legendre_out + residual_rel = + residual_abs / nondimensional_relative_helmholtz_free_energy_per_link_legendre + @test abs(residual_rel) <= 3e1 * parameters.rel_tol + end +end + end diff --git a/src/physics/single_chain/fjc/thermodynamics/isometric/legendre/ex.rs b/src/physics/single_chain/fjc/thermodynamics/isometric/legendre/ex.rs index 5a2bfa27..e7549069 100644 --- a/src/physics/single_chain/fjc/thermodynamics/isometric/legendre/ex.rs +++ b/src/physics/single_chain/fjc/thermodynamics/isometric/legendre/ex.rs @@ -11,12 +11,12 @@ pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondime #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, end_to_end_length: f64, temperature: f64) -> f64 { - super::helmholtz_free_energy(&&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) + super::helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, end_to_end_length: f64, temperature: f64) -> f64 { - super::helmholtz_free_energy_per_link(&&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) + super::helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_relative_helmholtz_free_energy(number_of_links: u8, link_length: f64, end_to_end_length: f64, temperature: f64) -> f64 @@ -31,12 +31,12 @@ pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_relativ #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondimensional_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 { - super::nondimensional_helmholtz_free_energy(&&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) + super::nondimensional_helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondimensional_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 { - super::nondimensional_helmholtz_free_energy_per_link(&&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) + super::nondimensional_helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondimensional_relative_helmholtz_free_energy(number_of_links: u8, nondimensional_end_to_end_length_per_link: f64) -> f64 @@ -71,12 +71,12 @@ pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondime #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_gibbs_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, end_to_end_length: f64, temperature: f64) -> f64 { - super::gibbs_free_energy(&&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) + super::gibbs_free_energy(&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_gibbs_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, end_to_end_length: f64, temperature: f64) -> f64 { - super::gibbs_free_energy_per_link(&&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) + super::gibbs_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &end_to_end_length, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_relative_gibbs_free_energy(number_of_links: u8, link_length: f64, end_to_end_length: f64, temperature: f64) -> f64 @@ -91,12 +91,12 @@ pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_relativ #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondimensional_gibbs_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 { - super::nondimensional_gibbs_free_energy(&&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) + super::nondimensional_gibbs_free_energy(&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondimensional_gibbs_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 { - super::nondimensional_gibbs_free_energy_per_link(&&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) + super::nondimensional_gibbs_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &nondimensional_end_to_end_length_per_link, &temperature) } #[no_mangle] pub extern fn physics_single_chain_fjc_thermodynamics_isometric_legendre_nondimensional_relative_gibbs_free_energy(number_of_links: u8, nondimensional_end_to_end_length_per_link: f64) -> f64 diff --git a/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/ex.rs b/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/ex.rs index 5da36d76..05fad10a 100644 --- a/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/ex.rs +++ b/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/ex.rs @@ -11,12 +11,12 @@ pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_nondi #[no_mangle] pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, well_width: f64, end_to_end_length: f64, temperature: f64) -> f64 { - super::helmholtz_free_energy(&&number_of_links, &link_length, &hinge_mass, &well_width, &end_to_end_length, &temperature) + super::helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &well_width, &end_to_end_length, &temperature) } #[no_mangle] pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, well_width: f64, end_to_end_length: f64, temperature: f64) -> f64 { - super::helmholtz_free_energy_per_link(&&number_of_links, &link_length, &hinge_mass, &well_width, &end_to_end_length, &temperature) + super::helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &well_width, &end_to_end_length, &temperature) } #[no_mangle] pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_relative_helmholtz_free_energy(number_of_links: u8, link_length: f64, well_width: f64, end_to_end_length: f64, temperature: f64) -> f64 @@ -31,12 +31,12 @@ pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_relat #[no_mangle] pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_nondimensional_helmholtz_free_energy(number_of_links: u8, link_length: f64, hinge_mass: f64, well_width: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 { - super::nondimensional_helmholtz_free_energy(&&number_of_links, &link_length, &hinge_mass, &well_width, &nondimensional_end_to_end_length_per_link, &temperature) + super::nondimensional_helmholtz_free_energy(&number_of_links, &link_length, &hinge_mass, &well_width, &nondimensional_end_to_end_length_per_link, &temperature) } #[no_mangle] pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_nondimensional_helmholtz_free_energy_per_link(number_of_links: u8, link_length: f64, hinge_mass: f64, well_width: f64, nondimensional_end_to_end_length_per_link: f64, temperature: f64) -> f64 { - super::nondimensional_helmholtz_free_energy_per_link(&&number_of_links, &link_length, &hinge_mass, &well_width, &nondimensional_end_to_end_length_per_link, &temperature) + super::nondimensional_helmholtz_free_energy_per_link(&number_of_links, &link_length, &hinge_mass, &well_width, &nondimensional_end_to_end_length_per_link, &temperature) } #[no_mangle] pub extern fn physics_single_chain_swfjc_thermodynamics_isometric_legendre_nondimensional_relative_helmholtz_free_energy(number_of_links: u8, link_length: f64, well_width: f64, nondimensional_end_to_end_length_per_link: f64) -> f64 diff --git a/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/test.jl b/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/test.jl index 2b252433..8bbe055f 100644 --- a/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/test.jl +++ b/src/physics/single_chain/swfjc/thermodynamics/isometric/legendre/test.jl @@ -810,8 +810,6 @@ end nondimensional_end_to_end_length_per_link = parameters.nondimensional_end_to_end_length_per_link_reference + parameters.nondimensional_end_to_end_length_per_link_scale * (0.5 - rand()) - temperature = - parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand()) nondimensional_force = model.nondimensional_force(nondimensional_end_to_end_length_per_link) h = parameters.rel_tol From f716140fcfaf8b058b1bc0a38adcdb15ce979fee Mon Sep 17 00:00:00 2001 From: mrbuche Date: Thu, 20 Apr 2023 16:59:33 -0600 Subject: [PATCH 11/11] forget test --- Dockerfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1c785a39..e67ea6c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,11 +4,9 @@ WORKDIR / RUN curl https://sh.rustup.rs -sSf | bash -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" COPY . . -RUN cargo test --verbose RUN pip install --no-cache-dir maturin && \ maturin build --all-features && \ - pip install --no-cache-dir target/wheels/*.whl && \ - pytest --verbose . + pip install --no-cache-dir target/wheels/*.whl COPY --from=julia /usr/local/julia/ /opt/julia/ ENV PATH "${PATH}:/opt/julia/bin" -RUN julia -e 'using Pkg; Pkg.develop(path="."); Pkg.build("Polymers"); Pkg.test("Polymers")' +RUN julia -e 'using Pkg; Pkg.develop(path="."); Pkg.build("Polymers")'