Skip to content

Conversation

@ChiahsinChu
Copy link
Contributor

@ChiahsinChu ChiahsinChu commented Dec 15, 2025

  1. Allow backend-convert from pt to tf with atom_exclude_types
  2. Fix bug in get_sel_type method of pt model (by calling fitting.reinit_exclude in atomic model init).

Fix #5096

Summary by CodeRabbit

  • Bug Fixes

    • Fitting now reinitializes exclusion/selection settings during model initialization and after type-map changes; deserialization injects selection info when atom exclusions exist to ensure correct selection behavior.
  • Tests

    • Added unit and cross-backend tests to verify atom-exclude → selection computation and parity between backends; expanded coverage for exclusion scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@ChiahsinChu ChiahsinChu changed the title fix(pt): fix(pt): get correct sel_type in pt model Dec 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

📝 Walkthrough

Walkthrough

Reinitialize PyTorch fitting exclusion state during DPAtomicModel init and after type-map updates; inject a computed sel_type (complement of atom_exclude_types) into fitting data during TF model deserialization; add tests asserting cross-backend sel_type consistency when atom_exclude_types is set.

Changes

Cohort / File(s) Summary
PyTorch DP atomic model — init & type-map update
deepmd/pt/model/atomic_model/dp_atomic_model.py, deepmd/dpmodel/atomic_model/dp_atomic_model.py
After assigning self.fitting / self.fitting_net, conditionally call reinit_exclude(self.atom_exclude_types) if the fitting object exposes that method (done before out-stat init). Also reinitialize exclusions after change_type_map to refresh exclusion/sel-type state.
TensorFlow model deserialization
deepmd/tf/model/model.py
Descriptor.deserialize now builds fitting_dict = data.pop("fitting", {}); if atom_exclude_types is non-empty, compute sel_type as the complement of atom_exclude_types over the full type_map and inject it into fitting_dict before calling Fitting.deserialize. Removed the previous NotImplementedError guard for atom_exclude_types.
Unit & cross-backend consistency tests
source/tests/pt/model/test_get_model.py, source/tests/consistent/model/test_dipole.py, source/tests/consistent/model/test_polar.py, source/tests/universal/dpmodel/atomc_model/test_atomic_model.py
Added/updated tests to cover atom_exclude_types: compute sel-type from exclusions, include atom_exclude_types in serialized refs, assert TF/PT get_sel_type() parity, add helper make_sel_type_from_atom_exclude_types, and extend parameterized cases to include exclude lists.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check correct guarded placement of reinit_exclude calls and ensure no side effects if absent.
  • Verify sel_type complement computation handles ordering and edge cases (empty/full exclusions) and matches legacy serialized formats.
  • Review new tests for deterministic ordering of types and for assumptions about serialization structure.

Possibly related PRs

Suggested reviewers

  • njzjz
  • wanghan-iapcm
  • iProzd

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.74% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(pt): get correct sel_type in pt model' accurately summarizes the main objective—fixing the sel_type computation in PyTorch models by ensuring fitting.reinit_exclude is called during initialization.
Linked Issues check ✅ Passed The PR implementation addresses the core requirements of issue #5096: it fixes the sel_type bug in PyTorch models by calling fitting.reinit_exclude in atomic model initialization and enables backend conversion from PyTorch to TensorFlow to respect atom_exclude_types.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the sel_type issue: modifications to atomic model initialization in three backends (pt, tf, dpmodel), corresponding test updates for consistency verification, and a utility function for type computation—no unrelated changes detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b15f10 and d9f1b6d.

📒 Files selected for processing (7)
  • deepmd/dpmodel/atomic_model/dp_atomic_model.py (2 hunks)
  • deepmd/pt/model/atomic_model/dp_atomic_model.py (2 hunks)
  • deepmd/tf/model/model.py (1 hunks)
  • source/tests/consistent/model/test_dipole.py (1 hunks)
  • source/tests/consistent/model/test_polar.py (1 hunks)
  • source/tests/pt/model/test_get_model.py (1 hunks)
  • source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (17 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • source/tests/consistent/model/test_polar.py
  • deepmd/pt/model/atomic_model/dp_atomic_model.py
  • source/tests/pt/model/test_get_model.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-16T21:49:57.401Z
Learnt from: njzjz
Repo: deepmodeling/deepmd-kit PR: 4226
File: deepmd/dpmodel/atomic_model/base_atomic_model.py:202-202
Timestamp: 2024-10-16T21:49:57.401Z
Learning: When reviewing PRs, avoid making refactor suggestions that are not directly related to the PR's changes. For example, in `deepmd/dpmodel/atomic_model/base_atomic_model.py`, do not suggest simplifying `for kk in ret_dict.keys()` to `for kk in ret_dict` unless it's relevant to the PR.

Applied to files:

  • deepmd/dpmodel/atomic_model/dp_atomic_model.py
🧬 Code graph analysis (4)
source/tests/consistent/model/test_dipole.py (4)
source/tests/consistent/model/test_polar.py (3)
  • test_atom_exclude_types (202-212)
  • skip_tf (92-93)
  • data (46-69)
source/tests/consistent/common.py (3)
  • get_reference_ret_serialization (312-332)
  • RefBackend (209-217)
  • reset_unique_id (117-118)
deepmd/tf/fit/dipole.py (2)
  • deserialize (470-495)
  • get_sel_type (160-162)
deepmd/tf/model/tensor.py (1)
  • get_sel_type (81-82)
deepmd/tf/model/model.py (3)
source/tests/consistent/model/test_dipole.py (1)
  • data (46-69)
deepmd/tf/fit/fitting.py (2)
  • Fitting (32-266)
  • deserialize (86-108)
deepmd/tf/fit/polar.py (1)
  • deserialize (691-714)
source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (3)
deepmd/dpmodel/atomic_model/dp_atomic_model.py (4)
  • has_message_passing (90-92)
  • get_sel_type (243-250)
  • get_dim_fparam (231-233)
  • get_dim_aparam (235-237)
deepmd/dpmodel/atomic_model/linear_atomic_model.py (4)
  • has_message_passing (99-101)
  • get_sel_type (353-363)
  • get_dim_fparam (344-347)
  • get_dim_aparam (349-351)
deepmd/pt/model/atomic_model/linear_atomic_model.py (4)
  • has_message_passing (121-123)
  • get_sel_type (448-468)
  • get_dim_fparam (439-442)
  • get_dim_aparam (444-446)
deepmd/dpmodel/atomic_model/dp_atomic_model.py (4)
deepmd/pd/model/task/fitting.py (1)
  • reinit_exclude (360-365)
deepmd/pt/model/model/make_model.py (1)
  • change_type_map (503-514)
deepmd/dpmodel/atomic_model/base_atomic_model.py (1)
  • change_type_map (134-149)
deepmd/dpmodel/model/make_model.py (1)
  • change_type_map (540-546)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Test Python (4, 3.13)
  • GitHub Check: Test Python (1, 3.10)
  • GitHub Check: Test Python (6, 3.13)
  • GitHub Check: Test Python (5, 3.10)
  • GitHub Check: Test Python (3, 3.10)
  • GitHub Check: Test Python (3, 3.13)
  • GitHub Check: Test Python (5, 3.13)
  • GitHub Check: Test Python (4, 3.10)
  • GitHub Check: Test Python (6, 3.10)
  • GitHub Check: Test Python (2, 3.13)
  • GitHub Check: Test Python (2, 3.10)
  • GitHub Check: Test Python (1, 3.13)
  • GitHub Check: Build C library (2.18, libdeepmd_c.tar.gz)
  • GitHub Check: Test C++ (false, true, true, false)
  • GitHub Check: Build wheels for cp311-win_amd64
  • GitHub Check: Test C++ (true, false, false, true)
  • GitHub Check: Build wheels for cp311-macosx_arm64
  • GitHub Check: Build wheels for cp310-manylinux_aarch64
  • GitHub Check: Test C++ (false, false, false, true)
  • GitHub Check: Build wheels for cp311-macosx_x86_64
  • GitHub Check: Test C++ (true, true, true, false)
  • GitHub Check: Build wheels for cp311-manylinux_x86_64
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (python)
  • GitHub Check: Build C++ (cuda120, cuda)
  • GitHub Check: Build C++ (rocm, rocm)
  • GitHub Check: Build C++ (cpu, cpu)
  • GitHub Check: Build C++ (clang, clang)
🔇 Additional comments (6)
deepmd/dpmodel/atomic_model/dp_atomic_model.py (2)

54-55: LGTM! Proper initialization of fitting exclusion state.

The conditional call to reinit_exclude correctly propagates atom_exclude_types to the fitting object during initialization, ensuring get_sel_type() returns the correct value. The hasattr guard appropriately handles fittings that don't support exclusions.


196-196: Change from self.fitting_net.change_type_map(...) to self.fitting.change_type_map(...) is correct.

The change aligns with the attribute defined on line 53 (self.fitting = fitting). self.fitting_net is not defined in this class; it only appears in the docstring as a parameter description while the actual parameter and attribute are named fitting. The updated code correctly uses the defined attribute.

source/tests/consistent/model/test_dipole.py (1)

208-218: LGTM! Cross-backend consistency test for atom exclusion.

The test correctly verifies that TensorFlow and PyTorch models produce identical sel_type values when deserialized with atom_exclude_types. The backend availability checks properly skip the test when either backend is unavailable.

deepmd/tf/model/model.py (1)

1006-1015: LGTM! Correct sel_type computation from atom_exclude_types.

The deserialization logic correctly computes sel_type as the complement of atom_exclude_types over the full type map and injects it into the fitting data. The use of np.setdiff1d(..., assume_unique=True) is appropriate here, as type indices are inherently unique.

source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (2)

77-82: LGTM! Utility function for sel_type computation.

The helper function correctly computes sel_type as the set difference between all types and excluded types, matching the logic in deepmd/tf/model/model.py (lines 1010-1014). Using np.setdiff1d with assume_unique=True is appropriate for type indices.


150-156: LGTM! Verification test for atom_exclude_types handling.

The test method correctly verifies that the helper function produces sel_type values matching those returned by the fitting's get_sel_type() method, confirming proper propagation of atom_exclude_types through the model initialization chain.


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.

@ChiahsinChu ChiahsinChu force-pushed the devel-pt-sel_type branch 2 times, most recently from 17ca9af to be6c622 Compare December 15, 2025 09:27
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (2)
deepmd/pt/model/atomic_model/dp_atomic_model.py (1)

52-68: Reinitializing fitting exclusions in __init__ is appropriate

Wiring self.atom_exclude_types into self.fitting_net.reinit_exclude(...) at construction time is the right place to fix the PT get_sel_type behavior and is consistent with the existing reinit_exclude API on the fitting side. This should correctly initialize the internal exclusion mask for both training and inference and is safe when atom_exclude_types is empty.

You may also want to consider re-calling reinit_exclude(self.atom_exclude_types) after change_type_map() if ntypes changes but the same excluded indices are expected to remain meaningful.

deepmd/tf/model/model.py (1)

1002-1015: Atom-exclusion → sel_type mapping in TF deserialize looks correct; consider normalizing type

Mapping atom_exclude_types to sel_type via the complement over type_map matches the existing pattern in deepmd.tf.fit.dipole.deserialize and should give TF parity with PT for selected types.

Two small robustness / consistency tweaks to consider:

  • Normalize sel_type to a plain Python list before passing it into Fitting.deserialize, to match other call sites and avoid any downstream assumptions about the type:
-        sel_type = np.setdiff1d(
-                full_type_list, atom_exclude_types, assume_unique=True
-            )
-            fitting_dict["sel_type"] = sel_type
+        sel_type = np.setdiff1d(
+            full_type_list, atom_exclude_types, assume_unique=True
+        )
+        fitting_dict["sel_type"] = sel_type.tolist()
  • If you are not relying on the small speed gain, you could also drop assume_unique=True (as in this code it is not performance‑critical) to be maximally safe against any accidental duplicates in atom_exclude_types.

Please re-run the TF backend model deserialization tests (including any TF↔PT conversion tests) to confirm that Fitting.deserialize is happy with sel_type when provided as a Python list rather than a NumPy array.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9c82d7 and be6c622.

📒 Files selected for processing (3)
  • deepmd/pt/model/atomic_model/dp_atomic_model.py (1 hunks)
  • deepmd/tf/model/model.py (1 hunks)
  • source/tests/pt/model/test_get_model.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
deepmd/tf/model/model.py (3)
source/tests/consistent/model/test_ener.py (2)
  • data (82-112)
  • data (307-337)
source/api_cc/src/common.cc (1)
  • sel_type (80-80)
deepmd/tf/fit/dipole.py (1)
  • deserialize (470-495)
deepmd/pt/model/atomic_model/dp_atomic_model.py (3)
deepmd/pd/model/task/fitting.py (1)
  • reinit_exclude (360-365)
deepmd/pt/model/task/fitting.py (1)
  • reinit_exclude (550-555)
deepmd/dpmodel/fitting/general_fitting.py (1)
  • reinit_exclude (389-394)
source/tests/pt/model/test_get_model.py (1)
deepmd/pt/model/atomic_model/dp_atomic_model.py (1)
  • get_sel_type (387-394)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: Build wheels for cp311-win_amd64
  • GitHub Check: Build wheels for cp311-macosx_arm64
  • GitHub Check: Build wheels for cp310-manylinux_aarch64
  • GitHub Check: Build wheels for cp311-macosx_x86_64
  • GitHub Check: Build wheels for cp311-manylinux_x86_64
  • GitHub Check: Build C++ (cuda120, cuda)
  • GitHub Check: Build C++ (cpu, cpu)
  • GitHub Check: Build C++ (clang, clang)
  • GitHub Check: Build C++ (rocm, rocm)
  • GitHub Check: Test Python (5, 3.10)
  • GitHub Check: Test Python (2, 3.13)
  • GitHub Check: Test Python (1, 3.13)
  • GitHub Check: Test Python (3, 3.13)
  • GitHub Check: Test Python (4, 3.13)
  • GitHub Check: Test Python (5, 3.13)
  • GitHub Check: Test Python (6, 3.13)
  • GitHub Check: Test Python (6, 3.10)
  • GitHub Check: Test Python (4, 3.10)
  • GitHub Check: Test Python (2, 3.10)
  • GitHub Check: Test Python (1, 3.10)
  • GitHub Check: Test Python (3, 3.10)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Test C++ (true, false, false, true)
  • GitHub Check: Test C++ (false, true, true, false)
  • GitHub Check: Test C++ (true, true, true, false)
  • GitHub Check: Test C++ (false, false, false, true)
  • GitHub Check: Build C library (2.18, libdeepmd_c.tar.gz)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
deepmd/tf/model/model.py (1)

1006-1015: TF deserialization: sel_type derivation from atom_exclude_types looks correct; consider minor robustness tweaks

This block correctly enables PT→TF conversion with atom_exclude_types by computing sel_type as the complement over type_map and feeding it into Fitting.deserialize, which aligns with the intended behavior.

Two small, non-blocking robustness points:

  • np.setdiff1d(..., assume_unique=True) assumes atom_exclude_types is unique. If a user ever passes duplicates, behavior can be surprising; dropping assume_unique=True keeps semantics correct at negligible cost.
  • When atom_exclude_types is non-empty, this path requires data["type_map"] to exist. If any legacy models could have atom_exclude_types without type_map, it may be worth guarding with a clearer error (or falling back) instead of a bare KeyError.

If these situations are impossible in your supported formats, the current implementation is fine as-is.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be6c622 and bbb2a49.

📒 Files selected for processing (3)
  • deepmd/pt/model/atomic_model/dp_atomic_model.py (2 hunks)
  • deepmd/tf/model/model.py (1 hunks)
  • source/tests/pt/model/test_get_model.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/tests/pt/model/test_get_model.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-16T21:49:57.401Z
Learnt from: njzjz
Repo: deepmodeling/deepmd-kit PR: 4226
File: deepmd/dpmodel/atomic_model/base_atomic_model.py:202-202
Timestamp: 2024-10-16T21:49:57.401Z
Learning: When reviewing PRs, avoid making refactor suggestions that are not directly related to the PR's changes. For example, in `deepmd/dpmodel/atomic_model/base_atomic_model.py`, do not suggest simplifying `for kk in ret_dict.keys()` to `for kk in ret_dict` unless it's relevant to the PR.

Applied to files:

  • deepmd/pt/model/atomic_model/dp_atomic_model.py
🧬 Code graph analysis (2)
deepmd/tf/model/model.py (3)
deepmd/tf/fit/fitting.py (2)
  • Fitting (32-266)
  • deserialize (86-108)
deepmd/tf/fit/dipole.py (1)
  • deserialize (470-495)
deepmd/tf/fit/polar.py (1)
  • deserialize (691-714)
deepmd/pt/model/atomic_model/dp_atomic_model.py (1)
deepmd/pt/model/task/fitting.py (1)
  • reinit_exclude (550-555)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: Build wheels for cp310-manylinux_aarch64
  • GitHub Check: Build wheels for cp311-manylinux_x86_64
  • GitHub Check: Build wheels for cp311-macosx_arm64
  • GitHub Check: Build wheels for cp311-macosx_x86_64
  • GitHub Check: Build wheels for cp311-win_amd64
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (python)
  • GitHub Check: Build C++ (cuda120, cuda)
  • GitHub Check: Build C++ (cpu, cpu)
  • GitHub Check: Build C library (2.18, libdeepmd_c.tar.gz)
  • GitHub Check: Build C++ (rocm, rocm)
  • GitHub Check: Build C++ (clang, clang)
  • GitHub Check: Test C++ (false, false, false, true)
  • GitHub Check: Test C++ (true, false, false, true)
  • GitHub Check: Test C++ (true, true, true, false)
  • GitHub Check: Test C++ (false, true, true, false)
🔇 Additional comments (2)
deepmd/pt/model/atomic_model/dp_atomic_model.py (2)

67-67: Hooking atom_exclude_types into fitting_net on initialization

Calling self.fitting_net.reinit_exclude(self.atom_exclude_types) right after assigning self.fitting_net ensures the fitting’s internal exclusion mask (and thus get_sel_type()) is consistent with the atomic model’s atom_exclude_types from the moment the model is constructed. This directly addresses the reported PT-trained get_sel_type discrepancy and looks correct given the existing reinit_exclude API.


155-156: Refreshing fitting exclusion after type_map changes

Reinvoking self.fitting_net.reinit_exclude(self.atom_exclude_types) immediately after change_type_map() is important to rebuild the exclusion mask with the updated number and ordering of types, so get_sel_type() remains consistent after type remapping. This is a clean, localized fix with no obvious side effects.

@codecov
Copy link

codecov bot commented Dec 15, 2025

Codecov Report

❌ Patch coverage is 92.85714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 82.14%. Comparing base (26013cb) to head (d9f1b6d).
⚠️ Report is 2 commits behind head on devel.

Files with missing lines Patch % Lines
deepmd/dpmodel/atomic_model/dp_atomic_model.py 66.66% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            devel    #5097   +/-   ##
=======================================
  Coverage   82.14%   82.14%           
=======================================
  Files         709      709           
  Lines       72458    72467    +9     
  Branches     3615     3615           
=======================================
+ Hits        59520    59531   +11     
+ Misses      11776    11774    -2     
  Partials     1162     1162           

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
source/tests/consistent/model/test_polar.py (1)

202-208: LGTM! Test correctly verifies cross-backend consistency.

The test appropriately validates that TF and PT backends compute the same sel_type after deserialization with atom_exclude_types. This directly addresses the PR objective of ensuring PyTorch models respect atom exclusions.

Consider adding an explicit assertion for the expected value to make the test more robust:

     def test_atom_exclude_types(self):
         _ret, data = self.get_reference_ret_serialization(self.RefBackend.PT)
         data["atom_exclude_types"] = [1]
         self.reset_unique_id()
         tf_obj = self.tf_class.deserialize(data, suffix=self.unique_id)
         pt_obj = self.pt_class.deserialize(data)
+        # With type_map ["O", "H"] and excluding type 1, sel_type should be [0]
+        self.assertEqual(pt_obj.get_sel_type(), [0])
         self.assertEqual(tf_obj.get_sel_type(), pt_obj.get_sel_type())
source/tests/consistent/model/test_dipole.py (1)

208-214: LGTM! Test correctly verifies cross-backend consistency.

The test appropriately validates that TF and PT backends compute the same sel_type after deserialization with atom_exclude_types. This ensures the dipole model correctly respects atom exclusions.

Consider adding an explicit assertion for the expected value to make the test more robust:

     def test_atom_exclude_types(self):
         _ret, data = self.get_reference_ret_serialization(self.RefBackend.PT)
         data["atom_exclude_types"] = [1]
         self.reset_unique_id()
         tf_obj = self.tf_class.deserialize(data, suffix=self.unique_id)
         pt_obj = self.pt_class.deserialize(data)
+        # With type_map ["O", "H"] and excluding type 1, sel_type should be [0]
+        self.assertEqual(pt_obj.get_sel_type(), [0])
         self.assertEqual(tf_obj.get_sel_type(), pt_obj.get_sel_type())
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa5ced2 and 77b9503.

📒 Files selected for processing (2)
  • source/tests/consistent/model/test_dipole.py (1 hunks)
  • source/tests/consistent/model/test_polar.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
source/tests/consistent/model/test_polar.py (1)
deepmd/tf/fit/polar.py (3)
  • deserialize (691-714)
  • get_sel_type (207-209)
  • get_sel_type (776-778)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Test C++ (true, true, true, false)
  • GitHub Check: Test C++ (false, false, false, true)
  • GitHub Check: Test C++ (false, true, true, false)
  • GitHub Check: Test C++ (true, false, false, true)
  • GitHub Check: Build wheels for cp311-win_amd64
  • GitHub Check: Test Python (1, 3.13)
  • GitHub Check: Test Python (1, 3.10)
  • GitHub Check: Test Python (4, 3.13)
  • GitHub Check: Test Python (3, 3.13)
  • GitHub Check: Test Python (4, 3.10)
  • GitHub Check: Test Python (5, 3.10)
  • GitHub Check: Test Python (6, 3.10)
  • GitHub Check: Test Python (5, 3.13)
  • GitHub Check: Test Python (2, 3.13)
  • GitHub Check: Test Python (3, 3.10)
  • GitHub Check: Test Python (2, 3.10)
  • GitHub Check: Test Python (6, 3.13)
  • GitHub Check: Build wheels for cp310-manylinux_aarch64
  • GitHub Check: Build wheels for cp311-manylinux_x86_64
  • GitHub Check: Build wheels for cp311-macosx_arm64
  • GitHub Check: Build wheels for cp311-macosx_x86_64
  • GitHub Check: Build C library (2.18, libdeepmd_c.tar.gz)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (python)
  • GitHub Check: Build C++ (cpu, cpu)
  • GitHub Check: Build C++ (cuda120, cuda)
  • GitHub Check: Build C++ (clang, clang)
  • GitHub Check: Build C++ (rocm, rocm)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
deepmd/pt/model/atomic_model/dp_atomic_model.py (1)

156-157: Inconsistency: Missing hasattr check for consistency.

Line 67 defensively checks hasattr(self.fitting_net, "reinit_exclude") before calling the method, but line 157 calls it directly without the check. All fitting types in the inheritance chain (Fitting, GeneralFitting, InvarFitting, and their subclasses) implement reinit_exclude, so the code is safe. However, add the same defensive check here for consistency with the __init__ pattern:

if hasattr(self.fitting_net, "reinit_exclude"):
    self.fitting_net.reinit_exclude(self.atom_exclude_types)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77b9503 and b693ae0.

📒 Files selected for processing (5)
  • deepmd/pt/model/atomic_model/dp_atomic_model.py (2 hunks)
  • deepmd/tf/model/model.py (1 hunks)
  • source/tests/consistent/model/test_dipole.py (1 hunks)
  • source/tests/consistent/model/test_polar.py (1 hunks)
  • source/tests/pt/model/test_get_model.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • deepmd/tf/model/model.py
  • source/tests/pt/model/test_get_model.py
  • source/tests/consistent/model/test_polar.py
  • source/tests/consistent/model/test_dipole.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-16T21:49:57.401Z
Learnt from: njzjz
Repo: deepmodeling/deepmd-kit PR: 4226
File: deepmd/dpmodel/atomic_model/base_atomic_model.py:202-202
Timestamp: 2024-10-16T21:49:57.401Z
Learning: When reviewing PRs, avoid making refactor suggestions that are not directly related to the PR's changes. For example, in `deepmd/dpmodel/atomic_model/base_atomic_model.py`, do not suggest simplifying `for kk in ret_dict.keys()` to `for kk in ret_dict` unless it's relevant to the PR.

Applied to files:

  • deepmd/pt/model/atomic_model/dp_atomic_model.py
🧬 Code graph analysis (1)
deepmd/pt/model/atomic_model/dp_atomic_model.py (3)
deepmd/pd/model/task/fitting.py (1)
  • reinit_exclude (360-365)
deepmd/pt/model/task/fitting.py (1)
  • reinit_exclude (550-555)
deepmd/dpmodel/fitting/general_fitting.py (1)
  • reinit_exclude (389-394)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Test Python (4, 3.13)
  • GitHub Check: Test Python (5, 3.10)
  • GitHub Check: Test Python (6, 3.13)
  • GitHub Check: Test Python (6, 3.10)
  • GitHub Check: Test Python (5, 3.13)
  • GitHub Check: Test Python (1, 3.13)
  • GitHub Check: Test Python (2, 3.10)
  • GitHub Check: Test Python (4, 3.10)
  • GitHub Check: Test Python (3, 3.13)
  • GitHub Check: Test Python (2, 3.13)
  • GitHub Check: Test Python (1, 3.10)
  • GitHub Check: Test Python (3, 3.10)
  • GitHub Check: Build C library (2.18, libdeepmd_c.tar.gz)
  • GitHub Check: Build C++ (cpu, cpu)
  • GitHub Check: Build C++ (rocm, rocm)
  • GitHub Check: Build C++ (clang, clang)
  • GitHub Check: Build C++ (cuda120, cuda)
  • GitHub Check: Build wheels for cp310-manylinux_aarch64
  • GitHub Check: Build wheels for cp311-macosx_x86_64
  • GitHub Check: Build wheels for cp311-win_amd64
  • GitHub Check: Build wheels for cp311-macosx_arm64
  • GitHub Check: Build wheels for cp311-manylinux_x86_64
  • GitHub Check: Test C++ (true, false, false, true)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (python)
  • GitHub Check: Test C++ (true, true, true, false)
  • GitHub Check: Test C++ (false, false, false, true)
  • GitHub Check: Test C++ (false, true, true, false)
🔇 Additional comments (1)
deepmd/pt/model/atomic_model/dp_atomic_model.py (1)

67-68: Core fix correctly initializes exclusion state.

The conditional call to reinit_exclude ensures the fitting network's exclusion mask reflects atom_exclude_types from initialization, fixing the get_sel_type discrepancy described in issue #5096.

@wanghan-iapcm wanghan-iapcm requested a review from njzjz December 16, 2025 09:58
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (1)

77-81: Utility function duplicates logic from production code.

The function correctly computes the complement of atom_exclude_types, but this logic is duplicated in deepmd/tf/model/model.py (lines 1010-1012). Consider extracting this to a shared utility module to reduce duplication and maintenance burden.

Would you like me to generate a refactoring that extracts this to a shared utility module, such as deepmd/utils/atom_exclude.py?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b20a888 and 2b15f10.

📒 Files selected for processing (7)
  • deepmd/dpmodel/atomic_model/dp_atomic_model.py (2 hunks)
  • deepmd/pt/model/atomic_model/dp_atomic_model.py (2 hunks)
  • deepmd/tf/model/model.py (1 hunks)
  • source/tests/consistent/model/test_dipole.py (1 hunks)
  • source/tests/consistent/model/test_polar.py (1 hunks)
  • source/tests/pt/model/test_get_model.py (1 hunks)
  • source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (17 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/tests/pt/model/test_get_model.py
  • deepmd/pt/model/atomic_model/dp_atomic_model.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-16T21:49:57.401Z
Learnt from: njzjz
Repo: deepmodeling/deepmd-kit PR: 4226
File: deepmd/dpmodel/atomic_model/base_atomic_model.py:202-202
Timestamp: 2024-10-16T21:49:57.401Z
Learning: When reviewing PRs, avoid making refactor suggestions that are not directly related to the PR's changes. For example, in `deepmd/dpmodel/atomic_model/base_atomic_model.py`, do not suggest simplifying `for kk in ret_dict.keys()` to `for kk in ret_dict` unless it's relevant to the PR.

Applied to files:

  • deepmd/dpmodel/atomic_model/dp_atomic_model.py
🧬 Code graph analysis (5)
source/tests/consistent/model/test_dipole.py (4)
source/tests/consistent/model/test_polar.py (3)
  • test_atom_exclude_types (202-212)
  • skip_tf (92-93)
  • data (46-69)
deepmd/tf/fit/dipole.py (2)
  • deserialize (470-495)
  • get_sel_type (160-162)
deepmd/tf/fit/polar.py (3)
  • deserialize (691-714)
  • get_sel_type (207-209)
  • get_sel_type (776-778)
deepmd/tf/model/tensor.py (1)
  • get_sel_type (81-82)
deepmd/dpmodel/atomic_model/dp_atomic_model.py (7)
deepmd/dpmodel/fitting/general_fitting.py (2)
  • reinit_exclude (389-394)
  • change_type_map (327-347)
deepmd/dpmodel/descriptor/se_t.py (1)
  • reinit_exclude (310-315)
deepmd/pt/model/model/make_model.py (1)
  • change_type_map (503-514)
deepmd/pt/model/atomic_model/base_atomic_model.py (1)
  • change_type_map (303-334)
deepmd/dpmodel/atomic_model/base_atomic_model.py (1)
  • change_type_map (134-149)
deepmd/dpmodel/atomic_model/linear_atomic_model.py (1)
  • change_type_map (115-130)
deepmd/dpmodel/descriptor/make_base_descriptor.py (1)
  • change_type_map (131-137)
deepmd/tf/model/model.py (3)
source/tests/consistent/fitting/test_dipole.py (1)
  • data (68-82)
deepmd/tf/fit/fitting.py (2)
  • Fitting (32-266)
  • deserialize (86-108)
deepmd/tf/fit/dipole.py (1)
  • deserialize (470-495)
source/tests/consistent/model/test_polar.py (2)
deepmd/tf/fit/polar.py (2)
  • get_sel_type (207-209)
  • get_sel_type (776-778)
deepmd/tf/model/tensor.py (1)
  • get_sel_type (81-82)
source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (2)
deepmd/dpmodel/atomic_model/dp_atomic_model.py (1)
  • get_sel_type (243-250)
deepmd/dpmodel/atomic_model/linear_atomic_model.py (1)
  • get_sel_type (353-363)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Build wheels for cp311-macosx_x86_64
  • GitHub Check: Build wheels for cp311-macosx_arm64
  • GitHub Check: Build wheels for cp311-win_amd64
  • GitHub Check: Build wheels for cp311-manylinux_x86_64
  • GitHub Check: Build wheels for cp310-manylinux_aarch64
  • GitHub Check: Test Python (5, 3.10)
  • GitHub Check: Test Python (5, 3.13)
  • GitHub Check: Test Python (4, 3.13)
  • GitHub Check: Test Python (2, 3.10)
  • GitHub Check: Test Python (6, 3.13)
  • GitHub Check: Test Python (1, 3.13)
  • GitHub Check: Test Python (3, 3.13)
  • GitHub Check: Test Python (4, 3.10)
  • GitHub Check: Test Python (3, 3.10)
  • GitHub Check: Test Python (6, 3.10)
  • GitHub Check: Test Python (1, 3.10)
  • GitHub Check: Test Python (2, 3.13)
  • GitHub Check: Build C++ (cpu, cpu)
  • GitHub Check: Build C++ (cuda120, cuda)
  • GitHub Check: Build C++ (rocm, rocm)
  • GitHub Check: Build C++ (clang, clang)
  • GitHub Check: Test C++ (false, true, true, false)
  • GitHub Check: Test C++ (false, false, false, true)
  • GitHub Check: Test C++ (true, false, false, true)
  • GitHub Check: Test C++ (true, true, true, false)
  • GitHub Check: Build C library (2.18, libdeepmd_c.tar.gz)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (python)
🔇 Additional comments (6)
deepmd/dpmodel/atomic_model/dp_atomic_model.py (2)

54-55: LGTM! Correctly initializes fitting exclusion state.

The conditional call to self.fitting.reinit_exclude(self.atom_exclude_types) ensures that the fitting's exclusion settings are properly initialized during DPAtomicModel construction, which is essential for get_sel_type() to return the correct selected atom types.


196-196: Bug fix: Use correct attribute name.

Changed from self.fitting_net.change_type_map(type_map=type_map) to self.fitting.change_type_map(type_map=type_map). This corrects the attribute name to match the actual assignment at line 53 (self.fitting = fitting).

source/tests/consistent/model/test_polar.py (1)

202-212: LGTM! Cross-backend consistency test for atom_exclude_types.

The test correctly validates that atom_exclude_types is handled consistently between TF and PT backends by comparing get_sel_type() results after deserialization. The skip checks appropriately handle unavailable backends.

source/tests/consistent/model/test_dipole.py (1)

208-218: LGTM! Cross-backend consistency test for atom_exclude_types.

The test validates that atom_exclude_types is handled consistently between TF and PT backends for dipole models. The implementation properly skips when backends are unavailable, addressing the past review comment.

source/tests/universal/dpmodel/atomc_model/test_atomic_model.py (1)

97-97: LGTM! Comprehensive test coverage for atom_exclude_types.

The parameterization includes both empty ([]) and non-empty ([0]) atom_exclude_types values, and the test method test_sel_type_from_atom_exclude_types validates that the utility function produces the expected sel_type. This pattern is consistently applied across all test classes.

Also applies to: 110-110, 142-143, 150-156

deepmd/tf/model/model.py (1)

1006-1015: Fix: Code pattern does NOT match the reference implementation in dipole.py and assumes uniqueness without validation.

The implementation uses np.setdiff1d(..., assume_unique=True) which differs from the reference pattern in deepmd/tf/fit/dipole.py (lines 469-494), which uses a list comprehension: [ii for ii in range(data["ntypes"]) if ii not in exclude_types].

The assume_unique=True parameter has undefined behavior if atom_exclude_types contains duplicates, per NumPy documentation. No validation exists in the codebase to ensure uniqueness. Consider either:

  • Adding validation to check for duplicates in atom_exclude_types, or
  • Using the safer list comprehension approach from dipole.py that doesn't require the uniqueness assumption
⛔ Skipped due to learnings
Learnt from: njzjz
Repo: deepmodeling/deepmd-kit PR: 4226
File: deepmd/dpmodel/atomic_model/base_atomic_model.py:202-202
Timestamp: 2024-10-16T21:49:57.401Z
Learning: When reviewing PRs, avoid making refactor suggestions that are not directly related to the PR's changes. For example, in `deepmd/dpmodel/atomic_model/base_atomic_model.py`, do not suggest simplifying `for kk in ret_dict.keys()` to `for kk in ret_dict` unless it's relevant to the PR.

@njzjz njzjz requested a review from iProzd December 17, 2025 00:39
@iProzd iProzd added this pull request to the merge queue Dec 17, 2025
github-merge-queue bot pushed a commit that referenced this pull request Dec 17, 2025
1. Allow backend-convert from pt to tf with `atom_exclude_types`
2. Fix bug in `get_sel_type` method of pt model (by calling
`fitting.reinit_exclude` in atomic model init).

Fix #5096 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Fitting now reinitializes exclusion/selection settings during model
init and after type-map changes, and deserialization injects selection
info when atom exclusions exist, ensuring correct selection behavior.

* **Tests**
* Added unit and cross-backend tests to verify atom-exclude → selection
computation and parity between backends; expanded test coverage for
exclusion scenarios.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@njzjz njzjz removed this pull request from the merge queue due to the queue being cleared Dec 17, 2025
@njzjz njzjz added this pull request to the merge queue Dec 19, 2025
Merged via the queue into deepmodeling:devel with commit 3020ff7 Dec 19, 2025
58 checks passed
@ChiahsinChu ChiahsinChu deleted the devel-pt-sel_type branch December 20, 2025 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] incorrect sel_type in pt model

3 participants