kups.core.neighborlist.verlet
¶
Verlet neighbor list with a skin: the margin accounting.
A Verlet-skin scheme builds one conservative neighbor list at an enlarged
radius r_build ≈ cutoff + skin, stores its edges, and reuses them over many
steps via
RefineCutoffNeighborList,
amortizing the expensive build over the rebuild window. This module holds the
pure geometry underneath such a scheme:
skin_margin decides how long the
stored list remains complete, and
effective_build_radii
keeps the build radius inside the single-image regime that edge reuse requires.
SkinMargin
¶
Per-system completeness accounting of a stored skin list.
Attributes:
| Name | Type | Description |
|---|---|---|
consumed |
Array
|
Worst-case distance (Å) by which atom motion and cell
deformation since the build can have pulled a non-listed pair
inward, |
budget |
Array
|
Distance (Å) such a pair had to spare at build time — the
effective skin |
Source code in src/kups/core/neighborlist/verlet.py
headroom
property
¶
budget - consumed; the stored list is complete while >= 0.
SkinReference
¶
Geometry snapshot taken when the skin list was built.
skin_margin measures the
drift of the current geometry relative to this snapshot. The arrays must
not alias the live position/cell buffers (donated jitted steps would then
receive the same buffer twice).
Attributes:
| Name | Type | Description |
|---|---|---|
positions |
Array
|
Cartesian positions at the build, |
cell |
Cell[AnyPeriodicity]
|
|
Source code in src/kups/core/neighborlist/verlet.py
effective_build_radii(cutoffs, skin, cell)
¶
Per-system build radius: cutoff + skin, clamped to a single image.
Reusing stored edges keeps exactly one periodic image per pair, so the build radius must stay below half the cell's smallest perpendicular length on every periodic axis — beyond that, second images enter the build sphere and the reuse path would drop them. A cell that compresses mid-run thus degrades to a thinner effective skin (more frequent rebuilds) instead of an incomplete list. No clamp applies in vacuum.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cutoffs
|
Array
|
True cutoffs (Å), |
required |
skin
|
ArrayLike
|
Requested skin width (Å). |
required |
cell
|
Cell[AnyPeriodicity]
|
|
required |
Returns:
| Type | Description |
|---|---|
Array
|
Build radii (Å), |
Source code in src/kups/core/neighborlist/verlet.py
skin_margin(particles, systems, reference, cutoffs, skin)
¶
How much of the skin list's safety margin the geometry has used up.
A skin list built at radius r_build stays complete for the true
cutoff as long as no pair that was outside r_build at build time
has come inside cutoff since. Two things move pairs inward:
- Cell deformation. Between the build and now the cell changed by the
linear map
F = h_ref⁻¹ h_now(row-vector convention), which maps every build-time pair vectord— including those to periodic images — tod @ F. A linear map cannot shrink any vector by more than its smallest singular value:|d @ F| >= σ_min(F) |d|for alld. So the affine part of the motion leaves every non-listed pair at distance at leastσ_min(F) r_build, an inward move of at mostr_build (1 - σ_min(F))— and none at all if the cell only expanded (σ_min >= 1). Becauseσ_minsees the whole map, pure shear counts like any other strain, unlike per-axis length ratios. - Atom motion on top of the deformation. Each atom's non-affine
displacement is
u_i = x_i - x_i_ref @ F— what remains after riding the cell — minimum-image wrapped in the current cell so that a boundary crossing (even along a sheared lattice vector) is undone exactly (a genuine non-affine drift beyond half a cell would be under-measured, but rebuilds fire at skin scale long before that). A pair distance changes by at most the two endpoint displacements,2 max|u|.
The stored list is therefore complete while, per system,
consumed := 2 max|u| + r_build max(0, 1 - σ_min(F)) <= r_build - cutoff =: budget
i.e. while the worst-case inward motion of a non-listed pair (consumed) has not eaten the extra radius the build added on top of the cutoff (budget). Pairs never span systems, so the accounting is fully per system: one hot system neither charges nor rebuilds the others.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
particles
|
Table[ParticleId, HasPositionsAndSystemIndex]
|
Current particle table (positions and system index). |
required |
systems
|
Table[SystemId, NeighborListSystems]
|
Current system table (cells). |
required |
reference
|
SkinReference
|
Positions and cell snapshot taken at the last build. |
required |
cutoffs
|
Table[SystemId, Array]
|
True cutoffs (Å) per system. |
required |
skin
|
ArrayLike
|
Requested skin width (Å) the list was built with. |
required |
Returns:
| Type | Description |
|---|---|
Table[SystemId, SkinMargin]
|
Per-system |
Table[SystemId, SkinMargin]
|
table ( |