use ndarray::prelude::*;
use crate::lattice2d::*;
pub trait Measurement {
fn get_spin_sum(&self) -> i32; fn get_spin_mean(&self) -> f64; fn _convolve_2d_circ_neighbours(mat:&Array2<i32>) -> Array2<i32>; fn get_dot_spin_neighbours(&self) -> i32; fn measure_energy(&self) -> f64; fn measure_energy_per_spin(&self) -> f64; }
impl Measurement for Lattice2d {
fn get_spin_sum(&self) -> i32 {
self.nodes.iter()
.fold(0 , |acc, &x| acc + x)
}
fn get_spin_mean(&self) -> f64 {
self.get_spin_sum() as f64 / (self.n_sites as f64)
}
fn _convolve_2d_circ_neighbours(mat:&Array2<i32>) -> Array2<i32> {
let roll = |ix: usize, amt: i32, max: usize| {
let max = max as i32;
((ix as i32 + amt + max) % max) as usize };
let (width, height) = mat.dim();
Array2::from_shape_fn((width, height), |ix| {
mat[[ix.0,roll(ix.1,1,height)]]
+ mat[[ix.0,roll(ix.1,-1,height)]]
+ mat[[roll(ix.0,1,width),ix.1]]
+ mat[[roll(ix.0,-1,width),ix.1]]
})
}
fn get_dot_spin_neighbours(&self) -> i32 {
let neighbors = Lattice2d::_convolve_2d_circ_neighbours(&self.nodes);
assert_eq!(neighbors.shape() , self.nodes.shape());
let mut dot_spin:i32 = 0;
for (x,y) in self.nodes.iter().zip(neighbors) {
dot_spin += x * y;
}
dot_spin
}
fn measure_energy(&self) -> f64 {
let spin_sum = self.get_spin_sum() as f64; let spin_neighbours_dot = self.get_dot_spin_neighbours() as f64; return - self.j * spin_neighbours_dot - self.h * spin_sum
}
fn measure_energy_per_spin(&self) -> f64 {
self.measure_energy() / self.n_sites as f64
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_spin_mean() {
println!("\n----------------------\nTesting Lattice2d, spin_expected_value");
let mut lattice = Lattice2d::new(
[25,25],
UpdateRule::Metropolis,
SpinType::SpinHalf,
InitType::Random,
1.0, 0.0, 0.5, );
for _ in 0..1 { println!("< Spin > = {}", lattice.get_spin_mean());
for _ in 0..1 { lattice.update();
}
}
}
#[test]
fn test_convolve_2d_circ_neighbours() {
let vec1 = vec![
vec![0,0,0],
vec![0,1,0],
vec![0,0,0],
];
let vec1_conv = vec![ vec![0,1,0],
vec![1,0,1],
vec![0,1,0],
];
let vec2 = vec![
vec![0,0,0,1],
vec![0,0,0,0],
vec![0,0,0,0],
vec![0,0,0,0],
];
let vec2_conv = vec![
vec![1,0,1,0],
vec![0,0,0,1],
vec![0,0,0,0],
vec![0,0,0,1],
];
let mut arr1 = Array2::<i32>::default((3,3));
for (i, mut row) in arr1.axis_iter_mut(Axis(0)).enumerate() {
for (j, col) in row.iter_mut().enumerate() {
*col = vec1[i][j];
}
}
let mut arr2 = Array2::<i32>::default((4,4));
for (i, mut row) in arr2.axis_iter_mut(Axis(0)).enumerate() {
for (j, col) in row.iter_mut().enumerate() {
*col = vec2[i][j];
}
}
let result1 = Lattice2d::_convolve_2d_circ_neighbours(&arr1);
let result2 = Lattice2d::_convolve_2d_circ_neighbours(&arr2);
for i in 0..3 {
for j in 0..3 {
assert_eq!(vec1[i][j] , arr1[[i,j]]); assert_eq!(result1[[i,j]] , vec1_conv[i][j]);
assert_eq!(result2[[i,j]] , vec2_conv[i][j]);
}
}
}
#[test]
fn test_get_dot_spin_neighbours() {
let lattice = Lattice2d::new([2,3],
UpdateRule::Metropolis,
SpinType::SpinHalf,
InitType::AllUp,
1.0, 0.0, 0.5, );
assert_eq!(lattice.get_dot_spin_neighbours() , 6 * 4);
}
}