Skip to content
/ SANNpy Public

SANNpy implements the Solid Angle Nearest neighbors (SANN) algorithm for 2D and 3D point clouds

License

Notifications You must be signed in to change notification settings

alptug/SANNpy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

SANNpy

SANNpy implements the Solid Angle Nearest neighbors (SANN) algorithm for 2D and 3D point clouds. It provides:

  • adaptive neighbor discovery driven by a KD-tree backend
  • optional symmetrisation (additive or subtractive) of the neighbor list
  • native support for periodic boundary conditions through box wrapping
  • parallel execution via Numba for high performance on large datasets

The project exposes a single public function, sann, intended for scientific workflows that require robust local coordination analysis (e.g., soft matter, crystallography, point set topology).

Installation

Clone the repository and install the package in editable or standard mode:

pip install .
# or
pip install -e .

SANNpy targets Python 3.10+ and depends on NumPy, SciPy, and Numba. Wheels are not yet published to PyPI; install from source as shown above.

Quick Start

import numpy as np
from SANNpy import sann

# Generate 3D particle coordinates
points = np.random.rand(1_000, 3)

# Compute neighbors with default settings
nnb, neighbors = sann(points)

print(nnb[:5])        # neighbor counts for the first few particles
print(neighbors[0])  # indices of neighbors for particle 0

API Reference

nnb, neighbors = sann(
	points,
	box=None,
	m_init=None,
	flavor="default",
	symmetrize="none",
	n_jobs=-1,
)
  • points (np.ndarray, shape (n_points, dim)): Input coordinates (dim ∈ {2, 3}).
  • box (array_like | None): Periodic box lengths. Supply a length-dim sequence to enable periodic wrapping. Points must lie within [0, box[i]).
  • m_init (int | None): Initial neighbor guess. Defaults to 10 in 2D and 20 in 3D. Larger values may reduce re-querying for dense systems.
  • flavor ("default" | "modified"): Variant of the SANN criterion. The modified flavour applies additional scaling that can assist in low-coordination environments.
  • symmetrize ("none" | "additive" | "subtractive"): Post-process the neighbor list. Additive forms the union of directed edges; subtractive keeps only mutual links.
  • n_jobs (int): Number of threads used by Numba. -1 selects the environment default (typically all available cores).

Returns

  • nnb (np.ndarray): Number of neighbors assigned to each point.
  • neighbors (list[np.ndarray]): Adjacency list containing integer indices for each point’s neighbors.

Use Cases

1. Delaunay-like neighborhoods

dim = 2 # or 3
points = np.random.rand(500, dim)
nnb, neighbors = sann(points)

Default parameters suffice for most point sets.

2. Structures with Periodic Boundary Conditions

box = np.array([1.0, 1.0])
nnb, neighbors = sann(points, box=box)

Set box to enable periodic boundary conditions—useful for molecular simulations or lattice models. Ensure all coordinates are pre-wrapped into the box.

3. Modified Flavour for Low-coordination Systems

nnb, neighbors = sann(points, flavor="modified")

The modified flavour introduces a number-of-neighbors dependent scaling that eliminates overcounting in low-coordination environments. See the accompanying paper for details.

4. Symmetric neighbor Assignment for e.g. Graph Algorithms

nnb, neighbors = sann(points, symmetrize="additive")

# Example: build an undirected NetworkX graph
import networkx as nx
G = nx.Graph()
G.add_nodes_from(range(points.shape[0]))
for idx, row in enumerate(neighbors):
	G.add_edges_from((idx, neighbor) for neighbor in row)

Additive symmetrisation ensures the neighbor graph is bidirectional, suitable for undirected graph analyses. Note: This procedure does not guarantee a planar graph. See the accompanying paper to construct a planar graph/tiling.

5. Conservative neighbor Sets via Subtractive Symmetrisation

nnb, neighbors = sann(points, symmetrize="subtractive")

Use subtractive mode when you require mutual acknowledgement. Note: This procedure does not guarantee a planar graph. See the accompanying paper to construct a planar graph/tiling.

6. Parallel Execution Control

nnb, neighbors = sann(points, n_jobs=8)

Set n_jobs to limit parallelism (useful on shared nodes). The default -1 delegates thread selection to Numba.

Performance Tips

  • For very dense systems, consider increasing m_init to reduce the number of KD-tree re-queries.
  • If SANN fails to converge for some points, a runtime warning is raised and the remaining nodes receive all other points as neighbors.

Development Notes

  • The exported surface is intentionally minimal (only sann). Internal helpers may change without notice.
  • Tests and additional tooling are not bundled; integrate SANNpy within your existing scientific workflow or notebook environment.

Papers to Cite

If SANNpy contributes to your research, please consider citing the paper where this library is introdiced:

@misc{ulugöl2025solid,
      title={Solid-angle based nearest-neighbor algorithm adapted for systems with low coordination number}, 
      author={Alptuğ Ulugöl and Frank Smallenburg and Laura Filion},
      year={2025},
      eprint={2511.10748},
      archivePrefix={arXiv},
      primaryClass={cond-mat.soft},
      url={https://arxiv.org/abs/2511.10748}, 
}

The original 3D SANN is introduced in

@article{vanmeel2012a,
    author = {van Meel, Jacobus A. and Filion, Laura and Valeriani, Chantal and Frenkel, Daan},
    title = {A parameter-free, solid-angle based, nearest-neighbor algorithm},
    journal = {The Journal of Chemical Physics},
    volume = {136},
    number = {23},
    pages = {234107},
    year = {2012},
    month = {06},
    issn = {0021-9606},
    doi = {10.1063/1.4729313},
    url = {https://doi.org/10.1063/1.4729313},
    eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/1.4729313/15451929/234107_1_online.pdf},
}

The 2D SANN is introduced in

@article{mugita2024simple,
    author = {Mugita, Daigo and Souno, Kazuyoshi and Koyama, Hiroaki and Nakamura, Taisei and Isobe, Masaharu},
    title = {Simple and efficient methods for local structural analysis in polydisperse hard disk systems},
    journal = {The Journal of Chemical Physics},
    volume = {160},
    number = {17},
    pages = {174104},
    year = {2024},
    month = {05},
    issn = {0021-9606},
    doi = {10.1063/5.0194873},
    url = {https://doi.org/10.1063/5.0194873},
    eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/5.0194873/19912852/174104_1_5.0194873.pdf},
}

The modified SANN for low coordination systems is introduced in

@misc{ulugöl2025solid,
      title={Solid-angle based nearest-neighbor algorithm adapted for systems with low coordination number}, 
      author={Alptuğ Ulugöl and Frank Smallenburg and Laura Filion},
      year={2025},
      eprint={2511.10748},
      archivePrefix={arXiv},
      primaryClass={cond-mat.soft},
      url={https://arxiv.org/abs/2511.10748}, 
}

License

MIT

About

SANNpy implements the Solid Angle Nearest neighbors (SANN) algorithm for 2D and 3D point clouds

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages