xnn.common.deploy.torchscript#

Self-contained TorchScript export: a trained model as a standalone .pt.

The artifact produced here is driven purely by tensors and carries its own neighbor list, so a consumer needs only libtorch / torch.jit.load – no xnn import, no Python model code, no config file. That is what makes a checkpoint usable from LAMMPS, i-PI, OpenMM, a C++ driver or any other MD package.

Two entry points are exported on the same module:

forward(pos, atomic_numbers, cell, pbc)

The whole-system ABI. The module builds its own neighbor list from the cutoff baked into it at export time. This is the general-purpose entry point and the only correct one for models carrying a long-range term.

forward_lammps(pos, edge_index, cell_shifts, atomic_numbers, cell)

The pair-style ABI, matching LAMMPSWrapper (and hence pair_nequip / pair_mace / pair_allegro): the caller supplies the neighbor list. Cheaper, because the MD engine already has a neighbor list, but see the long-range caveat below.

Calling conventions#

One structure per call (inputs are (N, 3), with no batch dimension). Positions may be float32 or float64 whatever the weights’ dtype: the module computes in its own dtype and answers in the caller’s. Wrapping the call in torch.no_grad() is fine – forces come from autograd, so the module re-enables grad internally and restores the caller’s mode afterwards – but torch.inference_mode() raises, because tensors created under it can never participate in autograd.

Add-on terms: LES long-range and D4 dispersion#

Two wrappers can sit on top of a core model, in either order or together: LatentEwald (an Ewald energy over latent charges) and DispersionCorrection (the DFT-D3 / DFT-D4 corrections; D4’s EEQ charges couple every atom of the structure through a dense linear system). Both are global: they do not decompose into a local, per-domain neighbor list. A model exported with either must be driven with the whole system on one rank (forward, or forward_lammps with a full-system neighbor list) – an MPI-decomposed pair style that only ever sees its own subdomain plus ghosts cannot reproduce the trained energy. export_torchscript_potential() records long_range and dispersion in the archive metadata so a consumer can check.

The dispersion wrapper also widens the neighbor list (its cutoffs default to the upstream 60 / 40 / 30 / 25 bohr): the export bakes in the wrapper’s cutoff and hands the core model only the edges within the core’s own radius, exactly as the eager wrapper does. The total charge of the system is fixed at export time (total_charge, default neutral), since neither tensor ABI carries it.

Functions

build_neighbor_list_ts(pos, cutoff, cell, pbc)

torch.jit-able neighbor list, matching the reference implementation.

export_torchscript_potential(model, cutoff, path)

Script a trained model to a standalone .pt and save it.

split_wrappers(model[, total_charge])

Peel the LES / D4 wrappers off a model.

Classes

TorchScriptPotential(model, cutoff[, ...])

Tensor-only, scriptable potential: positions in, energy/forces/stress out.