use crate::lattice2d::*;
use crate::measurement::Measurement;
use std::thread;
pub struct MonteCarloParams {
pub n_runs: usize, pub flips_to_skip: usize, pub samples_per_run: usize, pub flips_to_skip_between_samples: usize, }
pub trait MonteCarlo {
fn sample_energy_parallel(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>>;
fn sample_energy(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>>;
fn sample_neighbor_correlations_parallel(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>>;
fn sample_neighbor_correlations(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>>;
fn sample_magnetization_parallel(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>>;
fn sample_magnetization(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>>;
}
impl MonteCarlo for Lattice2d {
fn sample_energy(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>> {
let mut energy = vec![vec![0.0; params.samples_per_run]; params.n_runs];
for i in 0..params.n_runs {
self.reset_spins();
self.update_n(params.flips_to_skip);
for j in 0..params.samples_per_run {
self.update_n(params.flips_to_skip_between_samples);
energy[i][j] = self.measure_energy();
}
}
return energy;
}
fn sample_energy_parallel(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>> {
let mut energy = vec![];
let mut fetch_handle = vec![];
for _ in 0..params.n_runs {
let mut lattice_copy = self.clone();
let flips_to_skip = params.flips_to_skip;
let flips_to_skip_between_samples = params.flips_to_skip_between_samples;
let samples_per_run = params.samples_per_run;
fetch_handle.push(thread::spawn(move || -> Vec<f64> {
lattice_copy.update_n(flips_to_skip);
let mut erg_samples = vec![];
for _ in 0..samples_per_run {
lattice_copy.update_n(flips_to_skip_between_samples);
erg_samples.push(lattice_copy.measure_energy());
}
erg_samples
}));
}
for thread in fetch_handle.into_iter() {
energy.push(thread.join().unwrap());
}
return energy;
}
fn sample_neighbor_correlations(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>> {
let mut nn_corr = vec![vec![0.0; params.samples_per_run]; params.n_runs];
for i in 0..params.n_runs {
self.reset_spins();
self.update_n(params.flips_to_skip);
for j in 0..params.samples_per_run {
self.update_n(params.flips_to_skip_between_samples);
nn_corr[i][j] = self.get_dot_spin_neighbours() as f64 / self.n_sites as f64 / 4.0;
}
}
nn_corr
}
fn sample_neighbor_correlations_parallel(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>> {
let mut nn_corr = vec![];
let mut fetch_handle = vec![];
for _ in 0..params.n_runs {
let mut lattice_copy = self.clone();
let flips_to_skip = params.flips_to_skip;
let flips_to_skip_between_samples = params.flips_to_skip_between_samples;
let samples_per_run = params.samples_per_run;
fetch_handle.push(thread::spawn(move || -> Vec<f64> {
lattice_copy.update_n(flips_to_skip);
let mut nn_samples = vec![];
for _ in 0..samples_per_run {
lattice_copy.update_n(flips_to_skip_between_samples);
nn_samples.push(lattice_copy.get_dot_spin_neighbours() as f64 / lattice_copy.n_sites as f64 / 4.0);
}
nn_samples
}));
}
for thread in fetch_handle.into_iter() {
nn_corr.push(thread.join().unwrap());
}
return nn_corr;
}
fn sample_magnetization_parallel(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>> {
let mut fetch_handle = vec![];
for _ in 0..params.n_runs {
let mut lattice_copy = self.clone();
let flips_to_skip = params.flips_to_skip;
let flips_to_skip_between_samples = params.flips_to_skip_between_samples;
let samples_per_run = params.samples_per_run;
fetch_handle.push(thread::spawn(move || -> Vec<f64> {
lattice_copy.update_n(flips_to_skip);
let mut mag_samples = vec![];
for _ in 0..samples_per_run {
lattice_copy.update_n(flips_to_skip_between_samples);
mag_samples.push(lattice_copy.get_dot_spin_neighbours() as f64 / lattice_copy.n_sites as f64 / 4.0);
}
mag_samples
}));
}
let mut magnetization = vec![];
for thread in fetch_handle.into_iter() {
magnetization.push(thread.join().unwrap());
}
return magnetization;
}
fn sample_magnetization(&mut self, params: &MonteCarloParams) -> Vec<Vec<f64>> {
let mut mag_samples = vec![vec![0.0; params.samples_per_run]; params.n_runs];
for i in 0..params.n_runs {
self.reset_spins();
self.update_n(params.flips_to_skip);
for j in 0..params.samples_per_run {
self.update_n(params.flips_to_skip_between_samples);
mag_samples[i][j] = self.get_spin_mean();
}
}
mag_samples
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_sample_energy() {
let params = MonteCarloParams {
n_runs: 5,
flips_to_skip: 1_000, samples_per_run: 10,
flips_to_skip_between_samples: 100,
};
let beta: f64 = 2.4; let mut lattice = Lattice2d::new(
[9, 9],
UpdateRule::Metropolis,
SpinType::SpinHalf,
InitType::Random,
1.0f64, 0.0f64, beta, );
let energy_samples: Vec<Vec<f64>> = lattice.sample_energy(¶ms);
assert_eq!(energy_samples.len(), params.n_runs);
assert_eq!(energy_samples[0].len(), params.samples_per_run);
}
#[test]
fn test_sample_energy_parallel() {
let params = MonteCarloParams {
n_runs: 5,
flips_to_skip: 1_000,
samples_per_run: 10,
flips_to_skip_between_samples: 100,
};
let beta: f64 = 2.4;
let mut lattice = Lattice2d::new(
[9,9],
UpdateRule::Metropolis,
SpinType::SpinHalf,
InitType::Random,
1.0f64, 0.0f64, beta, );
let energy_samples: Vec<Vec<f64>> = lattice.sample_energy_parallel(¶ms);
assert_eq!(energy_samples.len(), params.n_runs);
assert_eq!(energy_samples[0].len(), params.samples_per_run);
}
#[test]
fn test_sample_neighbor_correlations() {
let params = MonteCarloParams {
n_runs: 5,
flips_to_skip: 1_000, samples_per_run: 10,
flips_to_skip_between_samples: 100,
};
let beta: f64 = 2.4; let mut lattice = Lattice2d::new(
[9, 9],
UpdateRule::Metropolis,
SpinType::SpinHalf,
InitType::Random,
1.0f64, 0.1f64, beta, );
let nn_corr: Vec<Vec<f64>> = lattice.sample_neighbor_correlations(¶ms);
assert_eq!(nn_corr.len(), params.n_runs);
assert_eq!(nn_corr[0].len(), params.samples_per_run);
}
#[test]
fn test_neighbor_correlations_parallel() {
let params = MonteCarloParams {
n_runs: 5,
flips_to_skip: 1_000,
samples_per_run: 10,
flips_to_skip_between_samples: 100,
};
let beta: f64 = 2.4;
let mut lattice = Lattice2d::new(
[9,9],
UpdateRule::Metropolis,
SpinType::SpinHalf,
InitType::Random,
1.0f64, 0.0f64, beta, );
let nn_corr: Vec<Vec<f64>> = lattice.sample_neighbor_correlations_parallel(¶ms);
assert_eq!(nn_corr.len(), params.n_runs);
assert_eq!(nn_corr[0].len(), params.samples_per_run);
}
}