# SPDX-FileCopyrightText: Copyright (c) 2025 - 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""JAX neighbor list API.
This module provides JAX bindings for neighbor list computation and related utilities
for both single and batched systems.
"""
from __future__ import annotations
from typing import Any
import jax
import jax.numpy as jnp
from nvalchemiops.jax.neighbors._dispatch import (
_auto_method_from_geometry,
_reject_unsupported_cluster_tile_combo,
estimate_neighbor_list_costs,
suggest_neighbor_list_method,
synthesize_cell_for_cell_list,
)
# Batch cell list functions
from nvalchemiops.jax.neighbors.batch_cell_list import (
batch_build_cell_list,
batch_cell_list,
batch_query_cell_list,
estimate_batch_cell_list_sizes,
)
# Batched cluster-pair tile neighbor list
from nvalchemiops.jax.neighbors.batch_cluster_tile import (
allocate_batch_cluster_tile_list,
batch_build_cluster_tile_list,
batch_cluster_tile_neighbor_list,
batch_query_cluster_tile,
batch_query_cluster_tile_coo,
estimate_batch_cluster_tile_list_sizes,
estimate_batch_cluster_tile_segments,
estimate_batch_max_tiles_per_group,
)
# Batch naive functions
from nvalchemiops.jax.neighbors.batch_naive import (
batch_naive_neighbor_list,
)
# Batch naive dual cutoff functions
from nvalchemiops.jax.neighbors.batch_naive_dual_cutoff import (
batch_naive_neighbor_list_dual_cutoff,
)
# Unbatched cell list functions
from nvalchemiops.jax.neighbors.cell_list import (
build_cell_list,
cell_list,
estimate_cell_list_sizes,
query_cell_list,
)
# Single-system cluster-pair tile neighbor list
from nvalchemiops.jax.neighbors.cluster_tile import (
build_cluster_tile_list,
cluster_tile_neighbor_list,
estimate_cluster_tile_list_sizes,
query_cluster_tile,
query_cluster_tile_coo,
)
# Unbatched naive functions
from nvalchemiops.jax.neighbors.naive import (
naive_neighbor_list,
)
# Unbatched naive dual cutoff functions
from nvalchemiops.jax.neighbors.naive_dual_cutoff import (
naive_neighbor_list_dual_cutoff,
)
# Utility functions
from nvalchemiops.jax.neighbors.neighbor_utils import (
NeighborOverflowError,
TileBufferOverflow,
_validate_dual_cutoff_order,
allocate_cell_list,
compute_naive_num_shifts,
estimate_max_neighbors,
get_fixed_capacity_neighbor_list_from_neighbor_matrix,
get_neighbor_list_from_neighbor_matrix,
prepare_batch_idx_ptr,
)
from nvalchemiops.jax.neighbors.prepared_neighbor_list import (
NeighborListState,
_execute_prepared_neighbor_list,
check_neighbor_list_state,
prepare_neighbor_list,
)
# Rebuild detection
from nvalchemiops.jax.neighbors.rebuild_detection import (
batch_cell_list_needs_rebuild,
batch_neighbor_list_needs_rebuild,
cell_list_needs_rebuild,
check_batch_cell_list_rebuild_needed,
check_batch_neighbor_list_rebuild_needed,
check_cell_list_rebuild_needed,
check_neighbor_list_rebuild_needed,
neighbor_list_needs_rebuild,
)
from nvalchemiops.neighbors.base_dispatch import (
NEIGHBOR_LIST_STRATEGIES,
neighbor_list_strategy_run_args,
)
from nvalchemiops.neighbors.cell_list import compute_batch_pair_centric_n_outer
from nvalchemiops.neighbors.cell_list._grid_selection import _validate_grid_policy
[docs]
def neighbor_list(
positions: jax.Array,
cutoff: float | None = None,
cell: jax.Array | None = None,
pbc: jax.Array | None = None,
batch_idx: jax.Array | None = None,
batch_ptr: jax.Array | None = None,
cutoff2: float | None = None,
half_fill: bool = False,
fill_value: int | None = None,
return_neighbor_list: bool = False,
method: str | None = None,
wrap_positions: bool = True,
*,
grid_policy: str = "configured",
state: NeighborListState | None = None,
**kwargs: Any,
):
"""Compute an eager neighbor list or execute a prepared route.
Without ``state``, this convenience entry point may select an algorithm,
inspect host values, and allocate buffers. That dispatcher is intentionally
eager and is not a supported ``jax.jit`` boundary. With a state returned by
:func:`prepare_neighbor_list`, it executes the resolved route and returns
``(results, next_state)``. Method-specific functions with explicit buffers
and capacities remain the lower-overhead compiled interface.
Parameters
----------
positions : jax.Array, shape (total_atoms, 3)
Concatenated atomic coordinates for all systems in Cartesian space.
Each row represents one atom's (x, y, z) position.
Unwrapped (box-crossing) coordinates are supported when PBC is used;
the kernel wraps positions internally.
cutoff : float, optional
Cutoff distance for neighbor detection in Cartesian units.
Must be positive. Atoms within this distance are considered neighbors.
May be omitted when ``state`` is supplied.
cell : jax.Array, shape (3, 3) or (num_systems, 3, 3), optional
Cell matrix defining the simulation box.
pbc : jax.Array, shape (3,) or (num_systems, 3), dtype=bool, optional
Periodic boundary condition flags for each dimension.
batch_idx : jax.Array, shape (total_atoms,), dtype=jnp.int32, optional
System index for each atom.
batch_ptr : jax.Array, shape (num_systems + 1,), dtype=jnp.int32, optional
Cumulative atom counts defining system boundaries.
cutoff2 : float, optional
Second cutoff distance for neighbor detection in Cartesian units.
Must be positive and greater than or equal to ``cutoff``. Atoms within
this distance are considered neighbors.
half_fill : bool, optional
If True, only store half of the neighbor relationships to avoid double counting.
Another half could be reconstructed by swapping source and target indices and inverting unit shifts.
fill_value : int | None, optional
Value to fill the neighbor matrix with. Default is total_atoms.
return_neighbor_list : bool, optional - default = False
If True, convert the neighbor matrix to a neighbor list (idx_i, idx_j) format by
creating a mask over the fill_value, which can incur a performance penalty.
We recommend using the neighbor matrix format,
and only convert to a neighbor list format if absolutely necessary.
method : str | None, optional
Method to use for neighbor list computation.
Choices: "naive", "cell_list", "cluster_tile", "batch_naive",
"batch_cell_list", "batch_cluster_tile", "naive_dual_cutoff",
"batch_naive_dual_cutoff". If None, a default method is chosen by
comparing estimated work from per-system atom counts and cell (or
bounding-box) volumes and can select cluster-tile when the CUDA,
float32, fully-periodic, contiguous-batch, and output-option guards
allow it. Method names that do not start with ``batch_`` refer to
single-system algorithms. When ``batch_idx`` or ``batch_ptr`` (batch
metadata) is supplied, those explicit method names are treated as aliases
for the corresponding ``batch_*`` methods. For example,
``method="naive"`` is dispatched as ``method="batch_naive"`` when batch
metadata is provided. When only ``batch_idx`` is provided (no
``batch_ptr`` or 3-D ``cell``),
auto-selection computes ``batch_idx.max() + 1`` (and a ``bincount``)
which triggers a device-to-host
synchronization. To avoid this, pass ``batch_ptr``, a 3-D ``cell``
array, or specify ``method`` explicitly.
wrap_positions : bool, default=True
If True, wrap input positions into the primary cell before
neighbor search. Set to False when positions are already
wrapped (e.g. by a preceding integration step) to save two
GPU kernel launches per call. Only applies to naive methods; cell list
methods handle wrapping internally.
grid_policy : {"configured", "adaptive"}, default "configured"
Grid-sizing policy for supported pair-centric cell-list paths.
``"adaptive"`` opts into geometry/population-based grid selection;
``"configured"`` derives cells per axis from cell dimensions and the
cutoff, then applies the configured per-axis minimum and available cell
capacity. Other neighbor methods retain their grid behavior. JAX
adaptive selection is eager-only.
state : NeighborListState, optional
State returned by :func:`prepare_neighbor_list`. Its fixed
configuration takes precedence. Prepared execution accepts positions,
an applicable current cell, selective ``rebuild_flags``, and current
``pair_params`` as runtime inputs and returns ``(results, next_state)``.
A ``NeighborListState`` uses configured grid sizing. Adaptive
``grid_policy`` is available only for eager calls without a
``NeighborListState``.
**kwargs : Any, optional
Additional keyword arguments to pass to the method.
max_neighbors : int, optional
Maximum number of neighbors per atom.
Can be provided to aid in allocation for both naive and cell list methods.
max_neighbors2 : int, optional
Maximum number of neighbors per atom within cutoff2.
Can be provided to aid in allocation for naive dual cutoff method.
max_tiles_per_group : int, optional
Capacity factor for the intermediate tile-pair buffer used by
cluster-tile methods. For ``g`` row groups, the buffer holds
``g * min(g, max_tiles_per_group)`` tile pairs. Increasing the value
up to ``g`` uses more memory and accommodates more candidate tile
pairs. Eager calls estimate the value when it is ``None``.
Transformed or compiled calls require a positive static Python
integer. See :ref:`cluster-tile-buffer-capacity` for sizing details.
neighbor_matrix : jax.Array, optional
Pre-shaped array of shape (num_rows, max_neighbors) for neighbor indices,
where ``num_rows`` is ``total_atoms`` normally and
``len(target_indices)`` for partial lists.
Can be provided to hint buffer reuse to XLA for both naive and cell list methods.
neighbor_matrix_shifts : jax.Array, optional
Pre-shaped array of shape (num_rows, max_neighbors, 3) for shift vectors.
Can be provided to hint buffer reuse to XLA for both naive and cell list methods.
num_neighbors : jax.Array, optional
Pre-shaped array of shape (num_rows,) for neighbor counts.
Can be provided to hint buffer reuse to XLA for both naive and cell list methods.
shift_range_per_dimension : jax.Array, optional
Pre-computed array of shape (1, 3) for shift range in each dimension.
Can be provided to avoid recomputation for naive methods.
num_shifts_per_system : jax.Array, optional
Pre-computed array of shape (num_systems,) for the number of periodic
shifts per system. Can be provided to avoid recomputation for naive methods.
max_shifts_per_system : int, optional
Maximum per-system shift count.
Can be provided to avoid recomputation for naive methods.
cells_per_dimension : jax.Array, optional
Pre-computed array of shape (3,) for number of cells in x, y, z directions.
Can be provided to hint buffer reuse to XLA for cell list construction.
neighbor_search_radius : jax.Array, optional
Pre-computed array of shape (3,) for radius of neighboring cells to search
in each dimension. Can be provided to hint buffer reuse to XLA for cell list construction.
atom_periodic_shifts : jax.Array, optional
Pre-shaped array of shape (total_atoms, 3) for periodic boundary crossings
for each atom. Can be provided to hint buffer reuse to XLA for cell list construction.
atom_to_cell_mapping : jax.Array, optional
Pre-shaped array of shape (total_atoms, 3) for cell coordinates for each atom.
Can be provided to hint buffer reuse to XLA for cell list construction.
atoms_per_cell_count : jax.Array, optional
Pre-shaped array of shape (max_total_cells,) for number of atoms in each cell.
Can be provided to hint buffer reuse to XLA for cell list construction.
cell_atom_start_indices : jax.Array, optional
Pre-shaped array of shape (max_total_cells,) for starting index in
cell_atom_list for each cell. Can be provided to hint buffer reuse to XLA for
cell list construction.
cell_atom_list : jax.Array, optional
Pre-shaped array of shape (total_atoms,) for flattened list of atom
indices organized by cell. Can be provided to hint buffer reuse to XLA for
cell list construction.
max_atoms_per_system : int, optional
Maximum number of atoms per system. Used in batch naive implementation
with PBC for full-row launch sizing. Every compact partial path,
including geometry and pair-output paths, ignores this bound.
Can be provided to avoid CUDA synchronization.
target_indices : jax.Array, optional
Select central atoms for a compact partial neighbor list. Repeated
and empty valid targets are supported. Topology-only naive partial
calls may use CUDA ``method="naive_tile"`` explicitly.
``method="naive"`` lets the direct naive family choose its strategy
automatically; ``method=None`` uses calibrated method selection.
Explicit tile rejects CPU. Distances, vectors, and pair-function
outputs are scalar-only and reject explicit tile. Eager calls reject
out-of-bounds indices; under ``jax.jit`` callers must prevalidate
them.
return_distances : bool, default=False
Also return per-pair distances ``|r_ij|``, differentiable w.r.t.
positions (and cell). Matrix layout is
``(num_rows, max_neighbors)``, where ``num_rows`` is
``total_atoms`` normally and ``len(target_indices)`` for partial
lists; flat COO layout is ``(num_pairs,)``.
return_vectors : bool, default=False
Also return per-pair displacement vectors ``r_ij``, differentiable
w.r.t. positions (and cell). Matrix layout is
``(num_rows, max_neighbors, 3)`` or flat COO ``(num_pairs, 3)``.
rebuild_flags : jax.Array, optional
Boolean flags selecting which systems to re-enumerate; systems whose
flag is ``False`` keep their previous output.
Notes
-----
Cost estimation, automatic dispatch, host-side inspection of capacity
diagnostics, and capacity growth belong outside ``jax.jit``. The direct
compiled boundaries are
:func:`naive_neighbor_list`, :func:`batch_naive_neighbor_list`,
their dual-cutoff variants,
:func:`cell_list`, :func:`batch_cell_list`,
:func:`cluster_tile_neighbor_list`, and
:func:`batch_cluster_tile_neighbor_list`. Their allocation-driving values
must be static, and matrix/segmented outputs require fixed capacity.
Naive scalar and tile strategies support this boundary. Cell-list compiled
calls support atom-centric queries directly. Pair-centric queries require
static launch metadata computed from concrete cell-list sizing outside
``jax.jit``.
``pair_fn`` is supported by the JAX bindings for single-cutoff neighbor
lists. The naive and atom-centric cell-list paths use JAX kernel wrappers,
while tiled paths use ``jax_callable``. Cluster-tile pair outputs are
limited to CUDA float32 eligible systems; compact COO pair outputs on that
path use eager shape compaction. ``target_indices`` is supported by naive and cell-list paths,
including batched naive/cell-list and low-level cell-list query wrappers,
with compact target rows. The ``pair_centric`` strategy and cluster-tile
methods reject ``target_indices``; use ``atom_centric`` for equivalent
filtered cell-list results.
Returns
-------
results : tuple of jax.Array
Variable-length tuple depending on input parameters. The return pattern follows:
**Single cutoff:**
- No PBC, matrix format: ``(neighbor_matrix, num_neighbors)``
- No PBC, list format: ``(neighbor_list, neighbor_ptr)``
- With PBC, matrix format: ``(neighbor_matrix, num_neighbors, neighbor_matrix_shifts)``
- With PBC, list format: ``(neighbor_list, neighbor_ptr, neighbor_list_shifts)``
For naive and cell-list methods, supplying ``coo_capacity`` makes the
list format fixed-capacity and appends
``(num_neighbors, metadata_valid)`` after the topology arrays.
``neighbor_ptr`` describes the stored prefix; ``num_neighbors``
contains the required count for every row when ``metadata_valid`` is
true, and contains ``-1`` otherwise.
**Dual cutoff:**
- No PBC, matrix format: ``(neighbor_matrix1, num_neighbors1, neighbor_matrix2, num_neighbors2)``
- No PBC, list format: ``(neighbor_list1, neighbor_ptr1, neighbor_list2, neighbor_ptr2)``
- With PBC, matrix format: ``(neighbor_matrix1, num_neighbors1, neighbor_matrix_shifts1, neighbor_matrix2, num_neighbors2, neighbor_matrix_shifts2)``
- With PBC, list format: ``(neighbor_list1, neighbor_ptr1, neighbor_list_shifts1, neighbor_list2, neighbor_ptr2, neighbor_list_shifts2)``
For naive dual-cutoff methods with ``coo_capacity``, each cutoff group
appends its own ``(num_neighbors, metadata_valid)`` pair. ``cutoff2``
must be greater than or equal to ``cutoff``.
**Components returned:**
- **neighbor_data** (array): Neighbor indices, format depends on ``return_neighbor_list``:
- If ``return_neighbor_list=False`` (default): Returns ``neighbor_matrix``
with shape (num_rows, max_neighbors), dtype int32, where
``num_rows`` is ``total_atoms`` normally and ``len(target_indices)``
for partial lists. Row ``r`` contains neighbors for atom ``r`` or
``target_indices[r]`` respectively.
- If ``return_neighbor_list=True``: Returns ``neighbor_list`` with shape
(2, num_pairs), dtype int32, in COO format [central_rows, neighbor_atoms].
With ``target_indices``, central rows are compact row ids.
- **num_neighbor_data** (array): Information about the number of neighbors for each atom,
format depends on ``return_neighbor_list``:
- If ``return_neighbor_list=False`` (default): Returns ``num_neighbors`` with shape (num_rows,), dtype int32.
Count of neighbors found for each atom.
- If ``return_neighbor_list=True``: Returns ``neighbor_ptr`` with shape (num_rows + 1,), dtype int32.
CSR-style pointer arrays where ``neighbor_ptr_data[i]`` to ``neighbor_ptr_data[i+1]`` gives the range of
neighbors for row i in the flattened neighbor list.
- **neighbor_shift_data** (array, optional): Periodic shift vectors, only when ``pbc`` is provided:
format depends on ``return_neighbor_list``:
- If ``return_neighbor_list=False`` (default): Returns ``neighbor_matrix_shifts`` with
shape (num_rows, max_neighbors, 3), dtype int32.
- If ``return_neighbor_list=True``: Returns ``unit_shifts`` with shape
(num_pairs, 3), dtype int32.
When ``cutoff2`` is provided, the pattern repeats for the second cutoff with interleaved
components (neighbor_data2, num_neighbor_data2, neighbor_shift_data2) appended to the tuple.
Examples
--------
Single cutoff, matrix format, with PBC::
>>> nm, num, shifts = neighbor_list(pos, 5.0, cell=cell, pbc=pbc)
Single cutoff, list format, no PBC::
>>> nlist, ptr = neighbor_list(pos, 5.0, return_neighbor_list=True)
Dual cutoff, matrix format, with PBC::
>>> nm1, num1, sh1, nm2, num2, sh2 = neighbor_list(
... pos, 2.5, cutoff2=5.0, cell=cell, pbc=pbc
... )
See Also
--------
naive_neighbor_list : Direct access to naive :math:`O(N^2)` algorithm
cell_list : Direct access to cell list :math:`O(N)` algorithm
cluster_tile_neighbor_list : Direct access to cluster-pair tile algorithm
batch_naive_neighbor_list : Batched naive algorithm
batch_cell_list : Batched cell list algorithm
batch_cluster_tile_neighbor_list : Batched cluster-pair tile algorithm
prepare_neighbor_list : Prepare managed repeated execution
check_neighbor_list_state : Report sticky prepared-state failures
"""
_validate_grid_policy(grid_policy)
if state is not None:
if grid_policy == "adaptive":
raise ValueError(
"grid_policy='adaptive' is not supported with NeighborListState; "
"NeighborListState uses configured grid sizing"
)
return _execute_prepared_neighbor_list(positions, cell, state, kwargs=kwargs)
if cutoff is None:
raise ValueError("cutoff is required when state is not provided")
if batch_ptr is not None and batch_ptr.shape[0] < 2:
raise ValueError("batch_ptr must have length at least 2")
if cutoff2 is not None:
_validate_dual_cutoff_order(cutoff, cutoff2, cutoff1_name="cutoff")
use_pair_fn_option = bool(kwargs.pop("use_pair_fn", False))
selected_atom_centric_path = str(kwargs.pop("atom_centric_path", "auto"))
target_indices = kwargs.get("target_indices")
return_vectors = bool(kwargs.get("return_vectors", False))
return_distances = bool(kwargs.get("return_distances", False))
use_pair_fn = (
use_pair_fn_option
or kwargs.get("pair_fn") is not None
or kwargs.get("pair_params") is not None
or kwargs.get("pair_energies") is not None
or kwargs.get("pair_forces") is not None
)
rebuild_flags = kwargs.get("rebuild_flags")
selected_naive_strategy = "auto"
selected_cell_strategy = "auto"
explicit_pair_centric = False
def _apply_auto_suboptions(
naive_strategy: str, cell_strategy: str, path: str
) -> None:
nonlocal selected_naive_strategy, selected_cell_strategy
nonlocal selected_atom_centric_path
if selected_naive_strategy == "auto" and naive_strategy != "auto":
selected_naive_strategy = naive_strategy
if selected_cell_strategy == "auto" and cell_strategy != "auto":
selected_cell_strategy = cell_strategy
if selected_atom_centric_path == "auto" and path != "auto":
selected_atom_centric_path = path
if method is None:
total_atoms = positions.shape[0]
has_batch_inputs = batch_idx is not None or batch_ptr is not None
num_systems = 1
if has_batch_inputs:
batch_idx, batch_ptr = prepare_batch_idx_ptr(
batch_idx, batch_ptr, total_atoms
)
num_systems = batch_ptr.shape[0] - 1
elif cell is not None and cell.ndim == 3:
num_systems = cell.shape[0]
strategy_name = _auto_method_from_geometry(
positions,
max(
float(cutoff), float(cutoff2) if cutoff2 is not None else float(cutoff)
),
cell,
pbc,
batch_idx if has_batch_inputs else None,
batch_ptr if has_batch_inputs else None,
num_systems,
cutoff2=cutoff2,
half_fill=half_fill,
return_neighbor_list=return_neighbor_list,
target_indices=target_indices,
return_vectors=return_vectors,
return_distances=return_distances,
use_pair_fn=use_pair_fn,
rebuild_flags=rebuild_flags,
wrap_positions=wrap_positions,
)
method, auto_native, auto_cell, auto_path = neighbor_list_strategy_run_args(
strategy_name
)
if total_atoms == 0:
# The JAX cell-list path cannot size a 0-atom grid; the naive
# family returns correctly-shaped empty outputs for any format.
method = "naive_dual_cutoff" if cutoff2 is not None else "naive"
elif cutoff2 is not None and method in ("naive", "cell_list"):
method = "naive_dual_cutoff"
elif method == "cell_list" and cell is None:
positions, cell, pbc = synthesize_cell_for_cell_list(
positions,
cutoff,
batch_idx=batch_idx if has_batch_inputs else None,
batch_ptr=batch_ptr if has_batch_inputs else None,
num_systems=num_systems,
)
_apply_auto_suboptions(auto_native, auto_cell, auto_path)
if has_batch_inputs:
method = "batch_" + method
else:
if batch_idx is not None or batch_ptr is not None:
# Route explicit single-system method names through the matching
# batch method when batch metadata is provided.
if not method.startswith("batch_"):
method = "batch_" + method
base = method[len("batch_") :] if method.startswith("batch_") else method
if base in NEIGHBOR_LIST_STRATEGIES:
# Fine-grained strategy name (e.g. from suggest/report): decompose to
# the base method plus its sub-options, honoring the batch_ prefix.
method, fg_native, fg_cell, fg_path = neighbor_list_strategy_run_args(
method
)
_apply_auto_suboptions(fg_native, fg_cell, fg_path)
if fg_cell == "pair_centric":
explicit_pair_centric = True
if (
half_fill
and selected_cell_strategy == "pair_centric"
and not explicit_pair_centric
):
selected_cell_strategy = "atom_centric"
match method:
case "naive":
return naive_neighbor_list(
positions,
cutoff,
pbc=pbc,
cell=cell,
half_fill=half_fill,
fill_value=fill_value,
return_neighbor_list=return_neighbor_list,
wrap_positions=wrap_positions,
strategy=selected_naive_strategy,
**kwargs,
)
case "cell_list":
if cell is None:
positions, cell, pbc = synthesize_cell_for_cell_list(
positions, cutoff, num_systems=1
)
return cell_list(
positions,
cutoff,
cell,
pbc,
half_fill=half_fill,
fill_value=fill_value,
return_neighbor_list=return_neighbor_list,
strategy=selected_cell_strategy,
grid_policy=grid_policy,
atom_centric_path=selected_atom_centric_path,
**kwargs,
)
case "batch_naive":
return batch_naive_neighbor_list(
positions,
cutoff,
pbc=pbc,
cell=cell,
batch_idx=batch_idx,
batch_ptr=batch_ptr,
half_fill=half_fill,
fill_value=fill_value,
return_neighbor_list=return_neighbor_list,
wrap_positions=wrap_positions,
strategy=selected_naive_strategy,
**kwargs,
)
case "batch_cell_list":
if cell is None:
batch_idx, batch_ptr = prepare_batch_idx_ptr(
batch_idx, batch_ptr, positions.shape[0]
)
positions, cell, pbc = synthesize_cell_for_cell_list(
positions,
cutoff,
batch_idx=batch_idx,
batch_ptr=batch_ptr,
num_systems=batch_ptr.shape[0] - 1,
)
return batch_cell_list(
positions,
cutoff,
cell,
pbc,
batch_idx,
batch_ptr=batch_ptr,
half_fill=half_fill,
fill_value=fill_value,
return_neighbor_list=return_neighbor_list,
strategy=selected_cell_strategy,
grid_policy=grid_policy,
atom_centric_path=selected_atom_centric_path,
**kwargs,
)
case "cluster_tile":
_reject_unsupported_cluster_tile_combo(pbc, half_fill)
if cell is None:
raise ValueError("cell is required for method='cluster_tile'")
return cluster_tile_neighbor_list(
positions,
cutoff,
cell,
fill_value=fill_value,
format="coo" if return_neighbor_list else "matrix",
cutoff2=cutoff2,
**kwargs,
)
case "batch_cluster_tile":
_reject_unsupported_cluster_tile_combo(pbc, half_fill)
if batch_idx is None or batch_ptr is None:
batch_idx, batch_ptr = prepare_batch_idx_ptr(
batch_idx, batch_ptr, positions.shape[0]
)
if cell is None:
raise ValueError("cell is required for method=batch_cluster_tile")
if cell.ndim == 2:
num_systems = batch_ptr.shape[0] - 1
cell = jnp.broadcast_to(cell, (num_systems, 3, 3))
return batch_cluster_tile_neighbor_list(
positions,
cutoff,
cell,
batch_ptr,
fill_value=fill_value,
format="coo" if return_neighbor_list else "matrix",
cutoff2=cutoff2,
**kwargs,
)
case "naive_dual_cutoff":
if cutoff2 is None:
raise ValueError(
"cutoff2 must be provided for naive_dual_cutoff method"
)
return naive_neighbor_list_dual_cutoff(
positions,
cutoff,
cutoff2,
pbc=pbc,
cell=cell,
half_fill=half_fill,
fill_value=fill_value,
return_neighbor_list=return_neighbor_list,
wrap_positions=wrap_positions,
**kwargs,
)
case "batch_naive_dual_cutoff":
if cutoff2 is None:
raise ValueError(
"cutoff2 must be provided for batch_naive_dual_cutoff method"
)
return batch_naive_neighbor_list_dual_cutoff(
positions,
cutoff,
cutoff2,
pbc=pbc,
cell=cell,
batch_idx=batch_idx,
batch_ptr=batch_ptr,
half_fill=half_fill,
fill_value=fill_value,
return_neighbor_list=return_neighbor_list,
wrap_positions=wrap_positions,
**kwargs,
)
case _:
raise ValueError(f"Invalid method: {method}")
__all__ = [
# High-level API
"neighbor_list",
"NeighborListState",
"prepare_neighbor_list",
"check_neighbor_list_state",
"estimate_neighbor_list_costs",
"suggest_neighbor_list_method",
# Unbatched neighbor list
"naive_neighbor_list",
"naive_neighbor_list_dual_cutoff",
"estimate_cell_list_sizes",
"build_cell_list",
"query_cell_list",
"cell_list",
"estimate_cluster_tile_list_sizes",
"build_cluster_tile_list",
"query_cluster_tile",
"query_cluster_tile_coo",
"cluster_tile_neighbor_list",
# Batched neighbor list
"batch_naive_neighbor_list",
"batch_naive_neighbor_list_dual_cutoff",
"estimate_batch_cell_list_sizes",
"batch_build_cell_list",
"batch_query_cell_list",
"batch_cell_list",
"estimate_batch_cluster_tile_list_sizes",
"estimate_batch_max_tiles_per_group",
"estimate_batch_cluster_tile_segments",
"allocate_batch_cluster_tile_list",
"batch_build_cluster_tile_list",
"batch_query_cluster_tile",
"batch_query_cluster_tile_coo",
"batch_cluster_tile_neighbor_list",
# Rebuild detection
"cell_list_needs_rebuild",
"neighbor_list_needs_rebuild",
"check_cell_list_rebuild_needed",
"check_neighbor_list_rebuild_needed",
# Utilities
"compute_naive_num_shifts",
"get_fixed_capacity_neighbor_list_from_neighbor_matrix",
"get_neighbor_list_from_neighbor_matrix",
"prepare_batch_idx_ptr",
"allocate_cell_list",
"estimate_max_neighbors",
"compute_batch_pair_centric_n_outer",
"NeighborOverflowError",
"TileBufferOverflow",
]