Skip to content

Commit b54ab60

Browse files
committed
Remove DataOnVertex<T>
1 parent 6a16b6e commit b54ab60

File tree

5 files changed

+33
-60
lines changed

5 files changed

+33
-60
lines changed

scripts/cppm.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ RUST_LOG="Info" cargo run --release -- \
77
scan \
88
-1 cppm-p18.xyz \
99
-2 cppm-p18.xyz \
10-
--rmin 37 --rmax 121 --dr 0.5 \
10+
--rmin 37 --rmax 121 --dr 2.0 \
1111
--top topology.yaml \
1212
--resolution 0.8 \
1313
--cutoff 1000 \

src/icoscan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn do_icoscan(
8181
n_vertices,
8282
n_vertices,
8383
n_total,
84-
table.get_heap_size() as f64 / 1e6
84+
table.get_size() as f64 / f64::powi(1024.0, 2)
8585
);
8686

8787
// Calculate energy of all two-body poses for given mass center separation and dihedral angle

src/icotable.rs

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
// See the license for the specific language governing permissions and
1313
// limitations under the license.
1414

15-
use crate::{
16-
make_icosphere, make_vertices, table::PaddedTable, DataOnVertex, IcoSphere, Vector3, Vertices,
17-
};
15+
use crate::{make_icosphere, make_vertices, table::PaddedTable, IcoSphere, Vector3, Vertex};
1816
use anyhow::Result;
1917
use core::f64::consts::PI;
2018
use get_size::GetSize;
@@ -44,19 +42,28 @@ pub type Face = [u16; 3];
4442
///
4543
/// https://en.wikipedia.org/wiki/Geodesic_polyhedron
4644
/// 12 vertices will always have 5 neighbors; the rest will have 6.
45+
///
46+
/// Vertex positions and neighbor information are available through a shared pointer.
47+
/// To enable concurrent write access, data is wrapped with `OnceLock` which allows
48+
/// setting data only once.
4749
#[derive(Clone, GetSize)]
4850
pub struct IcoTable<T: Clone + GetSize> {
4951
/// Reference counted pointer to vertex positions and neighbours
5052
/// We want only *one* copy of this, hence the ref. counted, thread-safe pointer
51-
#[get_size(size = 3)]
52-
vertices: Arc<OnceLock<Vec<Vertices>>>,
53+
#[get_size(size = 8)]
54+
vertices: Arc<OnceLock<Vec<Vertex>>>,
5355
/// Vertex information (position, data, neighbors)
54-
data: Vec<DataOnVertex<T>>,
56+
#[get_size(size_fn = oncelock_size_helper)]
57+
data: Vec<OnceLock<T>>,
58+
}
59+
60+
fn oncelock_size_helper<T: GetSize>(value: &Vec<OnceLock<T>>) -> usize {
61+
value.get_size() + std::mem::size_of::<T>() * value.len()
5562
}
5663

5764
impl<T: Clone + GetSize> IcoTable<T> {
5865
/// Iterator over vertices `(positions, neighbors)`
59-
pub fn iter_vertices(&self) -> impl Iterator<Item = &Vertices> {
66+
pub fn iter_vertices(&self) -> impl Iterator<Item = &Vertex> {
6067
self.vertices.get().unwrap().iter()
6168
}
6269
/// Get i'th vertex position
@@ -65,7 +72,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
6572
}
6673
/// Get i'th data or `None`` if uninitialized
6774
pub fn get_data(&self, index: usize) -> &OnceLock<T> {
68-
&self.data[index].data
75+
&self.data[index]
6976
}
7077
/// Get i'th neighbors
7178
pub fn get_neighbors(&self, index: usize) -> &[u16] {
@@ -89,12 +96,9 @@ impl<T: Clone + GetSize> IcoTable<T> {
8996
}
9097

9198
/// Generate table based on an existing vertices pointer and optionally set default data
92-
pub fn from_vertices(vertices: Arc<OnceLock<Vec<Vertices>>>, data: Option<T>) -> Self {
99+
pub fn from_vertices(vertices: Arc<OnceLock<Vec<Vertex>>>, data: Option<T>) -> Self {
93100
let num_vertices = vertices.get().unwrap().len();
94-
let data = match data {
95-
Some(data) => DataOnVertex::from(data),
96-
None => DataOnVertex::uninitialized(),
97-
};
101+
let data = data.map(|d| OnceLock::from(d)).unwrap_or(OnceLock::new());
98102
Self {
99103
vertices,
100104
data: vec![data; num_vertices],
@@ -108,7 +112,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
108112
}
109113
Self {
110114
vertices: Arc::new(OnceLock::from(make_vertices(icosphere))),
111-
data: vec![DataOnVertex::uninitialized(); icosphere.raw_points().len()],
115+
data: vec![OnceLock::new(); icosphere.raw_points().len()],
112116
}
113117
}
114118

@@ -138,7 +142,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
138142
/// The function takes the index of the vertex and its position
139143
/// Due to the `OnceLock` wrap, this can be done only once!
140144
pub fn set_vertex_data(&self, f: impl Fn(usize, &Vector3) -> T) -> anyhow::Result<()> {
141-
if self.data.iter().any(|v| v.data.get().is_some()) {
145+
if self.data.iter().any(|v| v.get().is_some()) {
142146
anyhow::bail!("Data already set for some vertices")
143147
}
144148
self.iter().enumerate().try_for_each(|(i, (pos, _, data))| {
@@ -154,14 +158,14 @@ impl<T: Clone + GetSize> IcoTable<T> {
154158
///
155159
/// After this call, `set_vertex_data` can be called again.
156160
pub fn clear_vertex_data(&mut self) {
157-
for vertex in self.data.iter_mut() {
158-
vertex.data = OnceLock::new();
161+
for data in self.data.iter_mut() {
162+
*data = OnceLock::new();
159163
}
160164
}
161165

162166
/// Get data associated with each vertex
163167
pub fn vertex_data(&self) -> impl Iterator<Item = &T> {
164-
self.data.iter().map(|v| v.data.get().unwrap())
168+
self.data.iter().map(|v| v.get().unwrap())
165169
}
166170

167171
/// Transform vertex positions using a function
@@ -173,7 +177,7 @@ impl<T: Clone + GetSize> IcoTable<T> {
173177
.map(|v| {
174178
let pos = f(&v.pos);
175179
let neighbors = v.neighbors.clone();
176-
Vertices { pos, neighbors }
180+
Vertex { pos, neighbors }
177181
})
178182
.collect_vec();
179183
self.vertices = Arc::new(OnceLock::from(new_vertices));
@@ -437,9 +441,9 @@ impl IcoTable<f64> {
437441
pub fn interpolate(&self, point: &Vector3) -> f64 {
438442
let face = self.nearest_face(point);
439443
let bary = self.barycentric(point, &face);
440-
bary[0] * self.data[face[0] as usize].data.get().unwrap()
441-
+ bary[1] * self.data[face[1] as usize].data.get().unwrap()
442-
+ bary[2] * self.data[face[2] as usize].data.get().unwrap()
444+
bary[0] * self.data[face[0] as usize].get().unwrap()
445+
+ bary[1] * self.data[face[1] as usize].get().unwrap()
446+
+ bary[2] * self.data[face[2] as usize].get().unwrap()
443447
}
444448
/// Generate table based on a minimum number of vertices on the subdivided icosaedron
445449
///

src/table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub type PaddedTable2D = PaddedTable<PaddedTable1D>;
2020

2121
/// Periodic and equidistiant table that emulates periodicity by padding edges
2222
#[derive(Debug, Clone, GetSize)]
23-
pub struct PaddedTable<T: Clone> {
23+
pub struct PaddedTable<T: Clone + GetSize> {
2424
/// Minimum key value
2525
min: f64,
2626
/// Maximum key value
@@ -31,7 +31,7 @@ pub struct PaddedTable<T: Clone> {
3131
data: Vec<T>,
3232
}
3333

34-
impl<T: Clone> PaddedTable<T> {
34+
impl<T: Clone + GetSize> PaddedTable<T> {
3535
pub fn new(min: f64, max: f64, step: f64, initial_value: T) -> PaddedTable<T> {
3636
assert!(min < max && step > 0.0);
3737
let n = ((max - min + 2.0 * step) / step + 0.5) as usize;

src/vertex.rs

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ use crate::{IcoSphere, Vector3};
1616
use get_size::GetSize;
1717
use hexasphere::AdjacencyBuilder;
1818
use itertools::Itertools;
19-
use std::sync::OnceLock;
2019

2120
/// Structure for storing vertex positions and neighbors
2221
#[derive(Clone, GetSize, Debug)]
23-
pub struct Vertices {
22+
pub struct Vertex {
2423
/// 3D coordinates of the vertex on a unit sphere
2524
#[get_size(size = 24)]
2625
pub pos: Vector3,
@@ -29,7 +28,7 @@ pub struct Vertices {
2928
}
3029

3130
/// Extract vertices and neightbourlists from an icosphere
32-
pub fn make_vertices(icosphere: &IcoSphere) -> Vec<Vertices> {
31+
pub fn make_vertices(icosphere: &IcoSphere) -> Vec<Vertex> {
3332
let vertex_positions = icosphere
3433
.raw_points()
3534
.iter()
@@ -45,39 +44,9 @@ pub fn make_vertices(icosphere: &IcoSphere) -> Vec<Vertices> {
4544

4645
vertex_positions
4746
.zip(neighbors)
48-
.map(|(pos, neighbors)| Vertices {
47+
.map(|(pos, neighbors)| Vertex {
4948
pos,
5049
neighbors: neighbors.iter().map(|i| *i as u16).collect_vec(),
5150
})
5251
.collect()
5352
}
54-
55-
/// Struct representing data stored at vertices on an icosphere
56-
///
57-
/// Interior mutability of vertex associated data is enabled using `std::sync::OnceLock`.
58-
/// This allows for data to be set once and then read multiple times.
59-
#[derive(Clone, GetSize)]
60-
pub struct DataOnVertex<T: Clone + GetSize> {
61-
/// Data associated with the vertex
62-
#[get_size(size_fn = oncelock_size_helper)]
63-
pub data: OnceLock<T>,
64-
}
65-
66-
fn oncelock_size_helper<T: GetSize>(value: &OnceLock<T>) -> usize {
67-
std::mem::size_of::<OnceLock<T>>() + value.get().map(|v| v.get_heap_size()).unwrap_or(0)
68-
}
69-
70-
impl<T: Clone + GetSize> DataOnVertex<T> {
71-
/// Construct a new vertex where data is *locked* to fixed value
72-
pub fn from(data: T) -> Self {
73-
Self {
74-
data: OnceLock::from(data),
75-
}
76-
}
77-
/// Construct new uninitialized data
78-
pub fn uninitialized() -> Self {
79-
Self {
80-
data: OnceLock::new(),
81-
}
82-
}
83-
}

0 commit comments

Comments
 (0)