Skip to main content

pairs_scale/
pairs_scale.rs

1//! Cutoff-list probe for the periodic 18 Å cube at a 4 Å cutoff.
2//!
3//! Env: `PAIRS_N` (default 4096), `PAIRS_REPS` (default 5),
4//! `PAIRS_HALF` (default 0), `PAIRS_HINT` (bin edge, or the cutoff).
5//! `PAIRS_SHUFFLE` (a seed) permutes the atoms, so their order no longer follows
6//! their position, as in a snapshot after a run.
7//! `RAYON_NUM_THREADS` is read at startup. The line reports the first
8//! three calls, then the mean of the timed reps after that. Those
9//! timed reps always record the POP3 hierarchy.
10
11use std::time::Instant;
12
13use linkcell::{pairs_within, Cell};
14
15fn env_usize(key: &str, default: usize) -> usize {
16    std::env::var(key)
17        .ok()
18        .and_then(|s| s.parse().ok())
19        .unwrap_or(default)
20}
21
22fn fill(n: usize) -> Vec<[f64; 3]> {
23    let boxl = 18.0;
24    let m = (n as f64).cbrt().ceil() as usize;
25    let mut xyz = Vec::with_capacity(n);
26    let mut count = 0usize;
27    'outer: for iz in 0..m {
28        for iy in 0..m {
29            for ix in 0..m {
30                if count >= n {
31                    break 'outer;
32                }
33                xyz.push([
34                    (ix as f64 + 0.5) * boxl / m as f64,
35                    (iy as f64 + 0.5) * boxl / m as f64,
36                    (iz as f64 + 0.5) * boxl / m as f64,
37                ]);
38                count += 1;
39            }
40        }
41    }
42    xyz
43}
44
45/// Fisher-Yates with an xorshift stream from `seed`.
46fn shuffle(xyz: &mut [[f64; 3]], seed: u64) {
47    let mut s = seed.max(1);
48    for i in (1..xyz.len()).rev() {
49        s ^= s << 13;
50        s ^= s >> 7;
51        s ^= s << 17;
52        xyz.swap(i, (s % (i as u64 + 1)) as usize);
53    }
54}
55
56fn main() {
57    let n = env_usize("PAIRS_N", 4096);
58    let reps = env_usize("PAIRS_REPS", 5).max(1);
59    let half = std::env::var("PAIRS_HALF").ok().as_deref() == Some("1");
60    let hint = std::env::var("PAIRS_HINT")
61        .ok()
62        .and_then(|s| s.parse().ok());
63    let threads = std::env::var("RAYON_NUM_THREADS").unwrap_or_else(|_| "default".to_string());
64    let mut xyz = fill(n);
65    if let Some(seed) = std::env::var("PAIRS_SHUFFLE")
66        .ok()
67        .and_then(|s| s.parse().ok())
68    {
69        shuffle(&mut xyz, seed);
70    }
71    let cell = Cell::ortho(18.0, 18.0, 18.0).expect("box");
72    linkcell::pop_engage();
73    linkcell::pop_prepare();
74    let mut pairs = Vec::new();
75    let mut early = Vec::new();
76    for _ in 0..3 {
77        let t = Instant::now();
78        pairs = pairs_within(&xyz, &cell, 4.0, None, hint, half).expect("pairs");
79        early.push(t.elapsed().as_secs_f64() * 1e3);
80    }
81    linkcell::pop_reset();
82    let t0 = Instant::now();
83    let mut acc = 0usize;
84    for _ in 0..reps {
85        let got = pairs_within(&xyz, &cell, 4.0, None, hint, half).expect("pairs");
86        acc += got.len();
87    }
88    let wall_ns = t0.elapsed().as_nanos() as u64;
89    let ms = wall_ns as f64 / 1e6;
90    println!(
91        "n={} half={} hint={:?} pairs={} cold={:.3} call2={:.3} call3={:.3} reps={} ms_per={:.4} acc={}",
92        xyz.len(),
93        half as u8,
94        hint,
95        pairs.len(),
96        early[0],
97        early[1],
98        early[2],
99        reps,
100        ms / reps as f64,
101        acc
102    );
103    let useful = linkcell::pop_snapshot();
104    let (lb, ce, pe) = linkcell::pop_efficiencies(&useful, wall_ns);
105    let list = useful
106        .iter()
107        .map(|ns| ns.to_string())
108        .collect::<Vec<_>>()
109        .join(",");
110    println!(
111        "pop shape=pairs-{n}-h{} threads={threads} n={n} reps={reps} wall_ns={wall_ns} useful_ns={list} lb={lb:.4} ce={ce:.4} pe={pe:.4}",
112        half as u8
113    );
114}