Skip to main content

XySimulation

Struct XySimulation 

Source
pub struct XySimulation {
    pub lattice: Lattice,
    pub realizations: Vec<XyRealization>,
    pub occupation: Vec<Vec<bool>>,
    pub n_replicas: usize,
    pub n_temps: usize,
    /* private fields */
}
Expand description

A batch of XY disorder realizations on one periodic hypercubic lattice.

use spin_sim::{XyConfig, XySimulation};
use std::sync::atomic::AtomicBool;
let mut xy = XySimulation::new(
    vec![4, 4], vec![vec![1.0; 32]], &[0.8, 1.2], 1, None, 42,
).unwrap();
let result = xy.sample(&XyConfig::default(), &AtomicBool::new(false), &|| {}).unwrap();
assert_eq!(result.values["energies"].len(), 2);

Fields§

§lattice: Lattice§realizations: Vec<XyRealization>§occupation: Vec<Vec<bool>>§n_replicas: usize§n_temps: usize

Implementations§

Source§

impl XySimulation

Source

pub fn new( shape: Vec<usize>, couplings: Vec<Vec<f64>>, temperatures: &[f64], n_replicas: usize, occupation: Option<Vec<Vec<bool>>>, seed: u64, ) -> Result<Self, String>

Examples found in repository?
examples/bench_xy.rs (line 86)
34fn main() {
35    let l = var("PEAPODS_L", 64usize);
36    let dims = var("PEAPODS_DIMS", 2usize);
37    let n_temps = var("PEAPODS_N_TEMPS", 16usize);
38    let n_replicas = var("PEAPODS_N_REPLICAS", 2usize);
39    let n_sweeps = var("PEAPODS_N_SWEEPS", 50usize);
40    let n_realizations = var("PEAPODS_N_REALIZATIONS", 128usize);
41    let sweep_mode = var("PEAPODS_SWEEP_MODE", "metropolis".to_string());
42    let cluster_mode = var("PEAPODS_CLUSTER_MODE", "none".to_string());
43    let overrelaxation_sweeps = var("PEAPODS_OVERRELAXATION", 0usize);
44    let pt_interval = env::var("PEAPODS_PT_INTERVAL")
45        .ok()
46        .map(|v| v.parse::<usize>().expect("PEAPODS_PT_INTERVAL"));
47    let warmup_ratio = var("PEAPODS_WARMUP_RATIO", 0.25f64);
48    let couplings_mode = var("PEAPODS_COUPLINGS", "ferro".to_string());
49    let dilution = var("PEAPODS_DILUTION", 0.0f64);
50    let sequential = env::var_os("PEAPODS_SEQUENTIAL").is_some();
51
52    let shape = vec![l; dims];
53    let n_spins = l.pow(dims as u32);
54    let temperatures: Vec<f64> = (0..n_temps)
55        .map(|i| 0.5 * 4.0f64.powf(i as f64 / (n_temps.max(2) - 1) as f64))
56        .collect();
57    let mut rng = Xoshiro256StarStar::seed_from_u64(0x5eed);
58    let couplings: Vec<Vec<f64>> = (0..n_realizations)
59        .map(|_| {
60            (0..n_spins * dims)
61                .map(|_| match couplings_mode.as_str() {
62                    "ferro" => 1.0,
63                    "bimodal" => {
64                        if rng.gen::<bool>() {
65                            1.0
66                        } else {
67                            -1.0
68                        }
69                    }
70                    "gaussian" => {
71                        // Box-Muller; only the distribution shape matters here.
72                        let (u, v) = (1.0 - rng.gen::<f64>(), rng.gen::<f64>());
73                        (-2.0 * u.ln()).sqrt() * (std::f64::consts::TAU * v).cos()
74                    }
75                    other => panic!("unknown PEAPODS_COUPLINGS '{other}'"),
76                })
77                .collect()
78        })
79        .collect();
80    let occupation = (dilution > 0.0).then(|| {
81        (0..n_realizations)
82            .map(|_| (0..n_spins).map(|_| rng.gen::<f64>() >= dilution).collect())
83            .collect()
84    });
85    let mut simulation =
86        XySimulation::new(shape, couplings, &temperatures, n_replicas, occupation, 42)
87            .expect("invalid XY benchmark configuration");
88
89    let cluster_update = match cluster_mode.as_str() {
90        "none" => None,
91        mode => Some(ClusterConfig {
92            interval: 1,
93            mode: ClusterMode::try_from(mode).expect("PEAPODS_CLUSTER_MODE"),
94            action: ClusterAction::Update,
95            collect_stats: false,
96        }),
97    };
98    let warmup_sweeps = ((n_sweeps as f64 * warmup_ratio).round() as usize).min(n_sweeps - 1);
99    let config = XyConfig {
100        simulation: SimConfig {
101            n_sweeps,
102            warmup_sweeps,
103            sweep_mode: SweepMode::try_from(sweep_mode.as_str()).expect("PEAPODS_SWEEP_MODE"),
104            cluster_update,
105            pt_interval,
106            pt_schedule: PtSchedule::SingleRandomEdge,
107            overlap_cluster: None,
108            autocorrelation_max_lag: None,
109            autocorrelation_backend: AutocorrelationBackend::Ring,
110            sequential,
111            equilibration_diagnostic: false,
112            conditional_link_overlap: true,
113        },
114        cluster_updates: 1,
115        overrelaxation_sweeps,
116        physics: PhysicsOptions::default(),
117        measure_interval: 1,
118    };
119
120    let interrupted = AtomicBool::new(false);
121    let start = Instant::now();
122    let result = match simulation.sample(&config, &interrupted, &|| {}) {
123        Ok(result) => result,
124        Err(error) => {
125            eprintln!("unsupported configuration: {error}");
126            std::process::exit(2);
127        }
128    };
129    let elapsed = start.elapsed();
130    let energy: f64 = result.values["energies"].iter().map(|row| row[0]).sum();
131
132    let mut state_hash = DefaultHasher::new();
133    for realization in &simulation.realizations {
134        for spin in &realization.spins {
135            spin.map(f64::to_bits).hash(&mut state_hash);
136        }
137        realization.system_ids.hash(&mut state_hash);
138        for rng in &realization.rngs {
139            rng.clone().next_u64().hash(&mut state_hash);
140        }
141    }
142    for (name, rows) in &result.values {
143        name.hash(&mut state_hash);
144        for value in rows.iter().flatten() {
145            value.to_bits().hash(&mut state_hash);
146        }
147    }
148    for disorder in &result.per_disorder {
149        for value in disorder.physics.moments.iter().flatten() {
150            value.to_bits().hash(&mut state_hash);
151        }
152        disorder.visited_spins.hash(&mut state_hash);
153    }
154    println!(
155        "L={l} dims={dims} temps={n_temps} replicas={n_replicas} realizations={n_realizations} \
156         sweeps={n_sweeps} warmup={warmup_sweeps} sweep={sweep_mode} cluster={cluster_mode} \
157         overrelaxation={overrelaxation_sweeps} pt={pt_interval:?} couplings={couplings_mode} \
158         dilution={dilution} sequential={sequential} threads={}",
159        rayon::current_num_threads()
160    );
161    println!("mean energy: {:.6}", energy / n_temps as f64);
162    println!("State checksum: {:016x}", state_hash.finish());
163    println!(
164        "{:.3} ms/sweep ({:.3} s total)",
165        elapsed.as_secs_f64() * 1e3 / n_sweeps as f64,
166        elapsed.as_secs_f64()
167    );
168}
Source

pub fn reset(&mut self, seed: Option<u64>)

Source

pub fn sample( &mut self, config: &XyConfig, interrupted: &AtomicBool, on_sweep: &(dyn Fn() + Sync), ) -> Result<XyResult, String>

Examples found in repository?
examples/bench_xy.rs (line 122)
34fn main() {
35    let l = var("PEAPODS_L", 64usize);
36    let dims = var("PEAPODS_DIMS", 2usize);
37    let n_temps = var("PEAPODS_N_TEMPS", 16usize);
38    let n_replicas = var("PEAPODS_N_REPLICAS", 2usize);
39    let n_sweeps = var("PEAPODS_N_SWEEPS", 50usize);
40    let n_realizations = var("PEAPODS_N_REALIZATIONS", 128usize);
41    let sweep_mode = var("PEAPODS_SWEEP_MODE", "metropolis".to_string());
42    let cluster_mode = var("PEAPODS_CLUSTER_MODE", "none".to_string());
43    let overrelaxation_sweeps = var("PEAPODS_OVERRELAXATION", 0usize);
44    let pt_interval = env::var("PEAPODS_PT_INTERVAL")
45        .ok()
46        .map(|v| v.parse::<usize>().expect("PEAPODS_PT_INTERVAL"));
47    let warmup_ratio = var("PEAPODS_WARMUP_RATIO", 0.25f64);
48    let couplings_mode = var("PEAPODS_COUPLINGS", "ferro".to_string());
49    let dilution = var("PEAPODS_DILUTION", 0.0f64);
50    let sequential = env::var_os("PEAPODS_SEQUENTIAL").is_some();
51
52    let shape = vec![l; dims];
53    let n_spins = l.pow(dims as u32);
54    let temperatures: Vec<f64> = (0..n_temps)
55        .map(|i| 0.5 * 4.0f64.powf(i as f64 / (n_temps.max(2) - 1) as f64))
56        .collect();
57    let mut rng = Xoshiro256StarStar::seed_from_u64(0x5eed);
58    let couplings: Vec<Vec<f64>> = (0..n_realizations)
59        .map(|_| {
60            (0..n_spins * dims)
61                .map(|_| match couplings_mode.as_str() {
62                    "ferro" => 1.0,
63                    "bimodal" => {
64                        if rng.gen::<bool>() {
65                            1.0
66                        } else {
67                            -1.0
68                        }
69                    }
70                    "gaussian" => {
71                        // Box-Muller; only the distribution shape matters here.
72                        let (u, v) = (1.0 - rng.gen::<f64>(), rng.gen::<f64>());
73                        (-2.0 * u.ln()).sqrt() * (std::f64::consts::TAU * v).cos()
74                    }
75                    other => panic!("unknown PEAPODS_COUPLINGS '{other}'"),
76                })
77                .collect()
78        })
79        .collect();
80    let occupation = (dilution > 0.0).then(|| {
81        (0..n_realizations)
82            .map(|_| (0..n_spins).map(|_| rng.gen::<f64>() >= dilution).collect())
83            .collect()
84    });
85    let mut simulation =
86        XySimulation::new(shape, couplings, &temperatures, n_replicas, occupation, 42)
87            .expect("invalid XY benchmark configuration");
88
89    let cluster_update = match cluster_mode.as_str() {
90        "none" => None,
91        mode => Some(ClusterConfig {
92            interval: 1,
93            mode: ClusterMode::try_from(mode).expect("PEAPODS_CLUSTER_MODE"),
94            action: ClusterAction::Update,
95            collect_stats: false,
96        }),
97    };
98    let warmup_sweeps = ((n_sweeps as f64 * warmup_ratio).round() as usize).min(n_sweeps - 1);
99    let config = XyConfig {
100        simulation: SimConfig {
101            n_sweeps,
102            warmup_sweeps,
103            sweep_mode: SweepMode::try_from(sweep_mode.as_str()).expect("PEAPODS_SWEEP_MODE"),
104            cluster_update,
105            pt_interval,
106            pt_schedule: PtSchedule::SingleRandomEdge,
107            overlap_cluster: None,
108            autocorrelation_max_lag: None,
109            autocorrelation_backend: AutocorrelationBackend::Ring,
110            sequential,
111            equilibration_diagnostic: false,
112            conditional_link_overlap: true,
113        },
114        cluster_updates: 1,
115        overrelaxation_sweeps,
116        physics: PhysicsOptions::default(),
117        measure_interval: 1,
118    };
119
120    let interrupted = AtomicBool::new(false);
121    let start = Instant::now();
122    let result = match simulation.sample(&config, &interrupted, &|| {}) {
123        Ok(result) => result,
124        Err(error) => {
125            eprintln!("unsupported configuration: {error}");
126            std::process::exit(2);
127        }
128    };
129    let elapsed = start.elapsed();
130    let energy: f64 = result.values["energies"].iter().map(|row| row[0]).sum();
131
132    let mut state_hash = DefaultHasher::new();
133    for realization in &simulation.realizations {
134        for spin in &realization.spins {
135            spin.map(f64::to_bits).hash(&mut state_hash);
136        }
137        realization.system_ids.hash(&mut state_hash);
138        for rng in &realization.rngs {
139            rng.clone().next_u64().hash(&mut state_hash);
140        }
141    }
142    for (name, rows) in &result.values {
143        name.hash(&mut state_hash);
144        for value in rows.iter().flatten() {
145            value.to_bits().hash(&mut state_hash);
146        }
147    }
148    for disorder in &result.per_disorder {
149        for value in disorder.physics.moments.iter().flatten() {
150            value.to_bits().hash(&mut state_hash);
151        }
152        disorder.visited_spins.hash(&mut state_hash);
153    }
154    println!(
155        "L={l} dims={dims} temps={n_temps} replicas={n_replicas} realizations={n_realizations} \
156         sweeps={n_sweeps} warmup={warmup_sweeps} sweep={sweep_mode} cluster={cluster_mode} \
157         overrelaxation={overrelaxation_sweeps} pt={pt_interval:?} couplings={couplings_mode} \
158         dilution={dilution} sequential={sequential} threads={}",
159        rayon::current_num_threads()
160    );
161    println!("mean energy: {:.6}", energy / n_temps as f64);
162    println!("State checksum: {:016x}", state_hash.finish());
163    println!(
164        "{:.3} ms/sweep ({:.3} s total)",
165        elapsed.as_secs_f64() * 1e3 / n_sweeps as f64,
166        elapsed.as_secs_f64()
167    );
168}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V