Skip to content

feat(dpmodel): complete DPA4/SeZM SO3 grid projection (mirror current pt)#5555

Queued
wanghan-iapcm wants to merge 18 commits into
deepmodeling:masterfrom
wanghan-iapcm:feat-dpmodel-dpa4-so3grid-v2
Queued

feat(dpmodel): complete DPA4/SeZM SO3 grid projection (mirror current pt)#5555
wanghan-iapcm wants to merge 18 commits into
deepmodeling:masterfrom
wanghan-iapcm:feat-dpmodel-dpa4-so3grid-v2

Conversation

@wanghan-iapcm

@wanghan-iapcm wanghan-iapcm commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

What

Completes the DPA4/SeZM SO3 grid projection port to the dpmodel backend so it faithfully mirrors master's current pt sezm_nn/grid_net.py. After this, the flagship examples/water/dpa4/input.json (which sets ffn_so3_grid=true, message_node_so3=true, grid_mlp) runs on dpmodel/pt_expt.

Builds on top of the S2-grid base that #5517/#5552 landed (GridProduct/GridMLP/op_type='mlp', the _project_frames refactor). Master's dpmodel was the S2 (n_frames==1) slice with SO3/cross-mode fail-fast guarded; this PR generalizes those ops to frame-aware (n_frames>1) + cross-mode and adds the missing SO3 pieces — matching current pt exactly (single source of truth: dpmodel == pt).

Supersedes #5547 (which ported the pre-#5552 design and went structurally stale).

Changes (all mirror current pt)

  • grid_net.py: add _project_frames; generalize GridMLP/GridBranch to frame-aware (n_frames); generalize BaseGridNet (un-guard mode='cross', layout='flat', residual_scale_init, n_frames>1; frame-axis to/from-grid via xp.matmul+reshape); add FrameContract/FrameExpand/_build_frame_degree_index; add SO3GridNet (self+cross).
  • projection.py: add SO3GridProjector (Wigner-D quadrature) + resolve_so3_grid/_build_so3_frame_set.
  • ffn.py: un-guard ffn_so3_gridSO3GridNet(mode='self').
  • so2.py: un-guard node_wise_{s2,so3}/message_node_{s2,so3} → cross-mode grid products, applied in call + round-tripped in serialize.

Validation

  • Component parity vs pt (weight-copied fp64): _project_frames, GridMLP/GridBranch (incl. S2 byte-identical regression), BaseGridNet cross/flat/residual, FrameContract/FrameExpand, SO3GridProjector matrices, SO3GridNet self+cross (op_type glu/mlp/branch, kmax 1&2) — all 1e-12; rotation equivariance 1e-10.
  • fp32 grid-path parity at the computation-in-fp32 budget (actual diffs 1e-6–1e-8 ≪ 1e-4).
  • Full-descriptor pt→dpmodel via DescrptDPA4.deserialize(pt.serialize()) on the example config (lmax=3, mmax=1) — ~1e-14 — proving dp convert-backend schema interop.
  • Permutation-invariance + masked-edge no-op.
  • Cross-backend consistency rows (pt vs dpmodel and pt_expt, mixed_types) for ffn_so3_grid / message_node_so3 / both / grid_mlp.
  • Verified on remote GPU (Tesla T4): 617 (grid+parity+pt_expt) + 50 (consistency) pass, no CUDA device errors.

pt_expt forward works today via auto-wrap (consistency + descriptor trio green) — no explicit registration needed.

Known limitations

  • pt_expt training Parameter-promotion for the new weight-bearing grid classes, torch.export/AOTI grid coverage, training e2e, argcheck doc_only_pt_supported removal, and freeze/DeepEval are a follow-up PR.
  • grid_method='e3nn' (non-Lebedev product grid) stays fail-fast (Lebedev-only, per parent design).
  • fp32 grid paths use a ~1e-4 budget by design; fp64 is the parity reference.

Summary by CodeRabbit

  • New Features
    • Added SO(3) grid projection support and frame-aware grid networks for DPA4 descriptors, including SO(3)-based FFN and improved cross-mode grid-product wiring.
    • Extended grid modules to support multi-frame configurations with per-degree frame mixing, and added full SO(3) projector/network serialization.
  • Bug Fixes
    • Enabled previously disabled/unsupported DPA4 SO(2) convolution cross-mode SO(3)/S2 grid products.
  • Documentation
    • Updated DPA4 porting-layer documentation to clarify supported configuration flags.
  • Tests
    • Added/expanded parity, equivariance, serialization/roundtrip, and torch-namespace compatibility tests for the new SO(3) and frame-aware paths.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0f9110c4-8e75-4204-a516-dfd3433f6fab

📥 Commits

Reviewing files that changed from the base of the PR and between 83e0b79 and 8b8608b.

📒 Files selected for processing (2)
  • deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
  • source/tests/common/dpmodel/test_dpa4_so3_gridnet.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/tests/common/dpmodel/test_dpa4_so3_gridnet.py
  • deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py

📝 Walkthrough

Walkthrough

Ports the previously unimplemented SO(3)/S2 cross-mode grid paths in the DPA4 dpmodel descriptor. Adds SO3GridProjector (Lebedev/Wigner-D matrix assembly), FrameContract/FrameExpand mixers, a frame-aware SO3GridNet with generalized BaseGridNet, wires ffn_so3_grid and node/message-node grid products into SO2Convolution, and adds comprehensive parity, equivariance, and serialization tests.

Changes

DPA4 dpmodel SO(3) grid port

Layer / File(s) Summary
SO(3) projector math
deepmd/dpmodel/descriptor/dpa4_nn/projection.py
Adds SO3GridProjector (Lebedev quadrature + Wigner-D matrix construction), resolve_so3_grid, and _build_so3_frame_set helpers with serialize/deserialize support.
Frame utilities
deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
Introduces _project_frames, _build_frame_degree_index, _FrameMixer base, and public FrameContract/FrameExpand classes for per-degree channel mixing across SO(3) frames.
Frame-aware grid operators and generalized BaseGridNet
deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
Adds n_frames to GridMLP/GridBranch constructors and call paths; generalizes BaseGridNet with frame_expand/frame_contract seams, residual scaling, and staged call pipeline; extends S2GridNet serialization; adds new SO3GridNet class.
FFN SO3 path and SO2Convolution cross-mode wiring
deepmd/dpmodel/descriptor/dpa4_nn/ffn.py, deepmd/dpmodel/descriptor/dpa4_nn/so2.py, deepmd/dpmodel/descriptor/dpa4_nn/block.py
Removes ffn_so3_grid=True guard; instantiates SO3GridNet in EquivariantFFN; sets grid_n_frames=2*kmax+1. Wires node_wise_grid_product and message_node_grid_product into SO2Convolution.call() as residuals; extends _variables()/_load_variables() for serialization round-trip.
Tests: foundations
source/tests/common/dpmodel/test_dpa4_so3_grid_utils.py, test_dpa4_so3_projector.py, test_dpa4_project_frames.py, test_dpa4_frame_mixers.py, test_dpa4_gridmlp_frames.py, test_dpa4_gridbranch_frames.py
Parity, round-trip, equivariance, serialization, and torch-namespace tests for projector utilities, frame mixer classes, per-frame projection helpers, and frame-aware grid operators.
Tests: integration
source/tests/common/dpmodel/test_dpa4_so3_gridnet.py, test_dpa4_basegridnet_cross.py, test_dpa4_ffn_so3.py, test_dpa4_so2_grid.py, test_dpa4_grid_descriptor.py, source/tests/consistent/descriptor/test_dpa4.py, source/tests/pt/model/test_dpa4_dpmodel_parity.py, source/tests/common/dpmodel/test_descrpt_dpa4.py
End-to-end parity/equivariance/fp32/serialize tests for SO3GridNet and S2GridNet cross-mode; SO2Convolution node-wise/message-node grid parity; FFN SO3 parity/serialize; full descriptor pt↔dpmodel interop and invariance; consistent test cases for new flags; guard/parity test updates removing now-ported NotImplementedError cases.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant EquivariantFFN
  participant SO3GridNet
  participant BaseGridNet
  participant FrameExpand
  participant GridOp as GridMLP/GridBranch
  participant FrameContract

  Caller->>EquivariantFFN: call(x_coeffs)
  EquivariantFFN->>SO3GridNet: act(x_coeffs) [ffn_so3_grid=True]
  SO3GridNet->>BaseGridNet: call(query, context=None)
  BaseGridNet->>FrameExpand: expand packed frames
  FrameExpand-->>BaseGridNet: expanded coefficients
  BaseGridNet->>GridOp: to_grid / quadratic product / from_grid
  GridOp-->>BaseGridNet: grid op output
  BaseGridNet->>FrameContract: contract back to channel dim
  FrameContract-->>BaseGridNet: contracted output
  BaseGridNet-->>SO3GridNet: result + residual_scale
  SO3GridNet-->>EquivariantFFN: activated features
  EquivariantFFN-->>Caller: updated x_coeffs
Loading
sequenceDiagram
  participant SO2Conv as SO2Convolution.call
  participant NodeWise as node_wise_grid_product
  participant AttnAgg as attention aggregation
  participant MsgNode as message_node_grid_product

  SO2Conv->>NodeWise: (x_dst_local, x_local) → residual [if enabled]
  NodeWise-->>SO2Conv: add to x_local before SO(2) focus
  SO2Conv->>AttnAgg: SO(2) convolution + edge aggregation → out
  SO2Conv->>MsgNode: (out, node features) → residual [if enabled]
  MsgNode-->>SO2Conv: add to out before final channel mixing
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • deepmodeling/deepmd-kit#5503: Adds the PT-side SO3GridNet, SO3GridProjector, and ffn_so3_grid/*_so3 wiring in SeZM that this PR ports to the dpmodel implementation.
  • deepmodeling/deepmd-kit#5515: Introduces core dpmodel DPA4 infrastructure (SO2Convolution, EquivariantFFN, grid_net.py) that this PR extends with SO(3) frame-aware capabilities.

Suggested labels

Core

Suggested reviewers

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

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.17% 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 PR title clearly summarizes the main change: completing DPA4/SeZM SO3 grid projection to mirror the PyTorch implementation, which is the primary objective of all the substantial code changes in the changeset.
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 source/tests/common/dpmodel/test_dpa4_so2_grid.py Fixed
@wanghan-iapcm wanghan-iapcm requested a review from OutisLi June 18, 2026 15:50
@wanghan-iapcm wanghan-iapcm added the Test CUDA Trigger test CUDA workflow label Jun 18, 2026
@github-actions github-actions Bot removed the Test CUDA Trigger test CUDA workflow label Jun 18, 2026

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

🧹 Nitpick comments (2)
source/tests/common/dpmodel/test_dpa4_so3_gridnet.py (1)

333-338: ⚡ Quick win

Assert both frame-mixer variables are absent in self mode.

test_so3_serialize_roundtrip only checks "frame_expand.weight" is absent for mode="self". Add the symmetric check for "frame_contract.weight" to prevent silent schema regressions.

Suggested patch
     if mode == "cross":
         assert "frame_expand.weight" in data["`@variables`"]
         assert "frame_contract.weight" in data["`@variables`"]
     else:
         assert "frame_expand.weight" not in data["`@variables`"]
+        assert "frame_contract.weight" not in data["`@variables`"]
🤖 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/common/dpmodel/test_dpa4_so3_gridnet.py` around lines 333 - 338,
In the test_so3_serialize_roundtrip function, the else block (which handles
mode="self") only asserts that "frame_expand.weight" is absent from
data["`@variables`"] but is missing the symmetric check for
"frame_contract.weight". Add an additional assert statement in the else block to
verify that "frame_contract.weight" is also not in data["`@variables`"], mirroring
the structure of the cross mode block which checks both variables.
source/tests/common/dpmodel/test_dpa4_so2_grid.py (1)

194-197: ⚡ Quick win

Add a non-trivial-output guard to avoid vacuous parity passes.

_assert_conv_parity currently only checks DP/PT closeness. Add a simple magnitude guard so parity can’t pass if both outputs collapse to (near) zero.

Suggested patch
     out_dp = dp_mod.call(x, dp_cache, radial)
     out_pt = pt_mod(_to_pt(x), pt_cache, _to_pt(radial_valid))
+    assert np.max(np.abs(np.asarray(out_dp))) > 1e-8
     _assert_parity(out_dp, out_pt, rtol=rtol, atol=atol)
🤖 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/common/dpmodel/test_dpa4_so2_grid.py` around lines 194 - 197,
The _assert_parity function currently only checks if DP and PT outputs are close
to each other, which means the test can pass vacuously if both outputs collapse
to near-zero values. Add a magnitude guard within the _assert_parity function
that verifies at least one of the outputs has a non-trivial magnitude (e.g.,
check that the absolute maximum value or norm of the outputs exceeds a small
threshold) before asserting their closeness, ensuring the parity test only
passes when the outputs are both meaningful and close to each other.
🤖 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/dpmodel/descriptor/dpa4_nn/grid_net.py`:
- Around line 1532-1544: The code in the class method (around the
projector_config assignment) is accessing only the `["config"]` portion of the
projector object, bypassing validation of the nested `@class` and `@version`
schema fields. Before extracting and using projector_config, validate the full
projector object structure (the complete config["projector"] payload) to ensure
it conforms to the expected schema and version, preventing acceptance of wrong
or incompatible projector schemas when rebuilding the object.
- Around line 950-956: The operands query and context_ndfc are being passed to
self.frame_expand() without first casting them to compute_dtype, unlike
scalar_pair which is properly cast on lines 952-953. This causes dtype
mismatches when fp32 inputs flow through float64 grid nets. Cast both query and
context_ndfc to compute_dtype (using xp.astype) before passing them to the
self.frame_expand() calls in the return statement, similar to how scalar_pair is
cast to compute_dtype.

In `@deepmd/dpmodel/descriptor/dpa4_nn/so2.py`:
- Around line 1827-1841: The deserialization of `node_wise_grid_product` and
`message_node_grid_product` does not validate that the template contains only
expected keys before calling `deserialize()`. After assigning the result of
`sub_vars()` to the `@variables` key in the template, add validation to reject
any unexpected or unknown top-level keys in the template before passing it to
the `deserialize()` method for both `node_wise_grid_product` and
`message_node_grid_product`. This prevents schema drift keys from being silently
ignored during the deserialization process.

---

Nitpick comments:
In `@source/tests/common/dpmodel/test_dpa4_so2_grid.py`:
- Around line 194-197: The _assert_parity function currently only checks if DP
and PT outputs are close to each other, which means the test can pass vacuously
if both outputs collapse to near-zero values. Add a magnitude guard within the
_assert_parity function that verifies at least one of the outputs has a
non-trivial magnitude (e.g., check that the absolute maximum value or norm of
the outputs exceeds a small threshold) before asserting their closeness,
ensuring the parity test only passes when the outputs are both meaningful and
close to each other.

In `@source/tests/common/dpmodel/test_dpa4_so3_gridnet.py`:
- Around line 333-338: In the test_so3_serialize_roundtrip function, the else
block (which handles mode="self") only asserts that "frame_expand.weight" is
absent from data["`@variables`"] but is missing the symmetric check for
"frame_contract.weight". Add an additional assert statement in the else block to
verify that "frame_contract.weight" is also not in data["`@variables`"], mirroring
the structure of the cross mode block which checks both variables.
🪄 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: 8516e16a-0724-4162-a7a7-f1167567c8f4

📥 Commits

Reviewing files that changed from the base of the PR and between d0a1959 and 4a7be0e.

📒 Files selected for processing (19)
  • deepmd/dpmodel/descriptor/dpa4_nn/block.py
  • deepmd/dpmodel/descriptor/dpa4_nn/ffn.py
  • deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
  • deepmd/dpmodel/descriptor/dpa4_nn/projection.py
  • deepmd/dpmodel/descriptor/dpa4_nn/so2.py
  • source/tests/common/dpmodel/test_descrpt_dpa4.py
  • source/tests/common/dpmodel/test_dpa4_basegridnet_cross.py
  • source/tests/common/dpmodel/test_dpa4_ffn_so3.py
  • source/tests/common/dpmodel/test_dpa4_frame_mixers.py
  • source/tests/common/dpmodel/test_dpa4_grid_descriptor.py
  • source/tests/common/dpmodel/test_dpa4_gridbranch_frames.py
  • source/tests/common/dpmodel/test_dpa4_gridmlp_frames.py
  • source/tests/common/dpmodel/test_dpa4_project_frames.py
  • source/tests/common/dpmodel/test_dpa4_so2_grid.py
  • source/tests/common/dpmodel/test_dpa4_so3_grid_utils.py
  • source/tests/common/dpmodel/test_dpa4_so3_gridnet.py
  • source/tests/common/dpmodel/test_dpa4_so3_projector.py
  • source/tests/consistent/descriptor/test_dpa4.py
  • source/tests/pt/model/test_dpa4_dpmodel_parity.py

Comment thread deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
Comment thread deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py Outdated
Comment thread deepmd/dpmodel/descriptor/dpa4_nn/so2.py
Han Wang and others added 2 commits June 19, 2026 00:34
…ng#5555)

- BaseGridNet cross-mode: lift query/context to compute_dtype before
  FrameExpand so the frame expansion runs in the net's precision (mirrors
  pt's fp64-weight-forced FrameExpand); _FrameMixer otherwise casts weights
  down to the operand dtype, expanding fp32 inputs in fp32. (CodeRabbit)
- SO3GridNet.deserialize: validate the nested projector @class/@Version
  instead of blindly reading config["projector"]["config"]. (CodeRabbit)
- SO2Convolution.deserialize: reject schema-drift keys under the
  node_wise/message_node grid-product prefixes (loaded @variables key set
  must match the fresh template). (CodeRabbit)
- drop unused n_valid local in test_dpa4_so2_grid.py. (CodeQL)

Tests: mixed-precision cross run, deserialize rejects bad projector
@class/@Version, deserialize rejects grid-product drift key.
@wanghan-iapcm wanghan-iapcm added the Test CUDA Trigger test CUDA workflow label Jun 18, 2026
@github-actions github-actions Bot removed the Test CUDA Trigger test CUDA workflow label Jun 18, 2026

@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/dpmodel/descriptor/dpa4_nn/grid_net.py`:
- Around line 1541-1548: The version key for the nested projector is being
accessed with a default value of 1 using get("`@version`", 1), which allows
malformed projector payloads without a version to silently pass validation.
Remove the default value parameter and add explicit validation to require the
`@version` key to be present in projector_data before calling
check_version_compatibility(). Raise a ValueError with a descriptive message if
the `@version` key is missing, following the same pattern as the existing `@class`
validation.

In `@source/tests/common/dpmodel/test_dpa4_so3_gridnet.py`:
- Around line 472-473: The test for invalid version handling in
DPSO3GridNet.deserialize uses overly broad exception handling with
pytest.raises(Exception), which can mask unrelated failures and weakens test
specificity. Replace Exception with the concrete exception type that the
deserialize method actually raises for invalid versions (examine the method
implementation to determine if it's ValueError, RuntimeError, or another
specific exception type), and optionally add a message parameter to match
against the error message fragment for even more precise assertion.
🪄 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: ca2ea555-f9dd-49f9-8000-5426bb8cb238

📥 Commits

Reviewing files that changed from the base of the PR and between 4a7be0e and 83e0b79.

📒 Files selected for processing (4)
  • deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
  • deepmd/dpmodel/descriptor/dpa4_nn/so2.py
  • source/tests/common/dpmodel/test_dpa4_so2_grid.py
  • source/tests/common/dpmodel/test_dpa4_so3_gridnet.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/tests/common/dpmodel/test_dpa4_so2_grid.py
  • deepmd/dpmodel/descriptor/dpa4_nn/so2.py

Comment thread deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py
Comment thread source/tests/common/dpmodel/test_dpa4_so3_gridnet.py Outdated
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.97156% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.22%. Comparing base (d0a1959) to head (be4e13c).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
deepmd/dpmodel/descriptor/dpa4_nn/grid_net.py 95.10% 14 Missing ⚠️
deepmd/dpmodel/descriptor/dpa4_nn/projection.py 96.47% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5555      +/-   ##
==========================================
+ Coverage   82.16%   82.22%   +0.05%     
==========================================
  Files         896      896              
  Lines      102643   103018     +375     
  Branches     4340     4340              
==========================================
+ Hits        84341    84708     +367     
- Misses      16965    16972       +7     
- Partials     1337     1338       +1     

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

@wanghan-iapcm wanghan-iapcm added the Test CUDA Trigger test CUDA workflow label Jun 18, 2026
@github-actions github-actions Bot removed the Test CUDA Trigger test CUDA workflow label Jun 18, 2026
…eepmodeling#5555)

Follow-up to CodeRabbit re-review:
- SO3GridNet.deserialize now requires the nested projector @Version key
  (was silently defaulting a missing version to 1).
- the version test asserts ValueError(match="version") instead of a blind
  Exception (ruff B017), and adds a missing-@Version case.
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.

3 participants