Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cff-version: 1.2.0
title: ' zelll: a fast, framework-free, and flexible implementation of the cell lists algorithm for the Rust programming language'
message: >-
If you use this software, please cite the research article
and a versioned Zenodo DOI if appropriate.
and a versioned Zenodo DOI where appropriate.
type: software
authors:
- given-names: Vincent
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ The latest Python API is documented [here](https://microscopic-image-analysis.gi
use zelll::CellGrid;

let data = vec![[0.0, 0.0, 0.0], [1.0,2.0,0.0], [0.0, 0.1, 0.2]];
let mut cg = CellGrid::new(data.iter().copied(), 1.0);
let mut cg = CellGrid::new(data.iter().copied().enumerate(), 1.0);

for ((i, p), (j, q)) in cg.particle_pairs() {
/* do some work */
}

cg.rebuild_mut(data.iter().copied(), Some(0.5));
cg.rebuild_mut(data.iter().copied().enumerate(), Some(0.5));
```

### Benchmarks
Expand Down
24 changes: 19 additions & 5 deletions benches/cellgrid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use criterion::{
use nalgebra::{Point, Point3, Vector3, distance_squared};
use rand::distributions::Standard;
use rand::prelude::*;
use zelll::CellGrid;
#[cfg(feature = "rayon")]
use zelll::rayon::ParallelIterator;
use zelll::{CellGrid, Particle};

type F32or64 = f64;

Expand Down Expand Up @@ -53,12 +53,26 @@ pub fn bench_cellgrid(c: &mut Criterion) {

let pointcloud = generate_points_random(size, [a, b, c], [0.0, 0.0, 0.0], None);
// pointcloud.sort_unstable_by(|p, q| p.z.partial_cmp(&q.z).unwrap());
let cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let cg = CellGrid::new(
pointcloud
.iter()
.map(|p| p.coords)
.map(Particle::from)
.enumerate(),
cutoff,
);

group.bench_with_input(
BenchmarkId::new("::new()", size),
&pointcloud,
|b, pointcloud| b.iter(|| CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff)),
|b, pointcloud| {
b.iter(|| {
CellGrid::new(
pointcloud.iter().map(|p| p.coords).map(Particle::from),
cutoff,
)
})
},
);

group.bench_with_input(
Expand All @@ -69,7 +83,7 @@ pub fn bench_cellgrid(c: &mut Criterion) {
b.iter(|| {
cg.particle_pairs()
.filter(|&((_i, p), (_j, q))| {
distance_squared(&p.into(), &q.into()) <= cutoff_squared
distance_squared(&(*p).into(), &(*q).into()) <= cutoff_squared
})
.for_each(|_| {});
})
Expand All @@ -84,7 +98,7 @@ pub fn bench_cellgrid(c: &mut Criterion) {
let cutoff_squared = cutoff.powi(2);
b.iter(|| {
cg.par_particle_pairs().for_each(|((_i, p), (_j, q))| {
if distance_squared(&p.into(), &q.into()) <= cutoff_squared {
if distance_squared(&(*p).into(), &(*q).into()) <= cutoff_squared {
} else {
}
});
Expand Down
15 changes: 11 additions & 4 deletions benches/iters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use rand::distributions::Standard;
use rand::prelude::*;
#[cfg(feature = "rayon")]
use rayon::ThreadPoolBuilder;
use zelll::CellGrid;
#[cfg(feature = "rayon")]
use zelll::rayon::ParallelIterator;
use zelll::{CellGrid, Particle};

type F32or64 = f64;

Expand Down Expand Up @@ -56,15 +56,22 @@ pub fn bench_iters(c: &mut Criterion) {

let pointcloud = generate_points_random(size, [a, b, c], [0.0, 0.0, 0.0], None);
// pointcloud.sort_unstable_by(|p, q| p.z.partial_cmp(&q.z).unwrap());
let cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let cg = CellGrid::new(
pointcloud
.iter()
.map(|p| p.coords)
.map(Particle::from)
.enumerate(),
cutoff,
);

#[cfg(not(feature = "rayon"))]
group.bench_with_input(BenchmarkId::new("sequential", size), &cg, |b, cg| {
let cutoff_squared = cutoff.powi(2);
b.iter(|| {
cg.particle_pairs()
.filter(|&((_i, p), (_j, q))| {
distance_squared(&p.into(), &q.into()) <= cutoff_squared
distance_squared(&(*p).into(), &(*q).into()) <= cutoff_squared
})
.for_each(|_| {});
})
Expand All @@ -85,7 +92,7 @@ pub fn bench_iters(c: &mut Criterion) {
b.iter(|| {
pool.install(|| {
cg.par_particle_pairs().for_each(|((_i, p), (_j, q))| {
if distance_squared(&p.into(), &q.into()) <= cutoff_squared {
if distance_squared(&(*p).into(), &(*q).into()) <= cutoff_squared {
} else {
}
})
Expand Down
24 changes: 19 additions & 5 deletions benches/lj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use criterion::{
use nalgebra::{Point, Point3, Vector3, distance_squared};
use rand::distributions::Standard;
use rand::prelude::*;
use zelll::CellGrid;
use zelll::{CellGrid, Particle};

type F32or64 = f64;

Expand Down Expand Up @@ -70,11 +70,18 @@ pub fn bench_lj(c: &mut Criterion) {
// so Massif doesn't keep it in its snapshots the whole time
{
let cutoff_squared = cutoff.powi(2);
let cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let cg = CellGrid::new(
pointcloud
.iter()
.map(|p| p.coords)
.map(Particle::from)
.enumerate(),
cutoff,
);
let potential_energy: F32or64 = cg
.particle_pairs()
.filter_map(|((_i, p), (_j, q))| {
let dsq = distance_squared(&p.into(), &q.into());
let dsq = distance_squared(&(*p).into(), &(*q).into());
if dsq < cutoff_squared {
Some(dsq)
} else {
Expand All @@ -92,11 +99,18 @@ pub fn bench_lj(c: &mut Criterion) {
|b, pointcloud| {
b.iter(|| {
let cutoff_squared = cutoff.powi(2);
let cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let cg = CellGrid::new(
pointcloud
.iter()
.map(|p| p.coords)
.map(Particle::from)
.enumerate(),
cutoff,
);
let _potential_energy: F32or64 = cg
.particle_pairs()
.filter_map(|((_i, p), (_j, q))| {
let dsq = distance_squared(&p.into(), &q.into());
let dsq = distance_squared(&(*p).into(), &(*q).into());
if dsq < cutoff_squared {
Some(dsq)
} else {
Expand Down
12 changes: 9 additions & 3 deletions examples/cachemisses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crabgrind::callgrind as valgrind;
use nalgebra::{Point, Point3, Vector3};
use rand::distributions::Standard;
use rand::prelude::*;
use zelll::CellGrid;
use zelll::{CellGrid, Particle};

type PointCloud<const N: usize> = Vec<Point<f64, N>>;
/// Generate a uniformly random 3D point cloud of size `n` in a cuboid of edge lengths `vol` centered around `origin`.
Expand Down Expand Up @@ -64,13 +64,19 @@ fn main() {

valgrind::start_instrumentation();
for _ in 0..repeat {
let _cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let _cg = CellGrid::new(
pointcloud.iter().map(|p| p.coords).map(Particle::from),
cutoff,
);
}
valgrind::stop_instrumentation();
} else {
valgrind::start_instrumentation();
for _ in 0..repeat {
let _cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let _cg = CellGrid::new(
pointcloud.iter().map(|p| p.coords).map(Particle::from),
cutoff,
);
}
valgrind::stop_instrumentation();
}
Expand Down
19 changes: 15 additions & 4 deletions examples/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rand::prelude::*;
#[cfg(feature = "rayon")]
use rayon::prelude::ParallelIterator;
use std::hint::black_box;
use zelll::CellGrid;
use zelll::{CellGrid, Particle};

type PointCloud<const N: usize> = Vec<Point<f64, N>>;
/// Generate a uniformly random 3D point cloud of size `n` in a cuboid of edge lengths `vol` centered around `origin`.
Expand Down Expand Up @@ -38,21 +38,32 @@ fn main() {
// linear probing in HashMap would help maybe?
//pointcloud.sort_unstable_by(|p, q| p.z.partial_cmp(&q.z).unwrap());

let cg = CellGrid::new(pointcloud.iter().map(|p| p.coords), cutoff);
let cg = CellGrid::new(
pointcloud
.iter()
.map(|p| p.coords)
.map(Particle::from)
.enumerate(),
cutoff,
);
println!("{:?}", cg.info().shape());
let _cutoff_squared = cutoff.powi(2);

//let mut count: usize = 0;
#[cfg(not(feature = "rayon"))]
// let count = cg.point_pairs().count();
cg.particle_pairs()
.filter(|&((_i, p), (_j, q))| distance_squared(&p.into(), &q.into()) <= _cutoff_squared)
.filter(|&((_i, p), (_j, q))| {
distance_squared(&(*p).into(), &(*q).into()) <= _cutoff_squared
})
.for_each(|_| black_box(()));
// cg.rebuild_mut(pointcloud.iter().rev().map(|p| p.coords), None);

#[cfg(feature = "rayon")]
cg.par_particle_pairs()
.filter(|&((_i, p), (_j, q))| distance_squared(&p.into(), &q.into()) <= _cutoff_squared)
.filter(|&((_i, p), (_j, q))| {
distance_squared(&(*p).into(), &(*q).into()) <= _cutoff_squared
})
.for_each(|_| {
//count += 1;
black_box(());
Expand Down
2 changes: 1 addition & 1 deletion python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ crate-type = ["cdylib"]

[dependencies]
bincode = { version = "2.0", features = ["serde"] }
pyo3 = { version = "0.27", features = ["experimental-inspect"] }
pyo3 = { version = "0.28", features = ["experimental-inspect"] }
zelll = { path = "..", features = ["serde"] }
serde = { version = "1.0" }

Expand Down
25 changes: 13 additions & 12 deletions python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use pyo3::types::PyIterator;
use std::iter::Enumerate;

// TODO: While having a borrowing iterator is nice, it's expensive on Python's side
// TODO: (every call to next() is an expensive python function call).
Expand All @@ -17,24 +18,24 @@ struct ParticlesIterable<'a, 'py> {
}

impl<'a, 'py> IntoIterator for ParticlesIterable<'a, 'py> {
type Item = [f64; 3];
type Item = (usize, [f64; 3]);
type IntoIter = ParticlesIterator<'py>;

fn into_iter(self) -> Self::IntoIter {
ParticlesIterator {
// PyO3 also just `unwrap()`s in their specific iterators
iter: self.inner.try_iter().unwrap(),
iter: self.inner.try_iter().unwrap().enumerate(),
}
}
}

#[derive(Clone)]
struct ParticlesIterator<'py> {
iter: Bound<'py, PyIterator>,
iter: Enumerate<Bound<'py, PyIterator>>,
}

impl<'py> Iterator for ParticlesIterator<'py> {
type Item = [f64; 3];
type Item = (usize, [f64; 3]);

fn next(&mut self) -> Option<Self::Item> {
// TODO: document behavior:
Expand All @@ -44,13 +45,13 @@ impl<'py> Iterator for ParticlesIterator<'py> {
// if it's Some, attempt conversion and break loop if it was successful
// otherwise, retry with next element
loop {
match self.iter.next().transpose() {
Ok(Some(p)) => match <[f64; 3] as FromPyObject>::extract(p.as_borrowed()) {
Ok(p) => break Some(p),
match self.iter.next() {
Some((i, Ok(x))) => match <[f64; 3] as FromPyObject>::extract(x.as_borrowed()) {
Ok(p) => break Some((i, p)),
Err(_) => (),
},
Ok(None) => break None,
Err(_) => (),
None => break None,
Some((_, Err(_))) => (),
}
}
}
Expand Down Expand Up @@ -93,9 +94,9 @@ impl<'py> Iterator for ParticlesIterator<'py> {
/// dist = np.linalg.norm(np.array(p) - np.array(q))
/// ```
#[derive(Clone)]
#[pyclass(name = "CellGrid", module = "zelll")]
#[pyclass(name = "CellGrid", module = "zelll", skip_from_py_object)]
pub struct PyCellGrid {
inner: CellGrid<[f64; 3]>,
inner: CellGrid<(usize, [f64; 3])>,
}

#[pymethods]
Expand Down Expand Up @@ -400,7 +401,7 @@ impl PyCellQueryIter {
/// for further technical details and background information.
/// If in doubt, the Rust API docs should be considered the authoritative source for the exact behavior
/// of the library.
#[pymodule(gil_used = false)]
#[pymodule]
pub mod zelll {
#[pymodule_export]
pub use super::{PyCellGrid, PyCellGridIter, PyCellQueryIter};
Expand Down
Loading
Loading