Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

efjc-isometric #214

Merged
merged 1 commit into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ python = ["dep:numpy", "dep:pyo3"]
numpy = {version = "0.19", optional = true}
pyo3 = {version = "0.19", features = ["extension-module"], optional = true}
rand = "0.8.5"
rand_distr = "0.4.3"

3 changes: 3 additions & 0 deletions src/physics/single_chain/efjc/thermodynamics/isometric/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ mod test;
/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble approximated using an asymptotic approach.
pub mod asymptotic;

/// The extensible freely-jointed chain (EFJC) model thermodynamics in the isometric ensemble calculated using Monte Carlo methods.
pub mod monte_carlo;

/// The structure of the thermodynamics of the EFJC model in the isometric ensemble.
pub struct EFJC
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
mod test;

use rand::prelude::*;

use rand_distr::{Normal, Distribution};

use std::f64::consts::TAU as TWO_PI;

pub fn random_configuration<const NUMBER_OF_LINKS: usize>(dist: Normal<f64>, rng: &mut ThreadRng) -> [[f64; 3]; NUMBER_OF_LINKS]
{
let mut lambda: f64 = 0.0;
let mut phi: f64 = 0.0;
let mut theta: f64 = 0.0;
let mut position = [0.0; 3];
let mut configuration = [[0.0; 3]; NUMBER_OF_LINKS];
configuration.iter_mut().for_each(|coordinate|{
lambda = dist.sample(rng);
phi = TWO_PI * rng.gen::<f64>();
theta = (1.0 - 2.0 * rng.gen::<f64>()).acos();
position[0] += lambda * (theta.sin() * phi.cos());
position[1] += lambda * (theta.sin() * phi.sin());
position[2] += lambda * theta.cos();
coordinate.iter_mut().zip(position.iter()).for_each(|(coordinate_i, position_i)|
*coordinate_i = *position_i
);
});
configuration
}

pub fn random_nondimensional_end_to_end_length<const NUMBER_OF_LINKS: usize>(dist: Normal<f64>, rng: &mut ThreadRng) -> f64
{
random_configuration::<NUMBER_OF_LINKS>(dist, rng)[NUMBER_OF_LINKS - 1].iter().map(|entry| entry * entry).sum::<f64>().sqrt()
}

pub fn nondimensional_equilibrium_radial_distribution<const NUMBER_OF_BINS: usize, const NUMBER_OF_LINKS: usize>(gamma_max: &f64, kappa: &f64, number_of_samples: usize) -> ([f64; NUMBER_OF_BINS], [f64; NUMBER_OF_BINS])
{
let mut rng = rand::thread_rng();
let dist = Normal::new(1.0, 1.0/kappa.sqrt()).unwrap();
let number_of_links_f64 = NUMBER_OF_LINKS as f64;
let mut bin_centers = [0.0_f64; NUMBER_OF_BINS];
bin_centers.iter_mut().enumerate().for_each(|(bin_index, bin_center)|
*bin_center = gamma_max * ((bin_index as f64) + 0.5)/(NUMBER_OF_BINS as f64)
);
let mut bin_counts = [0_u128; NUMBER_OF_BINS];
let mut gamma: f64 = 0.0;
(0..number_of_samples).for_each(|_|{
gamma = random_nondimensional_end_to_end_length::<NUMBER_OF_LINKS>(dist, &mut rng)/number_of_links_f64;
for (bin_center, bin_count) in bin_centers.iter().zip(bin_counts.iter_mut())
{
if &gamma < bin_center
{
*bin_count += 1;
break
}
}
});
let normalization = gamma_max * (number_of_samples as f64)/(NUMBER_OF_BINS as f64);
let mut bin_probabilities = [0.0_f64; NUMBER_OF_BINS];
bin_probabilities.iter_mut().zip(bin_counts.iter()).for_each(|(bin_probability, bin_count)|
*bin_probability = (*bin_count as f64)/normalization
);
(bin_centers, bin_probabilities)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#![cfg(test)]

use super::*;

const GAMMA_MAX: f64 = 1.5;
const KAPPA: f64 = 50.0;
const NUMBER_OF_BINS: usize = 100;
const NUMBER_OF_LINKS: usize = 3;
const NUMBER_OF_SAMPLES: usize = 100000;

#[test]
fn monte_carlo_random_configuration()
{
let mut rng = rand::thread_rng();
let dist = Normal::new(1.0, 1.0/KAPPA.sqrt()).unwrap();
let configuration = random_configuration::<NUMBER_OF_LINKS>(dist, &mut rng);
assert_eq!(configuration.len(), NUMBER_OF_LINKS);
assert_eq!(configuration[0].len(), 3);
}

#[test]
fn monte_carlo_random_nondimensional_end_to_end_length()
{
let mut rng = rand::thread_rng();
let dist = Normal::new(1.0, 1.0/KAPPA.sqrt()).unwrap();
let gamma = random_nondimensional_end_to_end_length::<NUMBER_OF_LINKS>(dist, &mut rng)/(NUMBER_OF_LINKS as f64);
assert!(gamma >= 0.0);
}

#[test]
fn monte_carlo_nondimensional_equilibrium_radial_distribution()
{
let (gamma, g_eq) = nondimensional_equilibrium_radial_distribution::<NUMBER_OF_BINS, NUMBER_OF_LINKS>(&GAMMA_MAX, &KAPPA, NUMBER_OF_SAMPLES);
assert_eq!(gamma.len(), NUMBER_OF_BINS);
assert_eq!(g_eq.len(), NUMBER_OF_BINS);
gamma.iter().zip(g_eq.iter()).for_each(|(gamma_i, g_eq_i)|{
assert!(gamma_i > &0.0);
assert!(g_eq_i >= &0.0);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn nondimensional_equilibrium_radial_distribution<const NUMBER_OF_BINS: usiz
let gamma_max = (2.0 - 2.0*(PI - theta).cos()).sqrt()/2.0;
let mut bin_centers = [0.0_f64; NUMBER_OF_BINS];
bin_centers.iter_mut().enumerate().for_each(|(bin_index, bin_center)|
*bin_center = gamma_max*((bin_index as f64) + 0.5)/(NUMBER_OF_BINS as f64)
*bin_center = gamma_max * ((bin_index as f64) + 0.5)/(NUMBER_OF_BINS as f64)
);
let mut bin_counts = [0_u128; NUMBER_OF_BINS];
let mut gamma: f64 = 0.0;
Expand All @@ -75,7 +75,7 @@ pub fn nondimensional_equilibrium_radial_distribution<const NUMBER_OF_BINS: usiz
}
}
});
let normalization = (number_of_samples as f64)/(NUMBER_OF_BINS as f64);
let normalization = gamma_max * (number_of_samples as f64)/(NUMBER_OF_BINS as f64);
let mut bin_probabilities = [0.0_f64; NUMBER_OF_BINS];
bin_probabilities.iter_mut().zip(bin_counts.iter()).for_each(|(bin_probability, bin_count)|
*bin_probability = (*bin_count as f64)/normalization
Expand Down
16 changes: 16 additions & 0 deletions tests/efjc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use polymers::physics::single_chain::efjc::thermodynamics::isometric::monte_carlo::nondimensional_equilibrium_radial_distribution;

const GAMMA_MAX: f64 = 1.5;
const KAPPA: f64 = 50.0;
const NUMBER_OF_BINS: usize = 1000;
const NUMBER_OF_LINKS: usize = 3;
const NUMBER_OF_SAMPLES: usize = 10000000;

#[test]
fn monte_carlo_nondimensional_equilibrium_radial_distribution()
{
let (gamma, g_eq) = nondimensional_equilibrium_radial_distribution::<NUMBER_OF_BINS, NUMBER_OF_LINKS>(&GAMMA_MAX, &KAPPA, NUMBER_OF_SAMPLES);
gamma.iter().zip(g_eq.iter()).for_each(|output|{
println!("{:?}", output)
});
}
2 changes: 1 addition & 1 deletion tests/frc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const KAPPA: f64 = 5.0/11.0;
const NUMBER_OF_BINS: usize = 1000;
const NUMBER_OF_LINKS: usize = 256;
const NUMBER_OF_SAMPLES: usize = 10000000;
const TOL: f64 = 5e-2;
const TOL: f64 = 8e-2;

#[test]
fn monte_carlo_nondimensional_equilibrium_radial_distribution_wlc_limit()
Expand Down
Loading