deepmodeling / deepmodeling/deepmd-kit
Deprecate descriptor-scoped exclude_types in favour of the model-level build-seam owner
- Dominant language
- Python
- Stars
- 2k
- Forks
- 649
- Avg merge
- 6d 18h
- Merged PRs (30d)
- 15
Description
Since #5733 pair exclusion is a graph-native transform, but there are still **two owners with two different scopes**, and one builder silently promotes between them. That promotion makes two otherwise-equivalent model builders disagree by ~80 eV on the same input.
### The two owners
| key | applied where | scope |
|---|---|---|
| model-level `pair_exclude_types` | graph **build** seam, folded into the graph before the atomic model sees it | every child of the composition, **including analytical bridging (ZBL)** |
| descriptor-level `exclude_types` | inside the descriptor forward, `apply_pair_exclusion(graph, atype, self.emask)` | the learned descriptor features only |
Application sites for the descriptor-scoped key: `deepmd/dpmodel/descriptor/dpa4.py:1514`, `deepmd/dpmodel/descriptor/dpa1.py:1866`, `deepmd/dpmodel/descriptor/repformers.py:622`.
The split is already documented in `deepmd/dpmodel/descriptor/dpa4_nn/edge_cache.py:279`:
> Model-level `pair_exclude_types` is a separate, graph-BUILD transform, already folded into the incoming graph.
### The promotion
`get_sezm_model` copies the descriptor-scoped key into the model-scoped one, writes it back down onto the descriptor, and raises if both are set to different values:
- `deepmd/pt_expt/model/get_model.py:148-162`
- `deepmd/pt/model/model/__init__.py:388-403` (identical)
`get_standard_model` does not do this, in either pt_expt or dpmodel.
### Observable consequence
Same config in both builders — `descriptor.exclude_types=[[0,1]]`, `bridging_method: ZBL`, `bridging_r_inner: 0.8`, `bridging_r_outer: 1.2`, `type_map: [Ni, O]` — evaluated on a 0.9 A Ni-O dimer:
| route | energy |
|---|---|
| `type: "dpa4"` (promotes) | -0.909 eV |
| `type: "standard"` (does not) | +79.056 eV |
dE = 79.97 eV, max|dF| = 318.48 eV/A. The difference is entirely whether the analytical ZBL child still sees the excluded pair. Surfaced during review of #5939.
### Why the promotion is the wrong side to keep
A descriptor-scoped setting should stay descriptor-scoped. The promotion also forecloses a physically meaningful configuration: hiding a pair from the network while keeping its real short-range nuclear repulsion. And because only one of the two builders promotes, "which builder did you use" silently changes the physics.
### Proposal
1. Emit a `DeprecationWarning` when `descriptor.exclude_types` is set, directing users to model-level `pair_exclude_types`.
2. Remove the promotion from `get_sezm_model` in **pt and pt_expt together**, so the backends cannot diverge mid-flight.
3. Leave `pair_exclude_types` as the single build-seam owner; at that point there is nothing left to reconcile and every builder agrees by construction.
4. Cover it in the cross-backend consistency harness (a data row exercising descriptor-only vs model-level exclusion), not a bespoke test, so a backend that skips the seam is visible.
### Backwards compatibility
Step 2 is a behaviour change for existing dpa4/sezm configs that set only `descriptor.exclude_types` and rely on it reaching the bridging term — their energies will change. Hence the staged warning first. Configs that set `pair_exclude_types` explicitly are unaffected.
Contributor guide
Assessment
This issue has not been assessed yet.