Skip to content

fix(pair-tab): validate uniform distance grid to avoid silently wrong potentials - #5908

Open
hanaol wants to merge 8 commits into
deepmodeling:masterfrom
hanaol:fix/pairtab-nonuniform-grid
Open

fix(pair-tab): validate uniform distance grid to avoid silently wrong potentials#5908
hanaol wants to merge 8 commits into
deepmodeling:masterfrom
hanaol:fix/pairtab-nonuniform-grid

Conversation

@hanaol

@hanaol hanaol commented Jul 26, 2026

Copy link
Copy Markdown

Summary

PairTab (used for use_srtab and ZBL tab_file short-range tables) assumes the distance grid is uniformly spaced, but never validates it. A non-uniform table is silently accepted and produces incorrect potentials with no error or warning.

Problem

PairTab.reinit() infers a single stride from the first two rows only:

self.hh = self.vdata[1][0] - self.vdata[0][0]

self.hh is then baked into the spline coefficients and stored in tab_info, and the C++ inference kernel (source/lib/src/pair_tab.cc) maps distance to table index purely as idx = floor((r - rmin) / hh) . No per-row distances are kept, so a non-uniform grid is impossible to represent.

Also, the uniform-grid requirement is documented (doc/model/pairtab.md: the table is defined "on an evenly discretized grid"), but nothing enforced it.

Fix

Validate in reinit() that every distance interval matches the inferred stride, and raise a ValueError otherwise. The check runs before any spline is built, so a bad table is rejected up front instead of mis-indexed later.

Tests

Added TestPairTabGridSpacing in
source/tests/common/dpmodel/test_pairtab_preprocess.py:

test_non_uniform_grid — a table with a changing stride now raises ValueError.
test_uniform_grid — a uniformly spaced table is still accepted.

Summary by CodeRabbit

  • Bug Fixes
    • Pairwise tables now validate the loaded distance grid before updating internal state.
    • Non-uniform, duplicate, or descending grids now fail fast with a clear ValueError advising to regrid.
    • Evenly spaced uniform grids still initialize with the expected spacing.
  • Tests
    • Added unit coverage for non-uniform, duplicate, descending, and uniform distance grids (including small-grid edge cases).
    • Added verification that a failed reinitialization preserves the previously serialized state.

… potentials

Signed-off-by: hanaol <ho0950@princeton.edu>
@dosubot dosubot Bot added the bug label Jul 26, 2026
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

PairTab.reinit validates radial-grid ordering and uniform spacing before updating instance state. Tests cover invalid grids, failed reinitialization state preservation, fine-grid handling, and successful spacing inference.

Changes

Pair table grid validation

Layer / File(s) Summary
Grid validation and state commit
deepmd/utils/pair_tab.py
PairTab.reinit rejects duplicate, descending, or uneven distance grids before computing and storing derived table state.
Grid validation tests
source/tests/common/dpmodel/test_pairtab_preprocess.py
Tests cover invalid and fine grids, preservation of serialized state after failed reinitialization, and successful hh inference for 0.01 and 1e-9 spacing.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% 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 clearly matches the main change: validating pair-tab distance grids to prevent incorrect potentials.
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.
✨ 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.

@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: 2

🤖 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/utils/pair_tab.py`:
- Around line 64-72: Update the radial-grid validation in the pair-table
initialization around vdata and dx to explicitly reject any non-positive
distance interval before or alongside the existing uniform-spacing check.
Preserve the current ValueError behavior for uneven grids, ensure duplicate and
descending grids cannot proceed to hh-dependent division or padding, and add
regression coverage for both cases.
- Around line 64-72: Make reinit() validate the newly loaded table using local
variables before modifying self.vdata, self.rmin, self.rmax, or self.hh. Move
the non-uniform-grid check and any related validation ahead of committing
instance state, then update all instance metadata and tab_info/tab_data together
only after validation succeeds, preserving the existing object unchanged when
validation raises.
🪄 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 Plus

Run ID: 259347aa-00a8-4fe1-b26d-3bf7c9ddeb92

📥 Commits

Reviewing files that changed from the base of the PR and between cc908a8 and 492e2e5.

📒 Files selected for processing (2)
  • deepmd/utils/pair_tab.py
  • source/tests/common/dpmodel/test_pairtab_preprocess.py

Comment thread deepmd/utils/pair_tab.py Outdated
Address review feedback on the pairwise table validation:

- A constant zero or negative distance stride passed the uniform-spacing
  check, leaving hh == 0 (division by zero) or hh < 0 with rmin > rmax in
  the padding and extrapolation arithmetic. Require a strictly increasing
  grid before checking uniformity.
- reinit() assigned vdata/rmin/rmax/hh before validating, so a failed
  reinit of a live PairTab left the new metadata next to the stale
  tab_info/tab_data. Validate locals first and commit instance state only
  once all checks pass.

Add regression tests for duplicate and descending grids, and assert that a
failed reinit leaves the serialized table unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: hanaol <ho0950@princeton.edu>
@hanaol

hanaol commented Jul 28, 2026

Copy link
Copy Markdown
Author

Thanks for the review — both findings addressed in f87eeb7, with two intentional deviations from the suggested diffs:

  1. Strictly increasing grid. Implemented as a separate check with its own error message rather than folding np.all(dx > 0) into the existing allclose condition. A descending grid with a constant negative step is evenly spaced, so reusing the "not evenly spaced" text would have misdescribed the failure. Duplicate rows and descending tables now raise "not strictly increasing"; genuinely uneven grids keep the original message.

  2. Atomic reinit(). Validation now runs against locals and instance state is committed only once every check passes. I also moved the ntypes assert inside the atomic region — otherwise a table with a bad column count would still have left the object half-updated.

Regression tests added for the duplicate-distance and descending-grid cases, plus one asserting that a failed reinit() on a live PairTab leaves the serialized table byte-for-byte unchanged.

@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

🤖 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 `@source/tests/common/dpmodel/test_pairtab_preprocess.py`:
- Around line 334-354: Update the test’s serialized-state snapshot by importing
copy and deep-copying the result of PairTab.serialize() before reinit(), so
expected arrays cannot alias live state. Replace np.testing.assert_allclose
comparisons for vdata, tab_info, and tab_data with exact array comparisons while
preserving the existing scalar checks; run the focused pytest case, ruff check
., and ruff format .
🪄 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 Plus

Run ID: 2cf3e420-5b67-4128-a098-f7b7e161b1da

📥 Commits

Reviewing files that changed from the base of the PR and between 492e2e5 and f87eeb7.

📒 Files selected for processing (2)
  • deepmd/utils/pair_tab.py
  • source/tests/common/dpmodel/test_pairtab_preprocess.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • deepmd/utils/pair_tab.py

Comment thread source/tests/common/dpmodel/test_pairtab_preprocess.py Outdated
hanaol and others added 3 commits July 28, 2026 15:38
serialize() returns references to the live vdata/tab_info/tab_data arrays,
so deep-copy the expected snapshot rather than aliasing it, and compare the
arrays exactly since a failed reinit must leave them untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: hanaol <ho0950@princeton.edu>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: hanaol <ho0950@princeton.edu>

@njzjz-bot njzjz-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.

Request changes

The uniform-grid check has a scale-dependent false-negative: atol=1e-8 permits clearly non-uniform grids whose spacing is below that absolute tolerance. Please make the tolerance relative to hh (for example, use atol=0 while retaining the relative tolerance) and add a regression test with a small non-uniform step.

Reviewed by OpenClaw 2026.6.11.

Comment thread deepmd/utils/pair_tab.py Outdated
hanaol and others added 2 commits July 29, 2026 11:07
atol=1e-8 dominated the comparison for sub-nanometre grids, so intervals
differing by an order of magnitude still compared equal and the table was
encoded with the smaller stride. Drop the absolute term and rely on rtol,
which is scale-invariant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: hanaol <ho0950@princeton.edu>
@hanaol
hanaol requested a review from njzjz-bot July 29, 2026 20:05
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.96%. Comparing base (4f827cc) to head (b00aeb3).
⚠️ Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5908      +/-   ##
==========================================
- Coverage   79.21%   78.96%   -0.25%     
==========================================
  Files        1069     1069              
  Lines      124070   124080      +10     
  Branches     4522     4527       +5     
==========================================
- Hits        98278    97980     -298     
- Misses      24171    24483     +312     
+ Partials     1621     1617       -4     

☔ 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.

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.

2 participants