1use std::time::Instant;
10
11use linkcell::{knearest_into, Cell};
12
13fn env_usize(key: &str, default: usize) -> usize {
14 std::env::var(key)
15 .ok()
16 .and_then(|s| s.parse().ok())
17 .unwrap_or(default)
18}
19
20fn lattice(n: usize, boxl: f64) -> Vec<[f64; 3]> {
21 let nside = ((n as f64).cbrt().ceil() as usize).max(1);
22 let a = boxl / nside as f64;
23 let mut xyz = Vec::with_capacity(n);
24 for i in 0..n {
25 let ix = i % nside;
26 let iy = (i / nside) % nside;
27 let iz = i / (nside * nside);
28 xyz.push([ix as f64 * a, iy as f64 * a, iz as f64 * a]);
29 }
30 xyz
31}
32
33fn frac_grid(cell: &Cell, n: usize) -> Vec<[f64; 3]> {
34 let nside = ((n as f64).cbrt().ceil() as usize).max(1);
35 let mut xyz = Vec::with_capacity(n);
36 for i in 0..n {
37 let ix = i % nside;
38 let iy = (i / nside) % nside;
39 let iz = i / (nside * nside);
40 let s = [
41 (ix as f64 + 0.5) / nside as f64,
42 (iy as f64 + 0.5) / nside as f64,
43 (iz as f64 + 0.5) / nside as f64,
44 ];
45 xyz.push(cell.cartesian(s));
46 }
47 xyz
48}
49
50fn nside_of(n: usize) -> usize {
51 ((n as f64).cbrt().round() as usize).max(1)
52}
53
54fn slab(n: usize) -> (Vec<[f64; 3]>, Cell) {
57 let nside = nside_of(n);
58 let film = nside as f64 * 3.125;
59 let cell = Cell::ortho(film, film, film * 2.0).expect("slab");
60 let mut xyz = Vec::with_capacity(n);
61 for i in 0..n {
62 let ix = i % nside;
63 let iy = (i / nside) % nside;
64 let iz = i / (nside * nside);
65 xyz.push([
66 (ix as f64 + 0.5) / nside as f64 * film,
67 (iy as f64 + 0.5) / nside as f64 * film,
68 (iz as f64 + 0.5) / nside as f64 * film,
69 ]);
70 }
71 (xyz, cell)
72}
73
74fn column(n: usize) -> (Vec<[f64; 3]>, Cell) {
77 let nside = nside_of(n);
78 let side = nside as f64 * 3.125;
79 let cell = Cell::ortho(side, side, side * 4.0).expect("column");
80 let mut xyz = Vec::with_capacity(n);
81 for i in 0..n {
82 let ix = i % nside;
83 let iy = (i / nside) % nside;
84 let iz = i / (nside * nside);
85 xyz.push([
86 (ix as f64 + 0.5) / nside as f64 * side,
87 (iy as f64 + 0.5) / nside as f64 * side,
88 (iz as f64 + 0.5) / nside as f64 * side + side * 1.5,
89 ]);
90 }
91 (xyz, cell)
92}
93
94fn system(shape: &str, n: usize) -> (Vec<[f64; 3]>, Cell) {
95 match shape {
96 "cubic" => {
97 let boxl = 50.0;
98 (
99 lattice(n, boxl),
100 Cell::ortho(boxl, boxl, boxl).expect("box"),
101 )
102 }
103 "slab" => slab(n),
104 "column" => column(n),
105 "hex" => {
106 let cell = Cell::from_vectors(
108 [50.0, 0.0, 0.0],
109 [25.0, 43.30127018922193, 0.0],
110 [0.0, 0.0, 55.55555555555556],
111 [0.0, 0.0, 0.0],
112 )
113 .expect("hex");
114 (frac_grid(&cell, n), cell)
115 }
116 "tilt" => {
117 let s = 2.85;
119 let cell = Cell::from_lammps(
120 -6.2106057 * s,
121 24.8424228 * s,
122 0.0,
123 10.7570846 * s,
124 0.0,
125 20.131291 * s,
126 -6.2106057 * s,
127 0.0,
128 0.0,
129 )
130 .expect("tilt");
131 (frac_grid(&cell, n), cell)
132 }
133 other => panic!("unknown KNN_HOT_SHAPE {other}"),
134 }
135}
136
137fn main() {
138 let n = env_usize("KNN_HOT_N", 4096);
139 let k = env_usize("KNN_HOT_K", 4);
140 let reps = env_usize("KNN_HOT_REPS", 40);
141 let shape = std::env::var("KNN_HOT_SHAPE").unwrap_or_else(|_| "cubic".to_string());
142 let (xyz, cell) = system(&shape, n);
143 let mut out = vec![-1i32; xyz.len() * k];
144 let mut acc = 0i32;
145 let started = Instant::now();
146 for _ in 0..reps {
147 knearest_into(&xyz, &cell, k, None, Some(3.0), &mut out).expect("knearest");
148 acc = acc.wrapping_add(out[0]);
149 }
150 let ms = started.elapsed().as_secs_f64() * 1000.0;
151 std::hint::black_box(acc);
152 eprintln!(
153 "shape={shape} n={} k={} reps={} ms={ms:.1}",
154 xyz.len(),
155 k,
156 reps
157 );
158}