Hessian range

The Hessian job is part of eOn Goswami [DHS_Gos25]. The older description of that client is Chill et al. Chill et al. [DHS_CWT+14].

When coloring applies

Hessian::calculate colors the mobile atoms when all of the following hold.

  • Potential::hessianRange() is finite and strictly positive.

  • [Main] remove_net_force is off, or some atom is fixed, or the system has one atom. Net-force removal shifts every atom, so a column is no longer confined to the neighborhood.

  • [Hessian] checkpoint_path is empty. A checkpoint is stored one coordinate at a time.

The reported value is the distance beyond which every Hessian block between two atoms is exactly zero. Mobile atoms are greedy-colored on the square of that neighborhood. One displacement of a color along x, y, or z fills the columns of that color. Entries outside the neighborhood are written as zero, which is exact only for that distance.

Each row of that square is deduplicated while it is filled, with the same epoch-marked visited array the greedy coloring uses. The temporary storage is the edges, at most one slot per mobile pair. Pushing every toucher pair and sorting afterwards holds O(sum t_k^2) integers first, which is the whole cell when a many-body range reaches across it.

When the coloring has as many colors as mobile atoms, calculateColored returns false and calculate takes the batched path, or the serial path when the potential does not batch. A color per atom does not reduce the force count, and the colored loop would skip batching. Catch2 Coloring falls back when every mobile atom needs its own color is that case: a four-atom cluster whose diameter is below the range takes 25 force calls, the serial central count. The eight-atom embedding chain takes 49 force calls total on the central scheme.

0 and any non-finite value mean the range is unknown. The matrix is then one column per coordinate. A potential that evaluates batches takes the batched path instead, still one sample per coordinate.

How a potential opts in

Override Potential::hessianRange() and return that distance. The default is 0.

An rgpot kernel wrapped by RgpotAdapter does not override the adapter. It specializes eonc::HessianRangeOf<Kernel> in include/eon/potentials/RgpotAdapter/HessianRange.h. The primary template is HessianLocality::Unknown and returns 0. The adapter calls that trait and passes the result through acceptedHessianRange, which turns a non-positive or non-finite value into 0.

Override Potential::hessianRange() directly for a potential that is not an rgpot kernel. finiteCutoff() is deprecated and stays as the fallback that default hessianRange() calls, so an existing override still colors.

The specialization declares a locality class and returns the matching distance.

Class

Range

Pair

the interaction cutoff

Atom-centred many-body

twice the interaction cutoff

Molecular site model

the intermolecular cutoff plus twice the largest intramolecular extent, or 0 when that extent is not a hard bound

Message passing

n_layers times the edge cutoff when the layer count is in the kernel, otherwise 0

Do not infer the range from config().cutoff. That field is the neighbour-list cutoff. For a many-body kernel it is too short, and for water and for UMA it is not a Hessian range at all.

A kernel added in rgpot follows Porting potentials and then adds this specialization in the same change that wires the factory arm. Leaving the primary template in place keeps coloring off.

Kernels

The classes below were checked at the current rgpot pin and at rgpot release v3.5.0. “Wrapped” means makePotential builds an RgpotAdapter for that kernel. A kernel that exists in rgpot but is not wrapped still has a specialization when its header is present, so a later factory arm cannot turn coloring on by having a cutoff field.

Kernel

Pin

3.5.0

Class

Reported range

LJPot

wrapped

wrapped

pair

config().cutoff, default 15 Å

LJClusterPot

wrapped

wrapped

pair

config().cutoff, default 15 Å

MorsePot

wrapped

wrapped

pair

config().cutoff, default 9.5 Å

ZBLPot

wrapped

wrapped

pair

config().cut_global, default 2.5 Å

EAMAlPot

wrapped

wrapped

atom-centred

2 * 7.1 Å

SWPot

wrapped

wrapped

atom-centred

2 * 1.8 * 2.0951 Å

TersoffPot

wrapped

wrapped

atom-centred

2 * 3.0 Å

EDIPPot

wrapped

wrapped

atom-centred

2 * 3.1213820 Å

LenoskyPot

wrapped

wrapped

atom-centred

2 * 4.5 Å

FeHePot

wrapped

wrapped

atom-centred

8.4 Å

CuH2Pot

wrapped

wrapped

atom-centred

2 * 6.1 Å

WaterHPot (TIP4P-H)

factory arm when water is built

same

unknown

disabled

XTBPot

wrapped when built

same

unknown

disabled

D3Pot

wrapped when built

same

unknown

disabled

D4Pot

wrapped when built

same

unknown

disabled

MOPACPot

wrapped

wrapped

unknown

disabled

ExprPot

wrapped when built

same

unknown

disabled

UmaPot

header, not a factory arm

same, and config().cutoff

message passing

disabled

TIP4PPot

not in this pin

header

molecular site

disabled

SPCEPot

not in this pin

header

molecular site

disabled

TIP4PPtPot

not in this pin

header

molecular site

disabled

EAMPot (cell list)

not in this pin

header

atom-centred

2 * 5.555 Å

EMTPot

not in this pin

header

atom-centred

disabled

NWChemPot, CPMDPot, TBLitePot, SkalaPot, MetatomicPot

dlopen engines

same

unknown

disabled

NWChemPot, CPMDPot, TBLitePot, SkalaPot and MetatomicPot are reached through RgpotPot or an engine plugin, not through RgpotAdapter. They do not override hessianRange, so they stay at 0.

Potentials that are not rgpot kernels also stay at 0 unless they override hessianRange. That includes the in-tree EMT potential and the in-tree TIP4P, SPC/E and TIP4P-Pt potentials on this pin. Those water potentials are the same flexible models as the 3.5.0 kernels below, and the same reason keeps coloring off.

Where the numbers come from

Pair kernels. LJPot, LJClusterPot and MorsePot return config().cutoff. ZBLPot returns cut_global. The ZBL switch makes the energy and the force zero at that radius (ZBLPot.cc, the switching polynomial at cut_global).

Atom-centred Fortran kernels. The C++ face has no cutoff field. The defaults below are the values the neighbour table is built at, and the block range is twice that.

  • EAMAlPot: rcut = 7.1 in rgpot_eam_al.f90. Pairs and densities are dropped by truncation_radius, which is inside rcut.

  • SWPot: alpha * sigma with sigma = 2.0951 and alpha = 1.8 in rgpot_sw.f90. The three-body term couples both ends of a triplet.

  • TersoffPot: taper end s = 3.0 in rgpot_tersoff.f90. cutoff_taper is zero at and beyond S.

  • EDIPPot: max(a, b) with a = b = 3.1213820 in rgpot_edip.f90.

  • LenoskyPot: default_cutoff = 4.5 in rgpot_lenosky.f90, shared by the pair and density splines.

  • FeHePot: in rgpot_fehe.f90 the pair cutoffs are Fe-Fe 5.3, Fe-He 3.9028 and He-He 5.4. d-band density vanishes at 4.2 and only Fe embeds it. s-band density vanishes at 4.10 and both species embed it. The range is the larger of the pair cutoffs and twice the largest density cutoff, max(5.4, 2 * 4.2) = 8.4.

  • CuH2Pot: rcut = 6.1 in rgpot_cuh2.f90. phi and rho are shifted to vanish there.

WaterHPot. rgpot_water_h.f90 says there is no cutoff. Every site interacts with the lone H at its nearest periodic image, however far away. The range stays 0.

UMA, on the pin and on v3.5.0. UmaConfig::cutoff (default 6 Å, UmaConfig.hpp) is the vesin edge cutoff. UmaPot::forceImpl builds that edge list and runs the compiled graph (UmaPot.cc, the vesin_fairchem_edges call). The package metadata can replace the cutoff. The number of message-passing layers is not a field of the kernel or of UmaConfig. n_layers * cutoff is not derivable, so the specialization is MessagePassing and the range is 0.

Water on v3.5.0. WaterConfig::cutoff (default 8.5 Å, WaterPots.hpp) is the intermolecular cutoff passed into TIP4P, SPC/E and TIP4P-Pt. The CCL intramolecular term (ccl.hpp, intramolecular) is a polynomial in the bond stretch and the angle. It has no distance at which it is identically zero. SPC/E also exposes coulombFull (spce_ccl.hpp), a Coulomb path with no cutoff. A molecule is flexible, so there is no hard intramolecular extent to add to the cutoff. The range stays 0.

Cell-list EAM on v3.5.0. EAMCellConfig is empty. EAM/Parameters.h lists r_cut of 5.555 Å (Al), 5.412 Å (Pd) and 5.5155 Å (Au). The specialization reports twice the largest of those cutoffs, 2 * 5.555 Å.

EMT on v3.5.0. EMTConfig is a parameter-set flag and has no cutoff. EMTDefaultParameterProvider::calc_cutoff builds a cutoff from the elements in the system, and the weight is a Fermi function. There is no single distance that is exact for every system, so the class is recorded and the range stays 0.

XTBPot, D3Pot, D4Pot, MOPACPot and ExprPot use the primary template. D3 and D4 do not expose a cutoff on their config, and an expression is only as local as its terms.

Checked zig-zags

Catch2 Opted-in kernels match the serial matrix at the declared range runs each opted-in kernel on its own zig-zag. The colored matrix matches the per-column matrix. A block past the interaction cutoff is nonzero for every many-body kernel, and every block past the declared range is 0. The short-range column is the negative test: SW_SI and EAM_AL are wrapped so the reported range is r_c instead of 2 r_c, and that matrix misses the per-column matrix by more than 1e-2 of max |H|.

| Kernel | Atoms | Colors | Serial calls | Colored calls | max |H| | Largest nonzero block (Å) | Colored error | Short-range error | | — | — | — | — | — | — | — | — | — | | EAM_AL | 14 | 11 | 85 | 67 | 0.730150 | 9.907 | 0 | 0.013011 | | SW_SI | 10 | 7 | 61 | 43 | 16.16306 | 4.070 | 0 | 0.458243 | | TERSOFF_SI | 8 | 5 | 49 | 31 | 14.54654 | 4.070 | 0 | not run | | EDIP | 10 | 7 | 61 | 43 | 12.68665 | 4.070 | 0 | not run | | LENOSKY_SI | 10 | 7 | 61 | 43 | 13.38487 | 4.613 | 0 | not run | | FEHE | 12 | 9 | 73 | 55 | 3.670133 | 8.188 | 0 | not run | | CUH2 | 14 | 11 | 85 | 67 | 2.062919 | 8.833 | 0 | not run | | ZBL | 8 | 3 | 49 | 19 | 137.3325 | 1.500 | 0 | not run |

References

[DHS_CWT+14]

Samuel T Chill, Matthew Welborn, Rye Terrell, Liang Zhang, Jean-Claude Berthet, Andreas Pedersen, Hannes Jónsson, and Graeme Henkelman. EON: software for long time simulations of atomic scale systems. Modelling and Simulation in Materials Science and Engineering, 22(5):055002, July 2014. doi:10.1088/0965-0393/22/5/055002.

[DHS_Gos25]

Rohit Goswami. Efficient exploration of chemical kinetics. October 2025. arXiv:2510.21368, doi:10.48550/arXiv.2510.21368.