ising 0.2.3

Ising simulation and algorithms
Documentation
use rand::rngs::SmallRng;

use crate::{algorithm::Algorithm, lattice::Lattice};

pub struct Simulation {
    rng: SmallRng,
    lattice: Lattice,
    // Cache temperature to only send new temperatures to the algorithm.
    temperature: f64,
    algorithm: Box<dyn Algorithm>,
}

impl Simulation {
    /// Creates a new simulation.
    ///
    /// # Examples
    /// ## Builtin algorithm types
    /// ```
    /// use rand::{rngs::SmallRng, SeedableRng};
    /// use ising::{lattice::Lattice, Simulation, algorithm::AlgorithmType, CRITICAL_TEMPERATURE};
    ///
    /// let side_length = 8;
    /// let mut rng = SmallRng::seed_from_u64(42);
    /// let lattice = Lattice::new(side_length, &mut rng);
    ///
    /// let temperature = CRITICAL_TEMPERATURE;
    /// let algorithm = AlgorithmType::Wolff.new_algorithm(&lattice, temperature);
    ///
    /// let sim = Simulation::new(rng, lattice, temperature, algorithm);
    ///```
    ///
    /// ## Custom algorithm types
    /// You just have to wrap your initialized struct that implements `Algorithm` in a `Box<dyn Algorithm>`.
    ///
    /// See also [`Algorithm`](crate::algorithm::Algorithm) for implementing the trait.
    ///
    /// Lets assume that you did implement Metropolis yourself and that it is not a builtin algorithm:
    /// ```
    /// # use rand::{rngs::SmallRng, SeedableRng};
    /// # use ising::{lattice::Lattice, Simulation, algorithm::AlgorithmType, CRITICAL_TEMPERATURE};
    /// use ising::algorithm::{Algorithm, Metropolis};
    ///
    /// # let side_length = 8;
    /// # let mut rng = SmallRng::seed_from_u64(42);
    /// # let lattice = Lattice::new(side_length, &mut rng);
    /// #
    /// # let temperature = CRITICAL_TEMPERATURE;
    /// let algorithm: Box<dyn Algorithm> = Box::new(Metropolis::new(temperature));
    ///
    /// let sim = Simulation::new(rng, lattice, temperature, algorithm);
    ///```
    #[must_use]
    pub fn new(
        rng: SmallRng,
        lattice: Lattice,
        temperature: f64,
        algorithm: Box<dyn Algorithm>,
    ) -> Self {
        Self {
            rng,
            lattice,
            temperature,
            algorithm,
        }
    }

    /// Sets a new random number generator.
    pub fn set_rng(&mut self, rng: SmallRng) {
        self.rng = rng;
    }

    /// Gets the lattice.
    #[must_use]
    pub const fn lattice(&self) -> &Lattice {
        &self.lattice
    }

    /// Sets a new lattice.
    pub fn set_lattice(&mut self, lattice: Lattice) {
        self.lattice = lattice;
    }

    /// Gets the temperature.
    #[must_use]
    pub const fn temperature(&self) -> f64 {
        self.temperature
    }

    /// Sets a new temperature.
    pub fn set_temperature(&mut self, val: f64) {
        // Only send a new temperature to the algorithm.
        if self.temperature != val {
            self.temperature = val;
            self.algorithm.set_temperature(val);
        }
    }

    /// Sets a new algorithm.
    pub fn set_algorithm(&mut self, algorithm: Box<dyn Algorithm>) {
        self.algorithm = algorithm;
    }

    /// Applies an algorithm step by calling [`Algorithm::step`](crate::algorithm::Algorithm::step).
    pub fn step(&mut self) {
        self.algorithm.step(&mut self.lattice, &mut self.rng);
    }
}