LAMMPS DeepMD Integration (pair_deepmd)#
Overview#
pair_deepmd is the LAMMPS pair style that connects DeePMD-kit's deep learning potentials to a LAMMPS MD simulation. It is implemented in source/lmp/pair_deepmd.cpp as PairDeepMD, a subclass of PairDeepBaseModel (which itself extends LAMMPS's Pair). The base class (source/lmp/pair_deepmd_base.cpp) handles neighbor list setup, init_one(), and MPI communication; PairDeepMD provides compute(), settings(), and coeff() specific to the standard DeePot potential.
Initialization Flow#
Model Loading — settings()#
PairDeepMD::settings() parses the pair_style deepmd command line:
- Single-model mode: initializes
deep_potfrom the first argument. Cutoff, type count, and frame/atom parameter dimensions are read directly from the model. - Multi-model mode (≥2 model files): additionally initializes
deep_pot_model_devifor committee-based uncertainty estimation. Both objects must agree on cutoff and type counts (enforced byasserts at lines 592–596) . - Recognized optional keywords:
out_freq,out_file,fparam,aparam,fparam_from_compute,aparam_from_compute,ttm,atomic,relative,relative_v,virtual_len,spin_norm.
Neighbor List Request — init_style()#
PairDeepBaseModel::init_style() requests a full (not half) neighbor list, required for the many-body DeepPot descriptor:
- LAMMPS ≥ 20220324:
neighbor->add_request(this, NeighConst::REQ_FULL) - Older LAMMPS: legacy
neighbor->request()withhalf = 0,full = 1
Pair Type Validation — init_one()#
PairDeepBaseModel::init_one() is called per atom-type pair. If either type index exceeds the model's numb_types, it emits a warning (not an error) and the interaction is silently dropped. It returns the model cutoff as the effective pair cutoff.
Compute Loop#
PairDeepMD::compute() is the main per-timestep entry point.
Coordinate and Box Preparation#
Coordinates are shifted to the box origin and unit-converted before being passed to DeePot :
dcoord[ii*3 + dd] = (x[ii][dd] - domain->boxlo[dd]) / dist_unit_cvt_factor
Box vectors are extracted from LAMMPS's domain->h triclinic representation and mapped to the 9-element row-major format expected by DeePot . No explicit NaN/Inf validation is performed in the wrapper — coordinate validity is delegated to the DeePot C++ API.
LAMMPS Neighbor List → InputNlist#
The LAMMPS NeighList is wrapped into a deepmd_compat::InputNlist , which directly aliases LAMMPS's list->ilist, list->numneigh, list->firstneigh. For parallel runs, CommBrickDeepMD swap metadata (nswap, sendnum, recvnum, sendlist, etc.) is appended for ghost-atom communication. The mask NEIGHMASK is applied to strip unused bits from neighbor indices.
For single-process runs with atom maps enabled, a mapping_vec (atom tag → local index) is set for DPA-2/JAX compatibility .
ago and Neighbor Rebuild Control#
ago = neighbor->ago tracks timesteps since the last neighbor list rebuild . ago is passed directly to deep_pot.compute(), which uses it to decide whether to reuse the previous session's internal neighbor structure or rebuild it. For multi-model deviation runs, ago is forced to 0 on deviation-output timesteps to guarantee fresh neighbor data for all models.
Dispatch to DeePot#
Three compute branches exist :
| Condition | Call |
|---|---|
| Single model, no per-atom output | deep_pot.compute(energy, force, virial, ...) |
| Single model, per-atom output | deep_pot.compute(energy, force, virial, eatom, vatom, ...) |
| Multi-model, deviation output step | deep_pot_model_devi.compute(all_energy, all_force, all_virial, ...) |
All deep_pot.compute() calls are wrapped in try/catch(deepmd_compat::deepmd_exception&) with error->one(FLERR, e.what()) on failure — this surfaces DeePot-level errors (e.g., out-of-range coordinates, model inference failures) as LAMMPS fatal errors .
Error / Unsupported Feature Guards#
- Spin atoms: explicitly rejected with
error->all(FLERR, ...)at the top ofcompute()and inpack_reverse_comm()— usepair_style deepspininstead . - 6-element atomic virial: rejected; the 9-element centroid virial via
compute centroid/stress/atomis required . - Serial multi-model:
error->all(FLERR, "Serial version does not support model devi").
Model Deviation Output (Multi-Model)#
When numb_models > 1 and out_freq > 0, per-timestep force and virial deviations are written to model_devi.out . Force standard deviation is computed via compute_std_f() (or the relative variant with the relative keyword). MPI Gather/Reduce operations collect per-rank data to rank 0 for output. The atomic keyword enables per-atom force deviation columns.
Neighbor List Internals (neighbor_list.cc)#
source/lib/src/neighbor_list.cc implements DeePot's own cell-list neighbor search, used in non-LAMMPS contexts (Python API, standalone tests). Key components:
build_clist(): bins atoms into cells; out-of-bound local atoms are clamped with a warning (up toMAX_WARN_IDX_OUT_OF_BOUND = 10times) rather than raising a fatal error .build_nlist(): two-cutoff neighbor list (innerrc0, outerrc1) using the cell list. Verifiesrc0 ≤ rc1and adequate cell subdivision viaassert.build_nlist_cpu(): O(N²) fallback for small systems; returns1(signal overflow) if neighbor count exceedsmem_size.copy_coord(): generates ghost atoms for PBC by replicating local atoms across cell boundaries.
In the LAMMPS integration path, this library code is bypassed — LAMMPS's own neighbor list machinery is used and passed directly as InputNlist.
Key Source Files#
| File | Role |
|---|---|
source/lmp/pair_deepmd.cpp | PairDeepMD::compute(), settings(), coeff() |
source/lmp/pair_deepmd_base.cpp | Base class: init_style(), init_one(), MPI comm helpers |
source/lib/src/neighbor_list.cc | Standalone cell-list neighbor builder (non-LAMMPS path) |
source/lib/include/neighbor_list.h | InputNlist struct definition |