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

MCMC FJC #209

Merged
merged 5 commits into from
Dec 5, 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
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
- name: checkout
uses: actions/checkout@v4
- name: tree
run: $([[ $(cargo tree --color always --edges normal | wc -l) -eq 1 ]])
run: cargo tree --color always --edges normal
- name: build
run: cargo build --color always --release --verbose
- name: clippy
Expand Down
2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,5 @@ python = ["dep:numpy", "dep:pyo3"]
[dependencies]
numpy = {version = "0.19", optional = true}
pyo3 = {version = "0.19", features = ["extension-module"], optional = true}

[dev-dependencies]
rand = "0.8.5"

4 changes: 4 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def pytest_collection_finish(session):
run(
['sed', '-i', 's@: test@@', '__pycache__/cargo.tests']
)
# remove monte carlo tests
run(
['sed', '-i', '-r', '/monte/d', '__pycache__/cargo.tests']
)
f = open("__pycache__/julia.tests", "w")
run(
['grep', '-r', '@testset', 'src/'],
Expand Down
2 changes: 1 addition & 1 deletion src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn integrate_1d(f: &dyn Fn(&f64) -> f64, x_min: &f64, x_max: &f64, num_point

pub fn integrate_1d_grid(f: &dyn Fn(&f64) -> f64, grid: &[f64], dx: &f64) -> f64
{
grid.iter().map(|x| f(x)).sum::<f64>()*dx
grid.iter().map(f).sum::<f64>()*dx
}

pub fn integrate_2d(f: &dyn Fn(&f64, &f64) -> f64, x_min: &f64, x_max: &f64, y_min: &f64, y_max: &f64, num_points: &u128) -> f64
Expand Down
3 changes: 3 additions & 0 deletions src/physics/single_chain/fjc/thermodynamics/isometric/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ mod test;
/// The freely-jointed chain (FJC) model thermodynamics in the isometric ensemble approximated using a Legendre transformation.
pub mod legendre;

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

use super::
{
treloar_sums,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
mod test;

use rand::prelude::*;

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

pub fn random_configuration<const NUMBER_OF_LINKS: usize>(rng: &mut ThreadRng) -> [[f64; 3]; NUMBER_OF_LINKS]
{
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|{
phi = TWO_PI * rng.gen::<f64>();
theta = (1.0 - 2.0 * rng.gen::<f64>()).acos();
position[0] += theta.sin() * phi.cos();
position[1] += theta.sin() * phi.sin();
position[2] += 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>(rng: &mut ThreadRng) -> f64
{
random_configuration::<NUMBER_OF_LINKS>(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>(number_of_samples: usize) -> ([f64; NUMBER_OF_BINS], [f64; NUMBER_OF_BINS])
{
let mut rng = rand::thread_rng();
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 = ((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>(&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 = (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,38 @@
#![cfg(test)]

use super::*;

const NUMBER_OF_BINS: usize = 100;
const NUMBER_OF_LINKS: usize = 8;
const NUMBER_OF_SAMPLES: usize = 100000;

#[test]
fn monte_carlo_random_configuration()
{
let mut rng = rand::thread_rng();
let configuration = random_configuration::<NUMBER_OF_LINKS>(&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 gamma = random_nondimensional_end_to_end_length::<NUMBER_OF_LINKS>(&mut rng)/(NUMBER_OF_LINKS as f64);
assert!(gamma >= 0.0);
assert!(gamma <= 1.0);
}

#[test]
fn monte_carlo_nondimensional_equilibrium_radial_distribution()
{
let (gamma, g_eq) = nondimensional_equilibrium_radial_distribution::<NUMBER_OF_BINS, NUMBER_OF_LINKS>(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!(gamma_i < &1.0);
assert!(g_eq_i >= &0.0);
});
}
23 changes: 23 additions & 0 deletions tests/fjc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use polymers::physics::single_chain::fjc::thermodynamics::isometric::
{
nondimensional_equilibrium_radial_distribution as check_geq,
monte_carlo::nondimensional_equilibrium_radial_distribution
};

const NUMBER_OF_BINS: usize = 1000;
const NUMBER_OF_LINKS: usize = 8;
const NUMBER_OF_SAMPLES: usize = 10000000;
const TOL: f64 = 5e-2;

#[test]
fn monte_carlo_nondimensional_equilibrium_radial_distribution()
{
let (gamma, g_eq) = nondimensional_equilibrium_radial_distribution::<NUMBER_OF_BINS, NUMBER_OF_LINKS>(NUMBER_OF_SAMPLES);
let mut check = 0.0;
let mut residual = 0.0;
gamma.iter().zip(g_eq.iter()).for_each(|(gamma_i, g_eq_i)|{
check = check_geq(&(NUMBER_OF_LINKS as u8), &gamma_i);
residual = (g_eq_i - &check).abs();
assert!(residual < TOL || residual/check < TOL || g_eq_i < &TOL);
});
}
Loading