Skip to content

refactor(pt/dpa4): use edge schema for dpa4 and ignore sel#5562

Open
OutisLi wants to merge 4 commits into
deepmodeling:masterfrom
OutisLi:pr/dpa4edge
Open

refactor(pt/dpa4): use edge schema for dpa4 and ignore sel#5562
OutisLi wants to merge 4 commits into
deepmodeling:masterfrom
OutisLi:pr/dpa4edge

Conversation

@OutisLi

@OutisLi OutisLi commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added edge-based neighbor list representation for improved model inference efficiency.
    • Extended neighbor list builders with optional edge-schema output mode.
  • Bug Fixes

    • Improved force computation consistency across bridging potentials.
  • Improvements

    • Enhanced model compilation with optimized tensor indexing.
    • Updated model export pipeline for better performance handling.
    • Added support for uncapped neighbor retention in list building.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Replaces the SeZM/DPA4 extended-coordinate neighbor-list input contract with a compact edge-vector schema (EdgeNeighborList) end-to-end. Adds EdgeNeighborList dataclass and schema builders, refactors SeZM model lower interfaces and compile/trace paths, updates Python inference/freeze pipelines, extends C++ DeepPotPTExpt with edge-schema tensor packing and dual dispatch, and adds aligned tests throughout.

Changes

SeZM/DPA4 Edge-Vector Schema Migration

Layer / File(s) Summary
EdgeNeighborList contract and neighbor-list API extensions
deepmd/dpmodel/utils/neighbor_list.py, deepmd/dpmodel/utils/default_neighbor_list.py, deepmd/pt/utils/nlist.py
EdgeNeighborList dataclass is introduced with coord, atype, edge_index, edge_vec, edge_scatter_index, edge_mask fields. NeighborList.build and DefaultNeighborList.build gain a return_mode parameter; DefaultNeighborList raises NotImplementedError for non-extended modes. build_neighbor_list gains cap_neighbors to dynamically size neighbor count when uncapped.
Edge schema builders and backend return_mode wiring
deepmd/pt_expt/utils/edge_schema.py, deepmd/pt_expt/utils/vesin_neighbor_list.py, deepmd/pt/utils/nv_nlist.py
New edge_schema.py provides four public edge builders: edge_schema_from_extended, edge_schema_from_neighbor_matrix, edge_schema_from_ij_shifts, merge_frame_edge_schemas, each appending dummy edges for export stability. VesinNeighborList.build and NvNeighborList.build gain return_mode="edges" support via these builders. NvNeighborList adds device-aware method selection and max_atoms_per_system override; CPU stderr suppression is added for native Warp import errors.
SeZMModel and SeZMSpinModel lower-path refactor
deepmd/pt/model/model/sezm_model.py, deepmd/pt/model/model/sezm_spin_model.py
forward_common_lower, core_compute, forward_lower, trace_and_compile, and forward_common_lower_exportable are updated to accept compact edge tensors (edge_index, edge_vec, edge_scatter_index, edge_mask) instead of extended DeePMD inputs. edge_vec.detach().requires_grad_(True) becomes the sole autograd leaf; edge_scatter_index drives edge_energy_deriv. SeZMSpinModel removes do_atomic_virial from lower-interface signatures and inlines edge_schema_from_extended construction. build_neighbor_list returns EdgeNeighborList; build_edge_list_from_nlist delegates to edge_schema_from_extended. check_compile_torch_version() guards are added to compile entry points.
Global Inductor int64-indexing patch
deepmd/pt/utils/compile_compat.py
Adds patch_inductor_force_int64_indexing() that monkeypatches SIMDScheduling.can_use_32bit_indexing to always return False, applied unconditionally in apply_global_compile_patches. Updates triton.max_tiles documentation in build_inductor_compile_options.
PT inference and freeze pipeline edge-input migration
deepmd/pt/infer/deep_eval.py, deepmd/pt/entrypoints/freeze_pt2.py
DeepEval adds _uses_edge_schema and branches _eval_lower_strategy to build edge tensors and call forward_common_lower with edge inputs for non-spin SeZM models. freeze_sezm_to_pt2 reworks _make_sample_inputs to output edge-schema tensors, updates _build_dynamic_shapes with nedge dynamic dim, and forces do_atomic_virial metadata True for non-spin exports.
pt_expt lower_input_kind detection and edge preparation
deepmd/pt_expt/infer/deep_eval.py
Adds _is_pt_backend_dpa4_params detector, rejects DPA4/SeZM .pt checkpoints with ValueError, sets lower_input_kind: "nlist" for eager .pt models. Adds _build_edge_inputs_from_nlist conversion helper, edge fast-path in _prepare_inputs, and _prepare_optional_lower_inputs. eval_descriptor/eval_fitting_last_layer switch to _prepare_nlist_inputs.
C++ edge tensor packing and PTExpt edge dispatch
source/api_cc/include/commonPT.h, source/api_cc/include/DeepPotPTExpt.h, source/api_cc/src/DeepPotPTExpt.cc
commonPT.h adds EdgeTensorPack, createEdgeTensors, and compactEdgeTensors. DeepPotPTExpt adds lower_input_is_edge_ flag, cached edge tensor members, and run_model_edges. Both compute overloads conditionally build edge tensors or padded neighbor-list tensors and dispatch to run_model_edges vs run_model. Multi-rank comm path fails fast in edge-schema mode.
Configuration, docs, and test updates
deepmd/utils/argcheck.py, examples/water/dpa4/input.json, source/api_cc/tests/..., source/tests/pt/model/...
SeZM sel default changes to 256 with updated energy-path non-truncation docs; example drops explicit sel. C++ tests add TestEdgeTensorPack unit tests and skin-nlist cpu_lmp_nlist_skin_below_model_width inference tests. Python tests add TestEdgeSchemaConsistency for cross-builder edge agreement, update test_sezm_export to edge-based forward wiring and lower_input_kind metadata assertions, and replace bridged-boundary energy smoothness checks with force-consistency checks.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant DeepEval
  participant NeighborListBuilder
  participant SeZMModel
  participant core_compute

  rect rgba(70, 130, 180, 0.5)
    Note over DeepEval,core_compute: Edge-schema path (_uses_edge_schema=True)
    Caller->>DeepEval: eval(coord, atype, box)
    DeepEval->>NeighborListBuilder: build(return_mode="edges")
    NeighborListBuilder-->>DeepEval: EdgeNeighborList
    DeepEval->>SeZMModel: forward_common_lower(coord, atype, edge_index, edge_vec, edge_scatter_index, edge_mask)
    SeZMModel->>core_compute: edge_vec.detach().requires_grad_(True)
    core_compute-->>SeZMModel: energy, forces via edge_scatter_index
    SeZMModel-->>DeepEval: predict dict
    DeepEval-->>Caller: energy, forces, virial
  end

  rect rgba(180, 70, 70, 0.5)
    Note over DeepEval,core_compute: Extended path (_uses_edge_schema=False)
    Caller->>DeepEval: eval(coord, atype, box)
    DeepEval->>NeighborListBuilder: build(return_mode="extended")
    NeighborListBuilder-->>DeepEval: ext_coord, ext_atype, nlist, mapping
    DeepEval->>SeZMModel: forward_common_lower(ext_coord, ext_atype, nlist, mapping)
    SeZMModel-->>DeepEval: predict dict (extended)
    DeepEval->>DeepEval: communicate_extended_output
    DeepEval-->>Caller: energy, forces, virial
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • deepmodeling/deepmd-kit#5448: Initial DPA4/SeZM descriptor and model implementation; this PR is a direct follow-on that replaces its extended-coordinate lower interface with the compact edge-vector schema.
  • deepmodeling/deepmd-kit#5491: Introduces EdgeNeighborList and return_mode to the NeighborList interface — the same modules extended in this PR with additional builders and backend wiring.
  • deepmodeling/deepmd-kit#5518: Refactors SeZM/DPA4 inference/export for edge-force and do_atomic_virial handling, overlapping directly with freeze_pt2/DeepEval changes in this PR.

Suggested reviewers

  • njzjz
  • iProzd
  • wanghan-iapcm
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: refactoring DPA4 to use edge schema and removing/ignoring the sel parameter.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread deepmd/pt/model/model/sezm_model.py Dismissed
Comment thread deepmd/pt_expt/utils/vesin_neighbor_list.py Dismissed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
deepmd/pt_expt/infer/deep_eval.py (1)

1266-1357: ⚠️ Potential issue | 🔴 Critical

Fix coordinate tensor asymmetry in fallback path: use local coordinates, not extended.

The fallback path (lines 1347–1357) passes ext_coord_t (extended coordinates) while slicing atype to local atoms only, creating a shape mismatch. The model reshapes coord based on atype.shape[1], which expects the two tensors to have compatible atom dimensions. The fast path correctly uses local coordinates; the fallback path should do the same. Replace ext_coord_t with a local coordinate slice in the fallback model_inputs tuple.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deepmd/pt_expt/infer/deep_eval.py` around lines 1266 - 1357, In the fallback
path where model_inputs is constructed (around lines 1350-1357 in the
_build_edge_inputs_from_nlist fallback), there is an asymmetry where ext_coord_t
(extended coordinates) is passed while ext_atype_t is sliced to local atoms only
with [:, :natoms], causing a shape mismatch. To fix this, slice ext_coord_t to
local atoms in the same way as the atype is being sliced so that both tensors
have compatible atom dimensions, matching the pattern used in the fast path
where edge_schema.coord (local coordinates) is used. Replace the ext_coord_t
reference in the model_inputs tuple with the appropriately sliced coordinate
tensor.
deepmd/pt/utils/nlist.py (1)

132-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject uncapped mode when type splitting is enabled.

cap_neighbors=False sizes nsel from all neighbors, but distinguish_types=True still routes through nlist_distinguish_types(..., sel), which slices each type back to sel and can silently drop neighbors despite the “keep every neighbor” contract.

Proposed guard
     if isinstance(sel, int):
         sel = [sel]
+    if not cap_neighbors and distinguish_types:
+        raise ValueError(
+            "cap_neighbors=False is only supported when distinguish_types=False"
+        )
 
     # Get the coordinates for the local atoms (first nloc atoms)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deepmd/pt/utils/nlist.py` around lines 132 - 149, The issue is that when
cap_neighbors is False, the code intends to keep every neighbor within rcut, but
when distinguish_types is True, the downstream call to nlist_distinguish_types
with the sel parameter still slices neighbors back to fixed sel values, silently
dropping neighbors and violating the "keep every neighbor" contract. Add a guard
at the beginning of the function (before the cap_neighbors conditional block)
that raises an error or rejects the invalid combination when both cap_neighbors
is False and distinguish_types is True, preventing this silent behavior
mismatch.
deepmd/pt/model/model/sezm_model.py (1)

2279-2294: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve the spin model’s extended-list contract after this return-type change.

build_neighbor_list() now returns EdgeNeighborList, but SeZMSpinModel.build_neighbor_list() still delegates to super().build_neighbor_list() while advertising the historical tuple contract. Update that override to call build_extended_neighbor_list() or change its callers/annotation; otherwise spin callers that unpack (extended_coord, extended_atype, nlist, mapping) will break.

Suggested downstream fix
# deepmd/pt/model/model/sezm_spin_model.py
     def build_neighbor_list(
         self,
         coord: torch.Tensor,
         atype: torch.Tensor,
         box: torch.Tensor | None,
     ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
         """Build the real-atom neighbor list before spin expansion."""
-        return super().build_neighbor_list(coord, atype, box)
+        return super().build_extended_neighbor_list(coord, atype, box)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deepmd/pt/model/model/sezm_model.py` around lines 2279 - 2294, The base class
build_neighbor_list() method now returns EdgeNeighborList, but
SeZMSpinModel.build_neighbor_list() override still delegates to
super().build_neighbor_list() while maintaining a tuple return type contract
that downstream callers depend on. Update the
SeZMSpinModel.build_neighbor_list() override to call
build_extended_neighbor_list() instead of super().build_neighbor_list() to
preserve the historical tuple unpacking contract (extended_coord,
extended_atype, nlist, mapping) that spin model callers expect.
🧹 Nitpick comments (1)
deepmd/pt_expt/infer/deep_eval.py (1)

1370-1414: 💤 Low value

Consider extracting shared fparam/aparam preparation logic.

This method duplicates the fparam/aparam preparation logic from _prepare_nlist_inputs (lines 1201-1240). While not a bug, extracting this into a shared helper would reduce maintenance burden.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deepmd/pt_expt/infer/deep_eval.py` around lines 1370 - 1414, The
_prepare_optional_lower_inputs method contains fparam and aparam preparation
logic that is duplicated from _prepare_nlist_inputs. Extract the shared tensor
preparation logic for both fparam and aparam (including default value handling,
validation, and tensor creation with reshape and expand operations) into a
separate helper method. Then replace the duplicated code blocks in both
_prepare_optional_lower_inputs and _prepare_nlist_inputs with calls to this new
helper method to reduce maintenance burden and improve code reusability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deepmd/pt/infer/deep_eval.py`:
- Around line 257-259: The _uses_edge_schema switch in the assignment is
currently based on self.model_def_script, which remains the top-level model
dictionary in multitask scenarios. However, self.input_param is replaced with
the selected branch params when a specific head is instantiated. Change the
_is_sezm_model_params call to use self.input_param instead of
self.model_def_script so that the edge-schema switch correctly reflects the
selected head's parameters rather than the top-level model definition, ensuring
the correct forward_common_lower argument contract is chosen for the O(N) path.

In `@deepmd/pt/model/model/sezm_model.py`:
- Around line 1524-1531: Ruff F722 is failing because it's attempting to parse
the string literals in the jaxtyping shape annotations (such as those in the
forward_lower method parameters at lines 1524-1531 and
build_extended_neighbor_list method at lines 2298-2300) as forward annotations,
which contain invalid Python syntax with embedded spaces and underscores. Add a
file-level `# noqa: F722` directive at the top of the sezm_model.py file to
suppress this linting rule for the entire file, ensuring that ruff check passes
without modifying the jaxtyping annotations themselves.

In `@source/api_cc/include/commonPT.h`:
- Around line 202-225: The createEdgeTensors function incorrectly assumes that
loop index ii directly corresponds to the center atom index, but when nlist is
compacted via shuffle_exclude_empty, row ii actually corresponds to ilist[ii].
This causes incorrect scatter indices and edge vector calculations. Pass ilist
as a parameter to createEdgeTensors and update the center atom index calculation
to use const int center = ilist[ii] instead of ii, then use this center variable
in the center_offset calculation at line 203 and in the dst_ext.push_back call
at line 225.

In `@source/api_cc/src/DeepPotPT.cc`:
- Around line 220-224: The filter_by_distance call on nlist_data needs to be
executed on every timestep, not just when ago equals zero (during neighbor list
rebuilds). Move the filter_by_distance call that filters pairs by the rcut
cutoff distance outside of the ago == 0 conditional block, keeping the other
nlist operations (copy_from_nlist, shuffle_exclude_empty, and padding) inside
the conditional block where they belong. This ensures pairs are correctly
filtered based on the cutoff distance at every step, preventing missed pairs
that re-enter the cutoff radius between rebuilds.

---

Outside diff comments:
In `@deepmd/pt_expt/infer/deep_eval.py`:
- Around line 1266-1357: In the fallback path where model_inputs is constructed
(around lines 1350-1357 in the _build_edge_inputs_from_nlist fallback), there is
an asymmetry where ext_coord_t (extended coordinates) is passed while
ext_atype_t is sliced to local atoms only with [:, :natoms], causing a shape
mismatch. To fix this, slice ext_coord_t to local atoms in the same way as the
atype is being sliced so that both tensors have compatible atom dimensions,
matching the pattern used in the fast path where edge_schema.coord (local
coordinates) is used. Replace the ext_coord_t reference in the model_inputs
tuple with the appropriately sliced coordinate tensor.

In `@deepmd/pt/model/model/sezm_model.py`:
- Around line 2279-2294: The base class build_neighbor_list() method now returns
EdgeNeighborList, but SeZMSpinModel.build_neighbor_list() override still
delegates to super().build_neighbor_list() while maintaining a tuple return type
contract that downstream callers depend on. Update the
SeZMSpinModel.build_neighbor_list() override to call
build_extended_neighbor_list() instead of super().build_neighbor_list() to
preserve the historical tuple unpacking contract (extended_coord,
extended_atype, nlist, mapping) that spin model callers expect.

In `@deepmd/pt/utils/nlist.py`:
- Around line 132-149: The issue is that when cap_neighbors is False, the code
intends to keep every neighbor within rcut, but when distinguish_types is True,
the downstream call to nlist_distinguish_types with the sel parameter still
slices neighbors back to fixed sel values, silently dropping neighbors and
violating the "keep every neighbor" contract. Add a guard at the beginning of
the function (before the cap_neighbors conditional block) that raises an error
or rejects the invalid combination when both cap_neighbors is False and
distinguish_types is True, preventing this silent behavior mismatch.

---

Nitpick comments:
In `@deepmd/pt_expt/infer/deep_eval.py`:
- Around line 1370-1414: The _prepare_optional_lower_inputs method contains
fparam and aparam preparation logic that is duplicated from
_prepare_nlist_inputs. Extract the shared tensor preparation logic for both
fparam and aparam (including default value handling, validation, and tensor
creation with reshape and expand operations) into a separate helper method. Then
replace the duplicated code blocks in both _prepare_optional_lower_inputs and
_prepare_nlist_inputs with calls to this new helper method to reduce maintenance
burden and improve code reusability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 64f127a8-03e5-4cdf-870f-77ed7c868ae1

📥 Commits

Reviewing files that changed from the base of the PR and between 5a0d505 and a51144e.

📒 Files selected for processing (30)
  • deepmd/dpmodel/utils/default_neighbor_list.py
  • deepmd/dpmodel/utils/neighbor_list.py
  • deepmd/pt/entrypoints/freeze_pt2.py
  • deepmd/pt/infer/deep_eval.py
  • deepmd/pt/model/model/sezm_model.py
  • deepmd/pt/model/model/sezm_spin_model.py
  • deepmd/pt/utils/compile_compat.py
  • deepmd/pt/utils/nlist.py
  • deepmd/pt/utils/nv_nlist.py
  • deepmd/pt_expt/infer/deep_eval.py
  • deepmd/pt_expt/utils/edge_schema.py
  • deepmd/pt_expt/utils/vesin_neighbor_list.py
  • deepmd/utils/argcheck.py
  • examples/water/dpa4/input.json
  • source/api_cc/include/DeepPotPTExpt.h
  • source/api_cc/include/common.h
  • source/api_cc/include/commonPT.h
  • source/api_cc/src/DeepPotPT.cc
  • source/api_cc/src/DeepPotPTExpt.cc
  • source/api_cc/src/DeepSpinPT.cc
  • source/api_cc/src/DeepSpinPTExpt.cc
  • source/api_cc/src/DeepTensorPT.cc
  • source/api_cc/src/common.cc
  • source/api_cc/tests/test_deeppot_pt.cc
  • source/api_cc/tests/test_deeppot_ptexpt.cc
  • source/api_cc/tests/test_neighbor_list_data.cc
  • source/tests/pt/model/test_descriptor_sezm.py
  • source/tests/pt/model/test_nv_nlist.py
  • source/tests/pt/model/test_sezm_export.py
  • source/tests/pt/model/test_sezm_model.py
💤 Files with no reviewable changes (1)
  • examples/water/dpa4/input.json

Comment thread deepmd/pt/infer/deep_eval.py
Comment thread deepmd/pt/model/model/sezm_model.py
Comment thread source/api_cc/include/commonPT.h Outdated
Comment thread source/api_cc/src/DeepPotPT.cc
Comment thread source/api_cc/include/commonPT.h Fixed
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.10864% with 150 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.15%. Comparing base (4b6506d) to head (2d05ad3).

Files with missing lines Patch % Lines
deepmd/pt_expt/infer/deep_eval.py 34.48% 38 Missing ⚠️
source/api_cc/src/DeepPotPTExpt.cc 32.00% 28 Missing and 6 partials ⚠️
source/api_cc/include/commonPT.h 81.35% 12 Missing and 10 partials ⚠️
deepmd/pt/model/model/sezm_model.py 86.60% 15 Missing ⚠️
deepmd/pt_expt/utils/edge_schema.py 91.73% 10 Missing ⚠️
source/api_cc/tests/test_deeppot_pt.cc 85.93% 9 Missing ⚠️
deepmd/pt/utils/nv_nlist.py 80.00% 7 Missing ⚠️
source/api_cc/tests/test_deeppot_ptexpt.cc 88.67% 6 Missing ⚠️
deepmd/pt/utils/compile_compat.py 70.00% 3 Missing ⚠️
deepmd/pt_expt/utils/vesin_neighbor_list.py 86.36% 3 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5562      +/-   ##
==========================================
- Coverage   82.17%   82.15%   -0.03%     
==========================================
  Files         898      899       +1     
  Lines      103576   104128     +552     
  Branches     4432     4470      +38     
==========================================
+ Hits        85117    85544     +427     
- Misses      17063    17176     +113     
- Partials     1396     1408      +12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
source/tests/pt/model/test_nv_nlist.py (1)

286-301: ⚡ Quick win

Assert scatter indices and low-sel invariance.

The new consistency check masks down to (src, dst, edge_vec) and every case passes sel=[64]. A builder could still scatter forces/virials to the wrong atoms, or cap edge-mode output when sel is small, while these tests pass. Include edge_scatter_index in the canonical comparison and repeat the cases with an intentionally small sel.

Proposed test strengthening
-def _canonical_edges(schema) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
+def _canonical_edges(
+    schema,
+) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
@@
     edge_index = _to_numpy(schema.edge_index)
     src = edge_index[0][mask].astype(np.int64)
     dst = edge_index[1][mask].astype(np.int64)
+    edge_scatter = _to_numpy(schema.edge_scatter_index)
+    scatter_src = edge_scatter[0][mask].astype(np.int64)
+    scatter_dst = edge_scatter[1][mask].astype(np.int64)
     edge_vec = _to_numpy(schema.edge_vec)[mask].astype(np.float64)
@@
-    return src[order], dst[order], edge_vec[order]
+    return (
+        src[order],
+        dst[order],
+        scatter_src[order],
+        scatter_dst[order],
+        edge_vec[order],
+    )
@@
-        ref_src, ref_dst, ref_vec = _canonical_edges(
+        ref_src, ref_dst, ref_scatter_src, ref_scatter_dst, ref_vec = _canonical_edges(
             _dense_keepall_edges(coord, atype, box, rcut)
         )
@@
-                src, dst, vec = _canonical_edges(
+                src, dst, scatter_src, scatter_dst, vec = _canonical_edges(
                     builder.build(coord, atype, box, rcut, sel, return_mode="edges")
                 )
                 np.testing.assert_array_equal(src, ref_src)
                 np.testing.assert_array_equal(dst, ref_dst)
+                np.testing.assert_array_equal(scatter_src, ref_scatter_src)
+                np.testing.assert_array_equal(scatter_dst, ref_scatter_dst)
                 np.testing.assert_allclose(vec, ref_vec, atol=1.0e-9, rtol=1.0e-9)
@@
-                self._assert_builders_match(coord, atype, box, 4.0, [64])
+                for sel in ([64], [1]):
+                    with self.subTest(sel=sel):
+                        self._assert_builders_match(coord, atype, box, 4.0, sel)
@@
-                self._assert_builders_match(coord, atype, box, 4.0, [64])
+                for sel in ([64], [1]):
+                    with self.subTest(sel=sel):
+                        self._assert_builders_match(coord, atype, box, 4.0, sel)
@@
-                self._assert_builders_match(coord, atype, None, 4.0, [64])
+                for sel in ([64], [1]):
+                    with self.subTest(sel=sel):
+                        self._assert_builders_match(coord, atype, None, 4.0, sel)

Also applies to: 356-390

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/tests/pt/model/test_nv_nlist.py` around lines 286 - 301, The
_canonical_edges function only returns (src, dst, edge_vec) which doesn't catch
potential bugs in scatter indices or edge-mode capping when sel is small. Modify
the _canonical_edges function to also extract edge_scatter_index from the schema
(similar to how edge_index and edge_vec are extracted using _to_numpy), apply
the mask, and include it as a fourth return value in the tuple. Then update all
test cases that call this function to unpack and validate the returned scatter
index alongside the other edge properties. Finally, repeat the test cases
mentioned in the comment (around lines 356-390) with an intentionally small sel
parameter value (such as sel=2 or sel=1) to ensure proper edge-mode output
behavior is tested.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deepmd/pt/model/model/sezm_model.py`:
- Around line 1021-1022: The extended_coord_corr tensor is being reshaped but
not normalized to match the device and dtype of other geometry tensors like
coord. After reshaping extended_coord_corr when its ndim is 2, add code to move
it to coord.device and coord.dtype using the same normalization approach applied
to coord and the edge tensors. This ensures consistent device placement and data
types throughout the geometry tensor operations and prevents device/dtype
mismatches when reaching edge_energy_deriv().

---

Nitpick comments:
In `@source/tests/pt/model/test_nv_nlist.py`:
- Around line 286-301: The _canonical_edges function only returns (src, dst,
edge_vec) which doesn't catch potential bugs in scatter indices or edge-mode
capping when sel is small. Modify the _canonical_edges function to also extract
edge_scatter_index from the schema (similar to how edge_index and edge_vec are
extracted using _to_numpy), apply the mask, and include it as a fourth return
value in the tuple. Then update all test cases that call this function to unpack
and validate the returned scatter index alongside the other edge properties.
Finally, repeat the test cases mentioned in the comment (around lines 356-390)
with an intentionally small sel parameter value (such as sel=2 or sel=1) to
ensure proper edge-mode output behavior is tested.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0a44c6b0-a928-4af2-87a2-0038bc305faa

📥 Commits

Reviewing files that changed from the base of the PR and between a51144e and d99be6c.

📒 Files selected for processing (30)
  • deepmd/dpmodel/utils/default_neighbor_list.py
  • deepmd/dpmodel/utils/neighbor_list.py
  • deepmd/pt/entrypoints/freeze_pt2.py
  • deepmd/pt/infer/deep_eval.py
  • deepmd/pt/model/model/sezm_model.py
  • deepmd/pt/model/model/sezm_spin_model.py
  • deepmd/pt/utils/compile_compat.py
  • deepmd/pt/utils/nlist.py
  • deepmd/pt/utils/nv_nlist.py
  • deepmd/pt_expt/infer/deep_eval.py
  • deepmd/pt_expt/utils/edge_schema.py
  • deepmd/pt_expt/utils/vesin_neighbor_list.py
  • deepmd/utils/argcheck.py
  • examples/water/dpa4/input.json
  • source/api_cc/include/DeepPotPTExpt.h
  • source/api_cc/include/common.h
  • source/api_cc/include/commonPT.h
  • source/api_cc/src/DeepPotPT.cc
  • source/api_cc/src/DeepPotPTExpt.cc
  • source/api_cc/src/DeepSpinPT.cc
  • source/api_cc/src/DeepSpinPTExpt.cc
  • source/api_cc/src/DeepTensorPT.cc
  • source/api_cc/src/common.cc
  • source/api_cc/tests/test_deeppot_pt.cc
  • source/api_cc/tests/test_deeppot_ptexpt.cc
  • source/api_cc/tests/test_neighbor_list_data.cc
  • source/tests/pt/model/test_descriptor_sezm.py
  • source/tests/pt/model/test_nv_nlist.py
  • source/tests/pt/model/test_sezm_export.py
  • source/tests/pt/model/test_sezm_model.py
✅ Files skipped from review due to trivial changes (1)
  • examples/water/dpa4/input.json
🚧 Files skipped from review as they are similar to previous changes (25)
  • source/api_cc/src/DeepPotPT.cc
  • source/api_cc/include/common.h
  • source/api_cc/src/DeepTensorPT.cc
  • source/api_cc/src/DeepSpinPTExpt.cc
  • source/api_cc/src/DeepSpinPT.cc
  • source/api_cc/include/DeepPotPTExpt.h
  • deepmd/dpmodel/utils/default_neighbor_list.py
  • deepmd/dpmodel/utils/neighbor_list.py
  • source/tests/pt/model/test_sezm_model.py
  • source/api_cc/tests/test_deeppot_pt.cc
  • deepmd/utils/argcheck.py
  • source/api_cc/tests/test_deeppot_ptexpt.cc
  • deepmd/pt_expt/utils/vesin_neighbor_list.py
  • source/api_cc/include/commonPT.h
  • deepmd/pt/utils/nv_nlist.py
  • source/api_cc/src/common.cc
  • deepmd/pt/utils/nlist.py
  • source/api_cc/tests/test_neighbor_list_data.cc
  • source/tests/pt/model/test_descriptor_sezm.py
  • deepmd/pt/entrypoints/freeze_pt2.py
  • source/api_cc/src/DeepPotPTExpt.cc
  • deepmd/pt/model/model/sezm_spin_model.py
  • source/tests/pt/model/test_sezm_export.py
  • deepmd/pt_expt/utils/edge_schema.py
  • deepmd/pt_expt/infer/deep_eval.py

Comment thread deepmd/pt/model/model/sezm_model.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
source/tests/pt/model/test_nv_nlist.py (1)

286-301: ⚡ Quick win

Cover scatter indices and undersized sel in edge-schema consistency tests.

These tests can pass even if a builder corrupts edge_scatter_index or still truncates edge-mode output by sel, because _canonical_edges() drops scatter indices and every case uses [64]. Compare edge_scatter_index too, and include a deliberately small sel such as [1] to enforce the “ignore sel” contract.

Proposed test strengthening
-def _canonical_edges(schema) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
+def _canonical_edges(
+    schema,
+) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
@@
     edge_index = _to_numpy(schema.edge_index)
     src = edge_index[0][mask].astype(np.int64)
     dst = edge_index[1][mask].astype(np.int64)
+    scatter = _to_numpy(schema.edge_scatter_index)[:, mask].astype(np.int64)
     edge_vec = _to_numpy(schema.edge_vec)[mask].astype(np.float64)
     keys = np.round(edge_vec * 1.0e6).astype(np.int64)
     order = np.lexsort((keys[:, 2], keys[:, 1], keys[:, 0], dst, src))
-    return src[order], dst[order], edge_vec[order]
+    return src[order], dst[order], scatter[:, order], edge_vec[order]
@@
-        ref_src, ref_dst, ref_vec = _canonical_edges(
+        ref_src, ref_dst, ref_scatter, ref_vec = _canonical_edges(
             _dense_keepall_edges(coord, atype, box, rcut)
         )
@@
-                src, dst, vec = _canonical_edges(
+                src, dst, scatter, vec = _canonical_edges(
                     builder.build(coord, atype, box, rcut, sel, return_mode="edges")
                 )
                 np.testing.assert_array_equal(src, ref_src)
                 np.testing.assert_array_equal(dst, ref_dst)
+                np.testing.assert_array_equal(scatter, ref_scatter)
                 np.testing.assert_allclose(vec, ref_vec, atol=1.0e-9, rtol=1.0e-9)
@@
-                self._assert_builders_match(coord, atype, box, 4.0, [64])
+                for sel in ([1], [64]):
+                    with self.subTest(device=str(device), sel=sel):
+                        self._assert_builders_match(coord, atype, box, 4.0, sel)

Also applies to: 356-372, 374-390

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/tests/pt/model/test_nv_nlist.py` around lines 286 - 301, The
edge-schema consistency tests are not comprehensive enough to catch potential
builder corruptions. The `_canonical_edges()` function currently drops scatter
indices and all test cases use the same large `sel` value of `[64]`, which means
the tests cannot detect if `edge_scatter_index` is corrupted or if edge-mode
output is incorrectly truncated by the `sel` parameter. Enhance the consistency
validation by adding checks for `edge_scatter_index` equality in the test
assertions, and include test cases with deliberately small `sel` values such as
`[1]` alongside the existing `[64]` cases to enforce the contract that edges
should be returned regardless of the `sel` parameter. Apply these changes to all
affected test functions mentioned in the comment range.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@source/tests/pt/model/test_nv_nlist.py`:
- Around line 286-301: The edge-schema consistency tests are not comprehensive
enough to catch potential builder corruptions. The `_canonical_edges()` function
currently drops scatter indices and all test cases use the same large `sel`
value of `[64]`, which means the tests cannot detect if `edge_scatter_index` is
corrupted or if edge-mode output is incorrectly truncated by the `sel`
parameter. Enhance the consistency validation by adding checks for
`edge_scatter_index` equality in the test assertions, and include test cases
with deliberately small `sel` values such as `[1]` alongside the existing `[64]`
cases to enforce the contract that edges should be returned regardless of the
`sel` parameter. Apply these changes to all affected test functions mentioned in
the comment range.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d67a780c-d5da-4f1b-bc3d-ef6e0fcc913d

📥 Commits

Reviewing files that changed from the base of the PR and between d99be6c and 2d05ad3.

📒 Files selected for processing (24)
  • deepmd/dpmodel/utils/default_neighbor_list.py
  • deepmd/dpmodel/utils/neighbor_list.py
  • deepmd/pt/entrypoints/freeze_pt2.py
  • deepmd/pt/infer/deep_eval.py
  • deepmd/pt/model/model/sezm_model.py
  • deepmd/pt/model/model/sezm_spin_model.py
  • deepmd/pt/utils/compile_compat.py
  • deepmd/pt/utils/nlist.py
  • deepmd/pt/utils/nv_nlist.py
  • deepmd/pt_expt/infer/deep_eval.py
  • deepmd/pt_expt/utils/edge_schema.py
  • deepmd/pt_expt/utils/vesin_neighbor_list.py
  • deepmd/utils/argcheck.py
  • examples/water/dpa4/input.json
  • source/api_cc/include/DeepPotPTExpt.h
  • source/api_cc/include/commonPT.h
  • source/api_cc/src/DeepPotPTExpt.cc
  • source/api_cc/tests/test_deeppot_pt.cc
  • source/api_cc/tests/test_deeppot_ptexpt.cc
  • source/api_cc/tests/test_neighbor_list_data.cc
  • source/tests/pt/model/test_descriptor_sezm.py
  • source/tests/pt/model/test_nv_nlist.py
  • source/tests/pt/model/test_sezm_export.py
  • source/tests/pt/model/test_sezm_model.py
💤 Files with no reviewable changes (1)
  • examples/water/dpa4/input.json
🚧 Files skipped from review as they are similar to previous changes (19)
  • deepmd/dpmodel/utils/default_neighbor_list.py
  • source/tests/pt/model/test_sezm_model.py
  • source/api_cc/include/DeepPotPTExpt.h
  • deepmd/dpmodel/utils/neighbor_list.py
  • source/api_cc/include/commonPT.h
  • source/api_cc/tests/test_deeppot_pt.cc
  • deepmd/pt/infer/deep_eval.py
  • source/api_cc/tests/test_deeppot_ptexpt.cc
  • deepmd/pt_expt/utils/vesin_neighbor_list.py
  • deepmd/pt/utils/nlist.py
  • deepmd/utils/argcheck.py
  • source/tests/pt/model/test_descriptor_sezm.py
  • deepmd/pt/entrypoints/freeze_pt2.py
  • source/tests/pt/model/test_sezm_export.py
  • deepmd/pt/utils/nv_nlist.py
  • deepmd/pt/model/model/sezm_spin_model.py
  • deepmd/pt_expt/infer/deep_eval.py
  • source/api_cc/src/DeepPotPTExpt.cc
  • deepmd/pt_expt/utils/edge_schema.py

@njzjz-bot

Copy link
Copy Markdown
Contributor

I reviewed the current head of this PR, focusing on the new edge-schema path for DPA4/SeZM and the pt_expt/C++ inference plumbing.

The parts I was most worried about look OK in the current revision:

  • the .pt inference edge-schema switch now follows the selected head params, not only the top-level model definition;
  • extended_coord_corr is normalized to the same device/dtype as the other geometry tensors before force/virial derivation;
  • the LAMMPS compacted-neighbor-list path passes row_centers into createEdgeTensors, so compacted jlist rows are mapped back to the correct center atoms;
  • the cached skin-topology edge path recomputes current cutoff edges via compactEdgeTensors(...), so out-of-cutoff skin pairs are not fed into the exported graph.

I also checked that the GitHub CI matrix is green. Locally I ran syntax checks for the touched Python files and ruff check on the main touched Python files; both passed. I do not see a blocking issue from this review.

Authored by OpenClaw 2026.6.8 (844f405) (model: custom-chat-jinzhezeng-group/gpt-5.5)

Comment thread source/api_cc/include/commonPT.h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants