diff --git a/doc/agent-skills.md b/doc/agent-skills.md index 54abd87d2e..dda701ace0 100644 --- a/doc/agent-skills.md +++ b/doc/agent-skills.md @@ -18,14 +18,17 @@ in the DeePMD-kit repository under `skills/`. The skill uses progressive disclosure: the top-level workflow handles common training steps and model selection, while model-specific configuration lives under `skills/deepmd-train/models/` and is read only after a model is chosen. - Current references include DPA3 and se_e2_a. + Current references include DPA3, DPA4/SeZM, and se_e2_a. - `deepmd-finetune-dpa3`: Fine-tune DPA3 models from self-trained checkpoints, multi-task pretrained models, or built-in models downloaded by `dp pretrained download`. +- `deepmd-finetune-dpa4`: Fine-tune DPA4/SeZM checkpoints with the PyTorch + backend using standard or LoRA fine-tuning, then validate and export to `.pt2`. - `deepmd-python-inference`: Run Python and CLI inference with trained or - frozen DeePMD-kit models, including energy, force, virial, descriptor, and - model-deviation workflows. + frozen DeePMD-kit models, including DPA4/SeZM `.pt2` archives and energy, + force, virial, descriptor, embedding, and model-deviation workflows. - `lammps-deepmd`: Prepare, explain, and run LAMMPS simulations with DeePMD-kit - potentials, including common NVE, NVT, and NPT setups. + potentials, including DPA4/SeZM `.pt2` deployment and common NVE, NVT, and + NPT setups. ## Related reference @@ -78,5 +81,7 @@ without launching an expensive calculation. For example: for loading a frozen DeePMD-kit model and evaluating one frame.” - “Use the `deepmd-train` skill to choose between DPA3 and se_e2_a for a small water dataset and draft a training input, but do not start training.” +- “Use the `deepmd-finetune-dpa4` skill to inspect a DPA4 checkpoint and draft + a LoRA fine-tuning input, but do not start training.” - “Use the `lammps-deepmd` skill to prepare an NVT LAMMPS input file for a DeePMD-kit model, and explain each command.” diff --git a/skills/deepmd-finetune-dpa4/SKILL.md b/skills/deepmd-finetune-dpa4/SKILL.md new file mode 100644 index 0000000000..3e096280d8 --- /dev/null +++ b/skills/deepmd-finetune-dpa4/SKILL.md @@ -0,0 +1,202 @@ +--- +name: deepmd-finetune-dpa4 +description: Fine-tune a DPA4 model in DeePMD-kit. Use for standard or LoRA fine-tuning from a DPA4/SeZM .pt checkpoint, validation and .pt2 export. +compatibility: Requires deepmd-kit with the PyTorch backend. DPA4/SeZM training is GPU-oriented. +license: LGPL-3.0-or-later +metadata: + author: SchrodingersCattt + version: '1.0' + repository: https://github.com/deepmodeling/deepmd-kit +--- + +# DeePMD-kit Fine-tuning: DPA4 + +Fine-tune a DPA4/SeZM checkpoint on downstream DeePMD data. This skill covers +single-task standard and LoRA fine-tuning. Do not infer the model family from a +`.pt` suffix or filename: DPA3 and DPA4 checkpoints use the same suffix. + +## Route the checkpoint + +If the user has not already established the model family, inspect the stored +configuration: + +```bash +dp --pt show pretrained.pt descriptor fitting-net type-map +``` + +Use this skill only when the descriptor/model configuration identifies DPA4 or +SeZM. If the checkpoint is multi-task, inspect its branches before selecting a +head: + +```bash +dp --pt show pretrained.pt model-branch descriptor type-map +``` + +Do not guess a branch. Use `deepmd-finetune-dpa3` instead when the descriptor is +DPA3, and stop when the family cannot be established. + +## Obtain a pretrained checkpoint + +Fine-tuning requires a DPA4/SeZM training checkpoint (`.pt`), not a `.pt2` +deployment archive. Check whether the installed version provides one: + +```bash +dp pretrained download -h +``` + +Use only a listed model or a checkpoint supplied by the user or its publisher. +Record its source and DeePMD-kit version, then verify its descriptor, branch, +architecture, and `type_map` before use. + +## Before fine-tuning + +1. Confirm the checkpoint exists and can be inspected. +1. Confirm training, validation, and held-out systems, labels, and element type maps. +1. Split correlated frames by independent system, trajectory, or source family; + do not create a nominal held-out set by randomly splitting adjacent frames. +1. Validate each DeePMD system before training: `natoms` is the number of tokens + in `type.raw`, coordinate and force widths are `3 * natoms`, and every used + label is finite and frame-aligned. +1. Start from the exact checkpoint architecture. Introducing new element types, + changing architecture, or combining specialized spin/property/multi-task + configurations requires separate compatibility validation. +1. Choose standard fine-tuning or LoRA. Do not assume a built-in DPA4 model name; + check `dp pretrained download -h` for the installed version. + +## Decide whether to use LoRA + +Use standard fine-tuning by default. Use LoRA only for a single-task target when +parameter-efficient adaptation is wanted and the exact base architecture is +known. LoRA is enabled by a non-null `model.lora` block in the new input; the +pretrained checkpoint does not need to contain LoRA. Multi-task LoRA targets are +unsupported. + +Periodic LoRA checkpoints retain adapters and can resume training. Best +checkpoints may merge the adapters into ordinary DPA4 weights, so absence of +LoRA metadata does not prove LoRA was never used. + +## Standard fine-tuning + +The model section in `input.json` must match the checkpoint unless the standard +pretrained-script mechanism is deliberately used: + +```bash +dp --pt train input.json --finetune pretrained.pt +``` + +When fine-tuning a single-task target from a multi-task checkpoint and the +intent is to preserve a particular pretrained fitting head, pass the branch +selected above: + +```bash +dp --pt train input.json --finetune pretrained.pt --model-branch SELECTED_BRANCH +``` + +If `--model-branch` is omitted, the fitting net may be initialized from the +`RANDOM` branch instead. A multi-task target uses `finetune_head` in each target +branch rather than the command-line option. + +`--use-pretrain-script` replaces only the target `model.descriptor` and +`model.fitting_net` from the checkpoint. It does not restore the complete model +configuration. Inspect and reproduce all other required model-level fields in +the target input, including `type`, spin settings, bridging method/radii, and +task-specific options: + +```bash +dp --pt train input.json --finetune pretrained.pt --use-pretrain-script +``` + +Inspect the resulting configuration and run a bounded initial segment before a +long training job. Do not combine model-specific additions with +`--use-pretrain-script` unless that combination has been validated. + +## LoRA fine-tuning + +DPA4/SeZM supports LoRA adapters for single-task fine-tuning. Copy the exact base +architecture into `lora_ft.json`, then add: + +```json +{ + "model": { + "type": "dpa4", + "lora": { + "rank": 16, + "alpha": 16.0 + } + } +} +``` + +Run: + +```bash +dp --pt train lora_ft.json --finetune pretrained.pt +``` + +When `pretrained.pt` is multi-task, preserve the selected fitting head: + +```bash +dp --pt train lora_ft.json --finetune pretrained.pt \ + --model-branch SELECTED_BRANCH +``` + +Use the shorter command only for a single-task source checkpoint. + +The JSON fragment above is not a complete training input. Adapt the full public +example at `../../examples/water/dpa4/lora_ft.json`, but copy the exact +architecture from the source checkpoint before adding `model.lora`. Do not add +`--use-pretrain-script` unless a targeted test confirms that LoRA is retained. + +## Monitor and validate + +Monitor `lcurve.out` for non-finite values and train/validation divergence. +Select a checkpoint using validation data, then follow the +[complete held-out evaluation](../deepmd-python-inference/references/held-out-evaluation.md) +with that exact native checkpoint and every held-out system. Export for deployment +only after the complete evaluation meets the task's declared thresholds. + +## Export and test + +Before export, read +`../deepmd-python-inference/references/dpa4-freeze-policy.md` and record the +selected freeze-time inference environment. + +DPA4/SeZM uses the `.pt2` AOTInductor export path rather than the conventional +PyTorch `.pth` freeze path: + +```bash +dp --pt freeze -c ckpt/model.ckpt.pt -o finetuned_model +dp test -m finetuned_model.pt2 -s /path/to/test_system -n 30 +``` + +The freeze command detects DPA4/SeZM and writes `finetuned_model.pt2`. Validate +the exported archive in the target environment before deployment. + +For a multi-task checkpoint, freeze the selected head explicitly: + +```bash +dp --pt freeze -c ckpt/model.ckpt.pt -o finetuned_model --head SELECTED_BRANCH +``` + +The resulting `.pt2` contains the selected single head; do not pass a branch +again when loading that archive. + +## Checklist + +- [ ] The stored descriptor identifies DPA4/SeZM; the `.pt` suffix was not used as proof. +- [ ] The checkpoint source, DeePMD-kit revision, architecture, and type map are recorded. +- [ ] The intended branch is explicit for a multi-task checkpoint. +- [ ] Training, validation, and held-out systems are independent by source family. +- [ ] Every admitted system has consistent atom counts, shapes, labels, and type maps. +- [ ] The input architecture is compatible with the checkpoint. +- [ ] Standard fine-tuning versus LoRA was selected from the task layout and domain shift. +- [ ] A resumable LoRA checkpoint is distinguished from a merged best checkpoint. +- [ ] LoRA uses a complete base configuration and is not silently overwritten. +- [ ] Complete held-out metrics, sample counts, and reference-label scales are reported. +- [ ] The selected `.pt` checkpoint was exported to and tested as `.pt2`. + +## References + +- [DPA4 model and LoRA documentation](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/dpa4.html) +- [Fine-tuning documentation](https://docs.deepmodeling.com/projects/deepmd/en/latest/train/finetuning.html) +- [Show model information](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/show-model-info.html) diff --git a/skills/deepmd-python-inference/SKILL.md b/skills/deepmd-python-inference/SKILL.md index 84348f835d..59811bcb15 100644 --- a/skills/deepmd-python-inference/SKILL.md +++ b/skills/deepmd-python-inference/SKILL.md @@ -1,11 +1,11 @@ --- name: deepmd-python-inference -description: Run Python inference with DeePMD-kit models using the DeepPot API. Use when the user wants to load a trained/frozen DeePMD model (.pth or .pb) or a built-in pretrained model (e.g., DPA-3.2-5M) in Python, predict energy/force/virial for atomic configurations, evaluate descriptors, or calculate model deviation between multiple models. Also covers using `dp test` CLI for batch evaluation against labeled data. -compatibility: Requires deepmd-kit Python package installed. PyTorch backend for .pth models, TensorFlow for .pb models. +description: Run Python inference with DeePMD-kit models using the DeepPot API. Use when the user wants to load a checkpoint, frozen model (.pb or .pth), DPA4/SeZM AOTInductor deployment archive (.pt2), or built-in pretrained model in Python; predict energy/force/virial; evaluate supported descriptors; calculate model deviation; or use `dp test` against labeled data. +compatibility: Requires deepmd-kit installed with the backend required by the selected model artifact. license: LGPL-3.0-or-later metadata: author: iProzd - version: '1.0' + version: '1.1' repository: https://github.com/deepmodeling/deepmd-kit --- @@ -29,15 +29,20 @@ e, f, v = dp.eval(coord, cell, atype) ## Agent Responsibilities 1. Determine the model source: - - Frozen model file (`.pth` for PyTorch, `.pb` for TensorFlow) + - Frozen model file (`.pth` for conventional PyTorch, `.pb` for TensorFlow, or `.pt2` for DPA4/SeZM) - Built-in pretrained model name (e.g., `DPA-3.2-5M`) - - Checkpoint file (requires freezing first) + - PyTorch checkpoint (`.pt`), whose stored model configuration must be inspected before choosing an inference or export path +1. Read `references/model-artifacts.md` for `.pt`/`.pt2` models or whenever the artifact route is unclear. +1. Read `references/held-out-evaluation.md` for complete labeled evaluation used for checkpoint selection or production admission. 1. Determine the inference task: - Single-frame prediction (energy, force, virial) - Batch prediction over multiple frames - Descriptor evaluation - Model deviation calculation - CLI-based testing against labeled data +1. Before using descriptor or embedding hooks, confirm that the selected + artifact supports them; a loadable `.pt2` does not necessarily contain the + serialized model required by those hooks. 1. Help the user prepare input arrays in the correct format. 1. Run inference and report results. @@ -54,6 +59,9 @@ dp = DeepPot("model.pth") # From a frozen TensorFlow model dp = DeepPot("graph.pb") +# From a frozen DPA4/SeZM model +dp = DeepPot("model.pt2") + # From a built-in pretrained model (auto-downloads if not cached) dp = DeepPot("DPA-3.2-5M") ``` @@ -196,6 +204,9 @@ Virial RMSE/Natoms : 2.957e-04 eV With `-d test_detail`, per-frame predictions are saved to files for further analysis. +The 30-frame commands above are bounded examples, not complete held-out evaluation. +Use `references/held-out-evaluation.md` when the result admits a model for production. + ## Complete Example: Train, Freeze, and Inference ```python @@ -285,7 +296,9 @@ dp pretrained download DPA-3.2-5M --cache-dir ./models ## Agent Checklist -- [ ] Model file exists and is accessible (`.pth`, `.pb`, or valid pretrained name) +- [ ] Model file exists and is accessible (`.pb`, `.pth`, `.pt`, `.pt2`, or valid pretrained name) +- [ ] An ambiguous `.pt` checkpoint was classified from its stored configuration, not its filename +- [ ] The requested descriptor or embedding operation is supported by the specific artifact, not inferred from its suffix - [ ] `coord` array is shaped (nframes, natoms\*3) and in Angstrom - [ ] `cell` array is shaped (nframes, 9) or `None` for non-periodic systems - [ ] `atype` indices match the model's `type_map` ordering diff --git a/skills/deepmd-python-inference/references/dpa4-freeze-policy.md b/skills/deepmd-python-inference/references/dpa4-freeze-policy.md new file mode 100644 index 0000000000..370f0345a3 --- /dev/null +++ b/skills/deepmd-python-inference/references/dpa4-freeze-policy.md @@ -0,0 +1,24 @@ +# DPA4 freeze-time inference policy + +Read this reference before exporting a DPA4 `.pt2`. The generated archive may +embed inference choices, so do not inherit unknown values of +`DP_TRITON_INFER`, `DP_TF32_INFER`, or `DP_AMP_INFER` from the shell. + +Choose one explicit policy for the target node. A conservative production +baseline that avoids the slow default while retaining full-precision +accumulation is: + +```bash +export DP_TRITON_INFER=1 +export DP_TF32_INFER=0 +export DP_AMP_INFER=0 +dp --pt freeze -c model.ckpt.pt -o frozen_model +``` + +`DP_TRITON_INFER=2` autotunes for the current hardware and therefore reinforces +the requirement to freeze and run on the same physical node. Levels 1 and 2 keep +FP32 accumulation. Level 3, TF32, and AMP change the numerical policy and require +task-specific accuracy and stability validation before production. + +Record all three values, device/runtime identity, input and output hashes, freeze +command, log, and true exit code with the artifact. diff --git a/skills/deepmd-python-inference/references/held-out-evaluation.md b/skills/deepmd-python-inference/references/held-out-evaluation.md new file mode 100644 index 0000000000..b2dd29cb95 --- /dev/null +++ b/skills/deepmd-python-inference/references/held-out-evaluation.md @@ -0,0 +1,78 @@ +# Complete held-out evaluation + +Read this reference when labeled DeePMD systems are used to select a checkpoint +or admit a model for production. A bounded smoke test is not a complete +held-out evaluation. + +## Admit the data + +- Keep held-out systems independent of training and validation by system, + trajectory, or source family; do not randomly split correlated adjacent frames. +- Enumerate every held-out system and all of its `set.*` directories. +- Set `natoms` to the number of whitespace-separated entries in `type.raw`. + Require coordinate and force widths of `3 * natoms`, one energy row per frame, + nine box values per periodic frame, and finite values for every evaluated label. +- When `type_map.raw` is present, interpret `type.raw` as zero-based indices into + that ordered map and compare model and data types by element identity. When it + is absent, require provenance that the dataset indices already follow the + candidate model's ordered type map. Fail closed when neither contract is + established; never copy dataset indices into an assumed model map. + +## Run every system + +Use the backend required by the exact candidate artifact. For a DPA4/SeZM native +checkpoint, run one command per held-out system: + +```bash +detail_root="details/selected-SHA256" +test ! -e "$detail_root" || exit 1 +mkdir -p "$detail_root" +detail_prefix="$detail_root/system.000" +dp --pt test -m selected.pt -s held_out/system.000 -n 0 -d "$detail_prefix" +``` + +`-n 0` evaluates all frames. Require explicit `-m`, `-s`, and a unique `-d` +prefix for each system. Preserve the command, log, true exit code, checkpoint +SHA256, and dataset identity. Do not overwrite existing detail files silently. + +For a native multi-task checkpoint, inspect its branches and pass the admitted +branch during evaluation: + +```bash +dp --pt show selected.pt model-branch +dp --pt test -m selected.pt -s held_out/system.000 -n 0 \ + -d "$detail_prefix" --head SELECTED_BRANCH +``` + +A frozen selected `.pt2` is already single-head; do not pass `--head` to it. + +## Validate detail outputs + +For an energy model, retain the emitted total-energy (`.e.out`), +energy-per-atom (`.e_peratom.out`), and force (`.f.out`) details. Retain +virial/stress details only when both reference labels and model outputs exist. +Require: + +- energy rows equal the evaluated frame count; +- force rows equal `frames * natoms`, with xyz stored as columns; +- all reference and prediction values are finite; +- energy-per-atom errors come directly from `.e_peratom.out`, or total-energy + errors are divided by `natoms` exactly once. + +Reject missing systems, partial frame coverage, reused detail prefixes, and +results tied to another checkpoint hash. + +## Report and decide + +For every available label, report per-system MAE, RMSE, units, sample count, and +the population standard deviation (`ddof=0`) of the corresponding held-out +reference values. Report an absent label as `N/A`, never zero. Aggregate from all +retained rows; do not average per-system RMSE values. + +Build parity plots from unrounded detail rows, with reference on x, prediction on +y, an equal-aspect `y=x` line, system identity, checkpoint hash, units, sample +count, RMSE, and reference-label standard deviation. + +Admit the candidate only when every declared held-out system is complete and the +declared thresholds pass. Training logs, a successful freeze, or a LAMMPS +canary cannot replace this evaluation. diff --git a/skills/deepmd-python-inference/references/model-artifacts.md b/skills/deepmd-python-inference/references/model-artifacts.md new file mode 100644 index 0000000000..a5c9608931 --- /dev/null +++ b/skills/deepmd-python-inference/references/model-artifacts.md @@ -0,0 +1,102 @@ +# DeePMD model artifacts for inference + +Read this reference when the model is a training checkpoint, its extension is +`.pt2`, or the correct backend/export path is unclear. + +## Identify the artifact + +A suffix identifies a serialization/backend route, not necessarily a model +family. In particular, both DPA3 and DPA4 training checkpoints use `.pt`. Never +classify a `.pt` checkpoint from its filename alone. Inspect its stored model +configuration when needed: + +```bash +dp --pt show model.pt descriptor fitting-net type-map +``` + +| Artifact | Typical role | Inference guidance | +| -------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `.pb` | TensorFlow frozen model | Load with `DeepPot` or use `dp test`. | +| `.pth` | Conventional PyTorch frozen model | Load with `DeepPot` or use `dp test`. | +| `.pt` | PyTorch training checkpoint | Inspect before use. DPA4 supports eager Python evaluation and embedding extraction from a checkpoint; deployment normally uses a frozen artifact. | +| `.pt2` | AOTInductor deployment archive | Use supported inference paths in a compatible runtime; the suffix alone does not imply descriptor hooks, portability, or multi-rank support. | + +Backend selection for inference is normally determined from the model artifact. +Do not add a backend flag merely from the assumed model family. + +## DPA4/SeZM + +DPA4/SeZM supports Python evaluation from its `.pt` checkpoint, but a `.pt2` +archive is the normal frozen deployment artifact. First read +`dpa4-freeze-policy.md`; choose and record the freeze-time inference environment +instead of inheriting unknown shell values. Then freeze with: + +```bash +dp --pt freeze -c model.ckpt.pt -o frozen_model +``` + +The command writes `frozen_model.pt2` for a detected DPA4/SeZM checkpoint. +For a multi-task checkpoint, select the head during export with +`--head SELECTED_BRANCH`; the resulting `.pt2` is already single-head. +Evaluate the archive with: + +```python +from deepmd.infer import DeepPot + +model = DeepPot("frozen_model.pt2") +energy, force, virial = model.eval(coord, cell, atype) +``` + +For labeled data: + +```bash +dp test -m frozen_model.pt2 -s /path/to/system -n 30 +``` + +`DeepPot.eval` on DPA4/SeZM `.pt2` archives is covered for energy, force, +virial, and atomic energy. Atomic virial is available only when the archive +metadata reports `do_atomic_virial=true`; the ordinary non-spin +`dp --pt freeze` route enables it, but specialized spin or conversion routes +may not. `dp test` uses the same model dispatch. Both require an installed +DeePMD-kit/PyTorch runtime compatible with the compiled archive. + +Check that `atype` follows the model `type_map` and that coordinates/cells use +the units and shapes documented by `DeepPot`. + +## Descriptors and DPA4 embeddings + +Descriptor evaluation is conditional for `.pt2`. It requires an archive that +contains the serialized `model.json`; metadata-only archives can run the main +`DeepPot.eval` path but raise `NotImplementedError` for `eval_descriptor`. +In particular, do not run `dp eval-desc` on a DPA4 `.pt2` produced by the +`dp --pt freeze` command above, because that export is metadata-only. Use a +supported checkpoint or verify the archive contents and backend first. + +DPA4 additionally exposes model embeddings from a training checkpoint: + +```bash +dp embed -m model.ckpt.pt -s /path/to/system -o embedding.hdf5 +``` + +`dp embed` supports the DPA4/SeZM `.pt` checkpoint and does not support `.pt2`. +For a multi-task checkpoint, preserve the selected head explicitly: + +```bash +dp embed -m model.ckpt.pt -s /path/to/system -o embedding.hdf5 --head SELECTED_BRANCH +``` + +## Validation + +- Confirm that the artifact exists and can be loaded in the target environment. +- Inspect the stored descriptor when `.pt` could mean DPA3 or DPA4. +- Confirm the type map before constructing `atype`. +- Run a small finite energy/force/virial evaluation before a large batch. +- Treat `.pt2` as a compiled deployment artifact, not a portable checkpoint. + Export and validate it with a device and toolchain compatible with the final + Python, C++, or LAMMPS runtime. + +## References + +- [DPA4 export, inference, and embeddings](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/dpa4.html) +- [Python inference](https://docs.deepmodeling.com/projects/deepmd/en/latest/inference/python.html) +- [Show model information](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/show-model-info.html) diff --git a/skills/deepmd-train/SKILL.md b/skills/deepmd-train/SKILL.md index d38e7858d7..6d5c685678 100644 --- a/skills/deepmd-train/SKILL.md +++ b/skills/deepmd-train/SKILL.md @@ -1,11 +1,11 @@ --- name: deepmd-train -description: Train DeePMD-kit models with progressive disclosure. Use when the user wants to train a DeePMD-kit potential, prepare an input.json, choose between model families such as se_e2_a/DeepPot-SE and DPA3, run `dp train`, monitor learning curves, freeze checkpoints, or test trained models. Start with model selection and read only the selected model reference under `models/` when model-specific configuration is needed. +description: Train DeePMD-kit models with progressive disclosure. Use when the user wants to train a DeePMD-kit potential, prepare an input.json, choose between model families such as se_e2_a/DeepPot-SE, DPA3, and DPA4/SeZM, run `dp train`, monitor learning curves, freeze checkpoints, or test trained models. Start with model selection and read only the selected model reference under `models/` when model-specific configuration is needed. compatibility: Requires deepmd-kit installed. The selected backend and model may require PyTorch, TensorFlow, JAX, Paddle, GPU support, or custom OP libraries. license: LGPL-3.0-or-later metadata: author: iProzd - version: '1.1' + version: '1.2' repository: https://github.com/deepmodeling/deepmd-kit --- @@ -33,6 +33,7 @@ Available model references: | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | [`models/se-e2-a.md`](models/se-e2-a.md) | The user wants a classical DeepPot-SE baseline, broad compatibility, or a smaller/established production model. | | [`models/dpa3.md`](models/dpa3.md) | The user wants a high-accuracy DPA3/LAM workflow, large/diverse datasets, dynamic neighbor selection, or pretrained DPA3-style training. | +| [`models/dpa4.md`](models/dpa4.md) | The user wants the PyTorch-only DPA4/SeZM SO(3)-equivariant architecture and its `.pt2` deployment path. | ## Model selection @@ -51,6 +52,7 @@ Recommended defaults: - Choose **se_e2_a** for a robust baseline, small to medium systems, compatibility-focused workflows, or when compute is limited. - Choose **DPA3** for high accuracy on diverse datasets, LAM-style training, or when the user explicitly asks for DPA3, DPA-3, LiGS, dynamic neighbor selection, or pretrained DPA3 variants. +- Choose **DPA4/SeZM** when the user explicitly requests it or wants its SO(3)-equivariant message-passing architecture and accepts a GPU-oriented, PyTorch-only workflow. ## Common workflow @@ -104,12 +106,16 @@ Training progress is usually written to `lcurve.out`. Check for: ### 6. Freeze and test +Read the selected model reference before choosing the output format. For +conventional PyTorch models, a typical flow is: + ```bash dp --pt freeze -o model.pth -dp --pt test -m model.pth -s /path/to/test_system -n 30 +dp test -m model.pth -s /path/to/test_system -n 30 ``` -Adjust the backend flags and output extension for non-PyTorch models. +DPA4/SeZM checkpoints instead freeze to `.pt2`; follow `models/dpa4.md`. +Adjust the backend and output format for other model families. ## Agent checklist diff --git a/skills/deepmd-train/models/dpa4.md b/skills/deepmd-train/models/dpa4.md new file mode 100644 index 0000000000..2abb71993c --- /dev/null +++ b/skills/deepmd-train/models/dpa4.md @@ -0,0 +1,115 @@ +# DPA4 training reference + +Read this file only after the user chooses DPA4/SeZM, or when it is the best fit +for the task. Keep shared data checks and the train/monitor workflow in +`../SKILL.md`; this file records DPA4-specific choices. + +## When to choose DPA4 + +Choose DPA4 when the user explicitly requests DPA4/SeZM or wants its +SO(3)-equivariant message-passing architecture and accepts a GPU-oriented, +PyTorch-only workflow. The aliases `DPA4`, `SeZM`, and `sezm` select the same +implementation. + +DPA4 is not selected merely because a checkpoint ends in `.pt`. Inspect an +existing checkpoint with: + +```bash +dp --pt show model.pt descriptor fitting-net type-map +``` + +## Minimal model configuration + +Start from the maintained example at `examples/water/dpa4/input.json`. A minimal +model section is: + +```json +{ + "model": { + "type": "dpa4", + "type_map": [ + "O", + "H" + ], + "descriptor": { + "rcut": 6.0 + }, + "fitting_net": { + "type": "dpa4_ener" + } + } +} +``` + +Both `model.descriptor` and `model.fitting_net` are required. DPA4 defaults to +`float32`; double precision is unnecessary and not recommended for the normal +workflow. + +## Parameters to choose deliberately + +- `rcut` sets the local environment cutoff. +- On the conservative energy path, `sel` is an initial neighbor-search capacity + that grows on demand; it does not truncate the neighbor list. It may also be + set to `auto` or `auto:factor` from training data. +- `lmax`/`l_schedule` and `mmax`/`m_schedule` control angular resolution and are + primary accuracy-cost levers. +- `n_blocks` controls depth; `channels` and `n_radial` control width. +- `n_focus` and `n_atten_head` control aggregation. + +Use documented defaults or a maintained example unless the user has evidence for +changing these parameters. Do not copy DPA3 descriptor parameters into DPA4. + +## Train and monitor + +Use the PyTorch backend: + +```bash +dp --pt train input.json +``` + +Monitor `lcurve.out`, validation metrics, checkpoint creation, and non-finite +values. DPA4 also supports advanced property, spin, denoising, ZBL, multitask, +and LoRA configurations; follow the DPA4 documentation and examples rather than +combining those features from memory. For checkpoint adaptation and LoRA, use +the `deepmd-finetune-dpa4` skill. + +## Freeze and test + +DPA4 checkpoints are `.pt`, but deployment uses an AOTInductor `.pt2` archive. +Read `../../deepmd-python-inference/references/dpa4-freeze-policy.md` and choose +the freeze-time inference policy before exporting: + +```bash +dp --pt freeze -c model.ckpt.pt -o frozen_model +dp test -m frozen_model.pt2 -s /path/to/test_system -n 30 +``` + +The command detects DPA4/SeZM and appends `.pt2`. DPA4 does not use the ordinary +TorchScript `.pth` freeze path and does not support model compression. Validate +the exported archive in the target inference or LAMMPS environment. + +If the checkpoint is multi-task, inspect its branches and pass the selected +head during export: + +```bash +dp --pt show model.ckpt.pt model-branch descriptor type-map +dp --pt freeze -c model.ckpt.pt -o frozen_model --head SELECTED_BRANCH +``` + +The frozen `.pt2` is a selected single-head artifact. + +## DPA4 checklist + +- [ ] The PyTorch backend is available. +- [ ] `model.type` is `dpa4`/`sezm`, or the stored checkpoint configuration proves it. +- [ ] `type_map`, data labels, and train/validation systems are consistent. +- [ ] Parameter changes are based on DPA4 documentation, not DPA3 defaults. +- [ ] Training and validation metrics are finite. +- [ ] The selected checkpoint is exported to `.pt2` and tested. +- [ ] `dp compress` is not used for DPA4. + +## References + +- [DPA4 model documentation](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/dpa4.html) +- [DPA4 training example](../../../examples/water/dpa4/input.json) +- [Energy model training](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/train-energy.html) diff --git a/skills/lammps-deepmd/SKILL.md b/skills/lammps-deepmd/SKILL.md index 4ec87c9adc..0305a05f92 100644 --- a/skills/lammps-deepmd/SKILL.md +++ b/skills/lammps-deepmd/SKILL.md @@ -1,13 +1,13 @@ --- name: lammps-deepmd description: > - A tool and knowledge base for running molecular dynamics (MD) simulations in LAMMPS with the DeePMD-kit plugin. It handles input script preparation, ensemble selection (NVE/NVT/NPT), and job execution via `uv` or offline binaries. - USE WHEN you need to set up, write, explain, or execute a LAMMPS molecular dynamics simulation using a DeePMD machine learning potential (e.g., `graph.pb`). -compatibility: Requires LAMMPS with DeePMD-kit support. Online mode prefers `uvx --from lammps --with deepmd-kit[gpu,torch,lmp] lmp`; offline mode requires a user-provided LAMMPS executable or module. + A tool and knowledge base for running molecular dynamics (MD) simulations in LAMMPS with the DeePMD-kit plugin. It handles input script preparation, ensemble selection (NVE/NVT/NPT), and execution with a verified DeePMD-enabled runtime. + USE WHEN you need to set up, write, explain, or execute a LAMMPS molecular dynamics simulation using a DeePMD machine learning potential (for example `.pb`, `.pth`, or DPA4/SeZM `.pt2`). +compatibility: Requires a user-provided, containerized, or source-built LAMMPS runtime with DeePMD-kit support. Verify capabilities in the target environment. license: LGPL-3.0-or-later metadata: author: OpenClaw - version: '1.0' + version: '1.1' repository: https://github.com/deepmodeling/deepmd-kit lammps_docs: https://docs.lammps.org/ --- @@ -18,51 +18,51 @@ Use this skill when the user wants to run molecular dynamics in LAMMPS with a De ## Agent responsibilities -1. Confirm the available execution mode: - - **Online mode**: if internet access is available and `uv` is installed, prefer - `uvx --from lammps --with deepmd-kit[gpu,torch,lmp] lmp ...` - - **Offline mode**: do **not** guess the executable. Ask the user which LAMMPS command, module, or container should be used. +1. Confirm the available execution runtime: + + - For a build from the current checkout, record the resolved Git commit SHA. + - For an installed binary, module, or container, record the exact command and + runtime versions. + - Do not infer capabilities from a future release or an artifact suffix. + 1. Confirm the minimum simulation inputs: + - structure/data file (for example `data.system`) - - DeePMD model file (for example `graph.pb` or compressed model) - - atom type to element mapping, including required per-type masses if the data file does not define them + - DeePMD model artifact; read `references/model-deployment.md` for a training + checkpoint, DPA4/SeZM, or an unclear export path + - atom type to element mapping, including required per-type masses if the data + file does not define them - target ensemble (NVE, NVT, NPT, or another explicitly requested setup) - temperature, pressure if applicable, timestep, and total number of steps -1. Write the LAMMPS input script yourself instead of asking the user to hand-write it. -1. Keep the example readable and fully explained. If you include an example input script, explain what **every command** does. -1. When possible, validate command availability against the LAMMPS docs or local `lmp -h` output before execution. -1. Report clearly which command was run, which files were used, and where outputs were written. - -## Decide the execution mode -### Online mode (preferred when internet access is available) - -Use: +1. Write the LAMMPS input script yourself instead of asking the user to hand-write it. -```bash -uvx --from lammps --with deepmd-kit[gpu,torch,lmp] lmp -in input.lammps -``` +1. Keep the example readable and fully explained. If you include an example input script, explain what **every command** does. -If you need to inspect the local command-line help: +1. When possible, validate command availability against the LAMMPS docs or local `lmp -h` output before execution. -```bash -uvx --from lammps --with deepmd-kit[gpu,torch,lmp] lmp -h | tee /dev/tty -``` +1. Report clearly which command was run, which files were used, and where outputs were written. -Notes: +## Verify the execution runtime -- This is the preferred path because it can provision LAMMPS and DeePMD-kit on demand. -- The `gpu,torch,lmp` extras match the requested runtime pattern from the user. -- If the environment is slow or the packages are large, warn the user that the first run may take time. +Use an existing site-installed binary, container, or build from the current +checkout. Before execution: -### Offline mode +- record `git rev-parse HEAD` for a source checkout, or record `dp --version` and + the exact installed package/container identity; +- inspect the selected LAMMPS command with `-h` and confirm that it provides the + required DeePMD pair style and model-artifact route; +- follow `references/model-deployment.md` for DPA4 `.pt2` and multi-rank + capability gates; +- do not install or upgrade packages silently, and do not claim support from an + unreleased version number. -If internet access is unavailable or the user explicitly wants a site-installed binary, ask a concrete question such as: +If no verified runtime is available, ask a concrete question such as: - "Which LAMMPS executable should I use, for example `lmp`, `lmp_mpi`, `mpirun -np 8 lmp`, or an HPC module command?" -- "Do you already have a DeePMD-enabled LAMMPS build on this machine or cluster?" +- "Do you already have a DeePMD-enabled LAMMPS build or container on this machine or cluster?" -Do not invent a binary name or module name. +Do not invent a binary, module, container, or package version. ## Minimal information to collect @@ -76,14 +76,15 @@ Ask only for what is missing: - timestep - run length in steps - whether velocities should be generated from scratch -- preferred execution command if offline +- execution command, module, container, or source checkout ## Recommended workflow 1. Inspect available files in the working directory. +1. Read `references/model-deployment.md` when the model needs export, its artifact type is unclear, or explicit element mapping is required. 1. Draft `input.lammps`. 1. Explain the script to the user if they asked for an explanation or if the script is nontrivial. -1. Run a short smoke test first when reasonable. +1. Follow the staged canary in `references/commands-and-workflow.md` before production. 1. Run the full simulation. 1. Summarize outputs such as `log.lammps`, dump trajectories, restart files, and thermodynamic data. @@ -104,15 +105,17 @@ atom_style atomic neighbor 1.0 bin +atom_modify map yes read_data data.system mass 1 28.0855 mass 2 15.999 pair_style deepmd graph_compressed.pb -pair_coeff * * +pair_coeff * * Si O thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz thermo ${THERMO_FREQ} -dump 1 all custom ${DUMP_FREQ} traj.lammpstrj id type x y z +dump 1 all custom ${DUMP_FREQ} traj.lammpstrj id type element x y z +dump_modify 1 element Si O sort id velocity all create ${TEMP} 743574 fix 1 all nvt temp ${TEMP} ${TEMP} ${TAU_T} @@ -169,9 +172,15 @@ run ${NSTEPS} - Uses the `bin` neighbor-building method. - Neighbor lists help LAMMPS efficiently find nearby atoms for force evaluation. +- `atom_modify map yes` + + - Creates an atom-ID map required by the documented DPA4 route. + - It must appear before `read_data`. + - `read_data data.system` - Reads the initial atomic structure, atom types, simulation box, and related information from the LAMMPS data file `data.system`. + - The data file's first line is a skipped title; actual header counts begin after it. - Replace this filename with the actual user file. - `mass 1 28.0855`, `mass 2 15.999` @@ -185,10 +194,11 @@ run ${NSTEPS} - Loads the DeePMD model from `graph_compressed.pb`. - Replace the model filename with the actual model path, for example `graph.pb`, `graph-compress.pb`, or another supported exported model. -- `pair_coeff * *` +- `pair_coeff * * Si O` - - Activates the previously selected pair style for all atom types. - - For DeePMD this often takes the simple form `* *` because the mapping is embedded in the model workflow rather than through conventional pairwise parameters. + - Activates the pair style for all local atom types. + - Maps LAMMPS type 1 to `Si` and type 2 to `O`, matching the masses and dump labels. + - Inspect the actual model type map and replace this example order; do not infer it from integer type IDs. - `thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz` @@ -207,14 +217,15 @@ run ${NSTEPS} - Prints the thermo block every `THERMO_FREQ` timesteps. -- `dump 1 all custom ${DUMP_FREQ} traj.lammpstrj id type x y z` +- `dump 1 all custom ${DUMP_FREQ} traj.lammpstrj id type element x y z` - - Creates dump ID `1`. - - Dumps atoms from group `all`. - - Uses the `custom` dump format. - - Writes every `DUMP_FREQ` steps. - - Saves to `traj.lammpstrj`. - - Outputs per-atom columns `id type x y z`. + - Creates dump ID `1` and writes every `DUMP_FREQ` steps. + - Saves `id`, local type, mapped element, and coordinates to `traj.lammpstrj`. + +- `dump_modify 1 element Si O sort id` + + - Uses the same local type-to-element order as `pair_coeff`. + - Sorts each frame by stable atom ID, not by element or model type-map position. - `velocity all create ${TEMP} 743574` @@ -277,21 +288,9 @@ When using NPT, it is often useful to keep `vol`, `lx`, `ly`, and `lz` in the th ## Execution templates -### Online run - -```bash -uvx --from lammps --with deepmd-kit[gpu,torch,lmp] lmp -in input.lammps -``` - -### Online help - -```bash -uvx --from lammps --with deepmd-kit[gpu,torch,lmp] lmp -h | tee /dev/tty -``` - -### Offline run +### Verified run -Only after the user specifies the executable, use a command such as one of these exact patterns: +Only after the runtime is identified, use the matching command, for example: ```bash lmp -in input.lammps @@ -299,7 +298,7 @@ mpirun -np 8 lmp_mpi -in input.lammps srun lmp -in input.lammps ``` -The agent must not choose one of these on its own without user guidance in offline mode. +Do not choose one of these without evidence that it is the verified runtime. ## Output checklist @@ -321,3 +320,4 @@ After a run, report at least: - DeePMD-kit: https://github.com/deepmodeling/deepmd-kit - User-provided tutorial reference: https://github.com/tongzhugroup/Chapter13-tutorial/blob/master/input.lammps - Detailed notes: `references/commands-and-workflow.md` +- Model artifact, export, and type-mapping notes: `references/model-deployment.md` diff --git a/skills/lammps-deepmd/assets/input.nvt.lammps b/skills/lammps-deepmd/assets/input.nvt.lammps index 90317704dd..c751ee0def 100644 --- a/skills/lammps-deepmd/assets/input.nvt.lammps +++ b/skills/lammps-deepmd/assets/input.nvt.lammps @@ -7,6 +7,7 @@ variable TAU_T equal 0.1 units metal boundary p p p atom_style atomic +atom_modify map yes neighbor 1.0 bin @@ -14,11 +15,12 @@ read_data data.system mass 1 28.0855 mass 2 15.999 pair_style deepmd graph_compressed.pb -pair_coeff * * +pair_coeff * * Si O thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz thermo ${THERMO_FREQ} -dump 1 all custom ${DUMP_FREQ} traj.lammpstrj id type x y z +dump 1 all custom ${DUMP_FREQ} traj.lammpstrj id type element x y z +dump_modify 1 element Si O sort id velocity all create ${TEMP} 743574 fix 1 all nvt temp ${TEMP} ${TEMP} ${TAU_T} diff --git a/skills/lammps-deepmd/references/commands-and-workflow.md b/skills/lammps-deepmd/references/commands-and-workflow.md index 7365057d17..48edb9ebb8 100644 --- a/skills/lammps-deepmd/references/commands-and-workflow.md +++ b/skills/lammps-deepmd/references/commands-and-workflow.md @@ -7,38 +7,45 @@ This reference expands the main skill with practical operating guidance. 1. Prefer small, explicit input scripts over clever but opaque templates. 1. Explain every command in the example script, because many users treat the example as a starting point for their own production run. 1. If the user asks to run a simulation, always confirm the structure file and DeePMD model file before execution. -1. If the user asks for offline execution, ask which exact LAMMPS command should be used instead of guessing. +1. Ask which exact LAMMPS command, module, container, or source-built runtime should be used instead of guessing or installing one silently. +1. Keep shell environment variables and LAMMPS variables distinct; pass values + with an explicit LAMMPS mechanism instead of copying shell syntax into input. +1. Keep a vacuum or nonperiodic slab axis fixed; do not barostat that direction + unless the scientific task explicitly requires changing it. 1. If the user only asks for a template, do not overcomplicate it with advanced computes or fixes unless they are needed. -## Suggested smoke test strategy +## Suggested canary strategy -Before a long production run, consider a short test such as: +Before a long production run, stage validation as: -```lammps -run 100 +```text +run 0 -> short NVE when physically appropriate -> short requested ensemble -> production ``` -This helps catch obvious issues such as: +Check the complete LAMMPS exit code and log at every stage. A canary passes only +when the model loads, thermodynamic values are finite, the atom count is stable, +and early temperature, pressure, and controlled variables are physically +compatible with the initial state. Exit code zero alone is insufficient. -- missing model file -- unsupported pair style in the local LAMMPS build -- malformed data file -- missing per-type masses in the data file or input script -- immediate numerical instability +This catches obvious issues such as: -Then replace the short run with the intended production length. +- unsupported model artifact or pair style in the selected runtime; +- malformed data headers, boxes, coordinates, or triclinic tilt factors; +- missing masses or inconsistent element/type mapping; +- immediate numerical instability or lost atoms. ## Typical files in a DeePMD-LAMMPS job - `input.lammps`: input script - `data.system`: atomic structure and box -- `graph.pb` or `graph_compressed.pb`: DeePMD model +- a supported DeePMD deployment artifact such as `.pb`, `.pth`, or DPA4/SeZM `.pt2`; see `model-deployment.md` - `log.lammps`: main textual log - `traj.lammpstrj`: trajectory output ## Caution points - The correct timestep depends on the physical system and the DeePMD model quality. +- The first line of a LAMMPS data file is a skipped title; put header counts after it. - Ensure every atom type has a mass, either in the LAMMPS data file `Masses` section or via explicit `mass` commands after `read_data`. - `velocity ... create ...` should usually not be repeated when continuing from a restart. - NPT settings need physically sensible damping constants; avoid copying values blindly. diff --git a/skills/lammps-deepmd/references/model-deployment.md b/skills/lammps-deepmd/references/model-deployment.md new file mode 100644 index 0000000000..70602e7cbd --- /dev/null +++ b/skills/lammps-deepmd/references/model-deployment.md @@ -0,0 +1,143 @@ +# DeePMD model deployment in LAMMPS + +Read this reference when choosing a model artifact, exporting a checkpoint, or +mapping LAMMPS atom types to model elements. General simulation setup and +execution remain in `commands-and-workflow.md`. + +## Choose the model artifact + +A training checkpoint is not automatically a LAMMPS deployment artifact. The +`.pt` suffix also does not distinguish DPA3 from DPA4. Inspect an unfamiliar +PyTorch checkpoint before choosing an export path: + +```bash +dp --pt show model.pt descriptor fitting-net type-map +``` + +| Model artifact | Deployment route | +| ---------------------------------- | --------------------------------------------------------------------------------- | +| TensorFlow frozen `.pb` | Use directly with a compatible `pair_style deepmd`. | +| Conventional PyTorch frozen `.pth` | Use directly with a compatible DeePMD-enabled LAMMPS build. | +| PyTorch checkpoint `.pt` | Inspect the stored model configuration and freeze using its model-specific route. | +| AOTInductor archive `.pt2` | Inspect its metadata and use only with a compatible DeePMD-enabled LAMMPS build. | + +Do not call a DPA4 `.pt2` archive a compressed model: DPA4 does not support +`dp compress`. + +## DPA4/SeZM deployment + +Before export, read +`../../deepmd-python-inference/references/dpa4-freeze-policy.md` and explicitly +choose the freeze-time inference environment. Then freeze a DPA4/SeZM checkpoint +with the standard PyTorch command: + +```bash +dp --pt freeze -c model.ckpt.pt -o frozen_model +``` + +The backend detects DPA4/SeZM and writes `frozen_model.pt2`. Validate the archive +in the actual target environment. For a multi-task checkpoint, select the head +during export: + +```bash +dp --pt freeze -c model.ckpt.pt -o frozen_model --head SELECTED_BRANCH +``` + +Create and consume the archive on the same target physical compute node and +allocation: inspect the native checkpoint -> freeze `.pt2` -> `run 0` -> bounded +MD -> production. Do not freeze in job or node A and move the archive to B unless +portability has been independently validated for that exact device and toolchain. + +Two DPA4 `.pt2` export contracts exist. `dp --pt freeze` uses the DPA4-specific +`edge_vec` ABI. `dp --pt_expt freeze --lower-kind graph` uses the NeighborGraph +ABI. They share a suffix but are not interchangeable contracts, and a `.pt2` +suffix alone does not prove multi-rank support. A multi-rank archive must report +`has_comm_artifact=true` and contain +`model/extra/forward_lower_with_comm.pt2`. + +A basic energy-model input uses: + +```lammps +atom_style atomic +atom_modify map yes +read_data data.system + +pair_style deepmd frozen_model.pt2 +pair_coeff * * O H +``` + +`atom_modify map yes` must appear before `read_data` for the documented DPA4 +route. Ordinary DPA4 energy models use `pair_style deepmd`; spin models may +require a different documented route and must not be treated as ordinary energy +models without inspection. + +Single-rank DPA4 execution is covered for supported `edge_vec`, graph, and +dense/nlist archives. Multi-rank execution is supported only when the archive +contains the with-communication artifact required by its ABI; fail closed when +that metadata or nested artifact is absent. + +## Atom-type mapping + +LAMMPS atom types, dataset type indices, and model types are separate namespaces. +Inspect the artifact's ordered type map, for example with +`dp --pt show model.pt type-map`, and treat element identity as the bridge. +For DeePMD data with `type_map.raw`, decode each zero-based `type.raw` index +through that ordered map. Without `type_map.raw`, require provenance that dataset +indices already follow the candidate model's ordered type map. Fail closed when +neither contract is established; do not reuse a dataset integer as a LAMMPS type. + +Use compact one-based LAMMPS types for the elements present in the structure and +write the same element order in masses, `pair_coeff`, and dump metadata: + +```lammps +mass 1 15.999 +mass 2 1.008 +pair_coeff * * O H +dump 1 all custom 100 traj.lammpstrj id type element x y z +dump_modify 1 element O H sort id +``` + +Here LAMMPS type 1 maps to `O` and type 2 maps to `H`. `dump_modify ... element` +labels each local type with that same mapping, while `sort id` gives a stable +per-frame atom order. Do not sort atoms by element or model type-map position. +Require that: + +- every LAMMPS atom type has a mass; +- every mapped element is supported by the inspected model type map; +- `pair_coeff`, masses, and dump element labels share one LAMMPS type order; +- the structure's atom and species counts are unchanged during conversion. + +An implicit `pair_coeff * *` is acceptable only when the model and LAMMPS type +orders have been verified to match. Prefer explicit element names for auditable +workflows. + +## LAMMPS data and box checks + +- The first line of a LAMMPS data file is a title and is skipped by `read_data`; + place the actual header counts after it. +- Put `atom_modify map yes` before `read_data` for the documented DPA4 route. +- For a restricted triclinic box, preserve the tilt mapping `xy = b_x`, + `xz = c_x`, and `yz = c_y`; never write `c_z` or `lz` into `yz`. +- After conversion, compare atom count, species counts, and box volume with the + source structure before running dynamics. + +## Pre-production validation + +1. Confirm the model loads without format or backend errors. +1. Keep DPA4 freeze, `run 0`, canary, and production on the same target physical + compute node and allocation unless exact artifact portability is proven. +1. For multi-rank execution, verify the archive's communication metadata and + nested with-comm artifact before launching MPI. +1. Stage `run 0` -> short NVE when physically appropriate -> short requested + ensemble -> production; do not jump from a successful load to a long run. +1. Require finite thermodynamics, stable atom count, and no mapping, box, or + lost-atom errors. Exit code zero alone is not a passed canary. +1. Require early temperature, pressure, and controlled variables to remain + physically compatible with the initial state and requested ensemble. +1. Preserve the generated data and input files, model path and SHA256, runtime + identity, command, complete log, and true exit code. + +## References + +- [DPA4 export and LAMMPS](https://docs.deepmodeling.com/projects/deepmd/en/latest/model/dpa4.html) +- [DeePMD-kit LAMMPS commands](https://docs.deepmodeling.com/projects/deepmd/en/latest/third-party/lammps-command.html) diff --git a/source/tests/common/test_agent_skills.py b/source/tests/common/test_agent_skills.py new file mode 100644 index 0000000000..d55e8de3c1 --- /dev/null +++ b/source/tests/common/test_agent_skills.py @@ -0,0 +1,264 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import json +import os +import re +import shutil +import subprocess +from pathlib import ( + Path, +) + +import pytest + +ROOT = Path(__file__).resolve().parents[3] +LAMMPS_SKILL = ROOT / "skills" / "lammps-deepmd" / "SKILL.md" +LAMMPS_DEPLOYMENT = ( + ROOT / "skills" / "lammps-deepmd" / "references" / "model-deployment.md" +) +LAMMPS_WORKFLOW = ( + ROOT / "skills" / "lammps-deepmd" / "references" / "commands-and-workflow.md" +) +LAMMPS_ASSET = ROOT / "skills" / "lammps-deepmd" / "assets" / "input.nvt.lammps" +DPA4_TRAIN_REFERENCE = ROOT / "skills" / "deepmd-train" / "models" / "dpa4.md" +DPA4_FREEZE_POLICY = ( + ROOT / "skills" / "deepmd-python-inference" / "references" / "dpa4-freeze-policy.md" +) +DPA4_FINETUNE_SKILL = ROOT / "skills" / "deepmd-finetune-dpa4" / "SKILL.md" +INFERENCE_SKILL = ROOT / "skills" / "deepmd-python-inference" / "SKILL.md" +HELD_OUT_REFERENCE = ( + ROOT + / "skills" + / "deepmd-python-inference" + / "references" + / "held-out-evaluation.md" +) +DP_TEST_ENTRYPOINT = ROOT / "deepmd" / "entrypoints" / "test.py" +ENERGY_TESTER = ROOT / "deepmd" / "infer" / "model_test" / "ener.py" +FINETUNE_SOURCE = ROOT / "deepmd" / "utils" / "finetune.py" + + +def test_lammps_skill_uses_capability_gated_runtime() -> None: + text = LAMMPS_SKILL.read_text(encoding="utf-8") + + assert "3.2.0b0" not in text + assert "uvx --from" not in text + assert "record the resolved Git commit SHA" in text + assert "do not claim support from an" in text + assert "unreleased version number" in text + assert "do not install or upgrade packages silently" in text + + +def test_lammps_required_inputs_remain_nested() -> None: + text = LAMMPS_SKILL.read_text(encoding="utf-8") + section = text.split("1. Confirm the minimum simulation inputs:", 1)[1].split( + "1. Write the LAMMPS input script", 1 + )[0] + + for required in ( + "structure/data file", + "DeePMD model artifact", + "atom type to element mapping", + "target ensemble", + "temperature, pressure", + ): + assert any( + line.startswith(" - ") and required in line + for line in section.splitlines() + ) + + +def test_complete_held_out_evaluation_is_routed_and_evidence_complete() -> None: + finetune = DPA4_FINETUNE_SKILL.read_text(encoding="utf-8") + inference = INFERENCE_SKILL.read_text(encoding="utf-8") + held_out = HELD_OUT_REFERENCE.read_text(encoding="utf-8") + + assert "references/held-out-evaluation.md" in inference + assert "held-out-evaluation.md" in finetune + assert "dp --pt test -m selected.pt" in held_out + assert '-n 0 -d "$detail_prefix"' in held_out + assert "one command per held-out system" in held_out + assert "population standard deviation (`ddof=0`)" in held_out + assert "do not average per-system RMSE values" in held_out + assert "Training logs, a successful freeze" in held_out + + +def test_complete_held_out_evaluation_checks_dataset_shapes() -> None: + held_out = HELD_OUT_REFERENCE.read_text(encoding="utf-8") + + assert "number of whitespace-separated entries in `type.raw`" in held_out + assert "coordinate and force widths of `3 * natoms`" in held_out + assert "force rows equal `frames * natoms`" in held_out + assert "divided by `natoms` exactly once" in held_out + assert "zero-based indices" in held_out + + +def test_held_out_contract_matches_dp_test_source() -> None: + entrypoint = DP_TEST_ENTRYPOINT.read_text(encoding="utf-8") + energy_tester = ENERGY_TESTER.read_text(encoding="utf-8") + + assert "if numb_test == 0:" in entrypoint + assert 'detail_path.with_suffix(".e.out")' in energy_tester + assert 'detail_path.with_suffix(".e_peratom.out")' in energy_tester + assert 'detail_path.with_suffix(".f.out")' in energy_tester + + +def test_dpa4_freeze_and_lammps_stay_on_target_node() -> None: + deployment = LAMMPS_DEPLOYMENT.read_text(encoding="utf-8") + + assert "same target physical compute node" in deployment + assert "inspect the native checkpoint -> freeze `.pt2` -> `run 0`" in deployment + assert "move the archive to B" in deployment + assert "artifact portability is proven" in deployment + + +def test_lammps_mapping_data_and_dump_contract() -> None: + skill = LAMMPS_SKILL.read_text(encoding="utf-8") + deployment = LAMMPS_DEPLOYMENT.read_text(encoding="utf-8") + workflow = LAMMPS_WORKFLOW.read_text(encoding="utf-8") + example = skill.split("## Example: annotated NVT input", 1)[1].split( + "### What every command means", 1 + )[0] + + assert example.index("atom_modify map yes") < example.index( + "read_data data.system" + ) + assert "pair_coeff * * Si O" in example + assert "dump_modify 1 element Si O sort id" in example + assert "zero-based `type.raw` index" in deployment + assert "Do not sort atoms by element" in deployment + assert "`xy = b_x`" in deployment + assert "`xz = c_x`" in deployment + assert "`yz = c_y`" in deployment + assert "first line of a LAMMPS data file is a title" in deployment + assert "first line of a LAMMPS data file is a skipped title" in workflow + + +def test_lammps_canary_requires_physical_stability() -> None: + deployment = LAMMPS_DEPLOYMENT.read_text(encoding="utf-8") + workflow = LAMMPS_WORKFLOW.read_text(encoding="utf-8") + + assert "short NVE when physically appropriate" in deployment + assert "Exit code zero alone is not a passed canary" in deployment + assert "early temperature, pressure, and controlled variables" in deployment + assert "do not barostat that direction" in workflow + assert "shell environment variables and LAMMPS variables distinct" in workflow + + +def test_held_out_command_runs_from_clean_directory_without_overwrite( + tmp_path: Path, +) -> None: + held_out = HELD_OUT_REFERENCE.read_text(encoding="utf-8") + command = held_out.split("```bash", 1)[1].split("```", 1)[0].strip() + bash = shutil.which("bash") + assert bash is not None + + fake_bin = tmp_path / "bin" + fake_bin.mkdir() + fake_dp = fake_bin / "dp" + fake_dp.write_text( + """#!/bin/sh +while [ "$#" -gt 0 ]; do + if [ "$1" = "-d" ]; then + shift + detail_prefix=$1 + fi + shift +done +: "${detail_prefix:?missing detail prefix}" +touch "${detail_prefix}.e.out" "${detail_prefix}.e_peratom.out" \ + "${detail_prefix}.f.out" +""", + encoding="utf-8", + ) + fake_dp.chmod(0o755) + env = os.environ.copy() + env["PATH"] = f"{fake_bin}{os.pathsep}{env['PATH']}" + + first = subprocess.run( + [bash, "-eu", "-c", command], cwd=tmp_path, env=env, check=False + ) + second = subprocess.run( + [bash, "-eu", "-c", command], cwd=tmp_path, env=env, check=False + ) + + assert first.returncode == 0 + assert second.returncode != 0 + assert (tmp_path / "details" / "selected-SHA256" / "system.000.e.out").is_file() + + +def test_dpa4_minimal_model_configuration_normalizes() -> None: + pytest.importorskip("deepmd.lib", reason="requires a built DeePMD checkout") + from deepmd.utils.argcheck import ( + normalize, + ) + from deepmd.utils.compat import ( + update_deepmd_input, + ) + + text = DPA4_TRAIN_REFERENCE.read_text(encoding="utf-8") + section = text.split("## Minimal model configuration", 1)[1] + fenced_json = re.search(r"```json\n(.*?)\n```", section, flags=re.DOTALL) + assert fenced_json is not None + model_fragment = json.loads(fenced_json.group(1)) + config = { + **model_fragment, + "training": { + "training_data": {"systems": ["dummy"]}, + "numb_steps": 1, + }, + "loss": {"type": "ener"}, + "learning_rate": {"type": "exp", "start_lr": 1e-3}, + } + + normalized = normalize(update_deepmd_input(config, warning=False)) + + assert normalized["model"]["fitting_net"]["type"] == "dpa4_ener" + + +def test_lammps_asset_matches_mapping_contract() -> None: + asset = LAMMPS_ASSET.read_text(encoding="utf-8") + + assert asset.index("atom_modify map yes") < asset.index( + "read_data data.system" + ) + assert "pair_coeff * * Si O" in asset + assert "id type element x y z" in asset + assert "dump_modify 1 element Si O sort id" in asset + + +def test_dpa4_freeze_policy_is_explicit_and_routed() -> None: + policy = DPA4_FREEZE_POLICY.read_text(encoding="utf-8") + train = DPA4_TRAIN_REFERENCE.read_text(encoding="utf-8") + finetune = DPA4_FINETUNE_SKILL.read_text(encoding="utf-8") + deployment = LAMMPS_DEPLOYMENT.read_text(encoding="utf-8") + + for variable in ("DP_TRITON_INFER", "DP_TF32_INFER", "DP_AMP_INFER"): + assert f"export {variable}=" in policy + assert "Levels 1 and 2 keep" in policy + assert "Level 3, TF32, and AMP" in policy + assert "dpa4-freeze-policy.md" in train + assert "dpa4-freeze-policy.md" in finetune + assert "dpa4-freeze-policy.md" in deployment + + +def test_held_out_multitask_and_optional_type_map_contracts() -> None: + held_out = HELD_OUT_REFERENCE.read_text(encoding="utf-8") + + assert "When `type_map.raw` is present" in held_out + assert "is absent, require provenance" in held_out + assert "--head SELECTED_BRANCH" in held_out + assert "already single-head; do not pass `--head`" in held_out + + +def test_use_pretrain_script_guidance_matches_source_scope() -> None: + guidance = DPA4_FINETUNE_SKILL.read_text(encoding="utf-8") + source = FINETUNE_SOURCE.read_text(encoding="utf-8") + function = source.split("def _apply_pretrained_model_params", 1)[1].split( + "\ndef ", 1 + )[0] + + assert "does not restore the complete model" in guidance + assert "model.descriptor" in guidance + assert "model.fitting_net" in guidance + assert 'pretrained_config["descriptor"]' in function + assert 'pretrained_config["fitting_net"]' in function