Skip to content

Implement explicit 2-D and 3-D snow MPM solvers - #175

Merged
utilForever merged 4 commits into
mainfrom
snow-mpm-solver
Aug 8, 2026
Merged

utilForever merged 4 commits into
mainfrom
snow-mpm-solver

Conversation

@utilForever

@utilForever utilForever commented Aug 8, 2026 •

Copy link
Copy Markdown
Owner

This revision includes:

Summary by CodeRabbit

  • New Features

    • Added 2D and 3D snow material point method (MPM) solvers.
    • Added Python access to configure resolution, grid spacing, origin, particle properties, and time-step scaling.
    • Added adaptive sub-stepping and wave-speed calculations for stable simulations.
    • Added support for gravity, wind, drag, deformation, and particle-grid transfers.
  • Tests

    • Added comprehensive validation for solver behavior, configuration, material responses, wave-speed calculations, and invalid inputs.

@utilForever utilForever self-assigned this Aug 8, 2026
@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2e9c461a-ca52-40d3-a87f-66f0636e2d02

📥 Commits

Reviewing files that changed from the base of the PR and between 3f3efef and be2cd1f.

📒 Files selected for processing (1)
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
📜 Recent review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: 🪟 CUDA Build - Windows Server 2022 + Visual Studio 2022 + CUDA 12.6.3 (Release)
  • GitHub Check: 🪟 CUDA Build - Windows Server 2025 + Visual Studio 2026 + CUDA 13.2.0 (Release)
  • GitHub Check: 🐧 CUDA Build - Ubuntu 24.04 + gcc-12 + CUDA 12.6.3
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-13
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-14
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-17
  • GitHub Check: 🧪 Code Coverage - Codecov (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-12
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-18
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-16
  • GitHub Check: 🍎 Build - macOS 15.7.4 + Xcode 16.4
  • GitHub Check: 🌞 Static Analysis - SonarCloud (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🍎 Build - macOS 26.3 + Xcode 26.3
  • GitHub Check: 🪟 Build - Windows Server 2022 + Visual Studio 2022
  • GitHub Check: 🪟 Build - Windows Server 2025 + Visual Studio 2026

📝 Walkthrough

Walkthrough

Snow MPM support now includes validated constitutive wave-speed calculation, explicit 2-D and 3-D solver lifecycles, adaptive substeps, particle-grid transfers, builders, Python bindings, and unit tests.

Changes

Snow MPM simulation

Layer / File(s) Summary
Constitutive wave-speed calculation
Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp, Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp, Tests/UnitTests/SnowConstitutiveModelTests.cpp
Adds validated wave-speed calculation and shared plastic-hardening logic. Tests cover analytic values, hardening, special parameters, and invalid states.
Explicit SnowMPMSolver lifecycle
Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp, Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp, Tests/UnitTests/SnowMPMSolverTests.cpp
Adds 2-D and 3-D solver construction, particle-grid transfers, force integration, deformation updates, adaptive substeps, reference-volume initialization, builders, and unit tests.
Python solver API
Includes/API/Python/Solver/Particle/MPM/SnowMPMSolver.hpp, Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp, Sources/API/Python/main.cpp, Tests/PythonTests/test_snow_mpm_solver.py
Registers 2-D and 3-D SnowMPMSolver classes with constructors, system-data access, time-step scaling, and Python API tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PythonClient
  participant SnowMPMSolver
  participant MPMSystemData
  participant SnowConstitutiveModel
  PythonClient->>SnowMPMSolver: construct and update solver
  SnowMPMSolver->>MPMSystemData: transfer particle data to grid
  SnowMPMSolver->>SnowConstitutiveModel: compute wave speed and stress
  SnowConstitutiveModel-->>SnowMPMSolver: return constitutive values
  SnowMPMSolver->>MPMSystemData: update grid and particle state
  SnowMPMSolver-->>PythonClient: expose updated solver data
Loading

Possibly related issues

Possibly related PRs

Poem

A rabbit bounds through snow and code,
While particles share the load.
Waves set steps, and grids align,
Two dimensions, then three, combine.
Python bindings softly glow.
Tests confirm the flows below.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.70% 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 describes the main change: implementation of explicit 2-D and 3-D snow MPM solvers.
Linked Issues check ✅ Passed The PR implements the CPU snow MPM solvers, constitutive wave speed, builders, transfers, substeps, bindings, and tests required by issue [#163].
Out of Scope Changes check ✅ Passed The changes support the snow MPM solver objectives, including required constitutive calculations, API exposure, and focused tests, with no unrelated code identified.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch snow-mpm-solver

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

@codacy-production

codacy-production Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 112 complexity · 2 duplication

Metric Results
Complexity 112
Duplication 2

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (5)
Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp (2)

286-291: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Hoist the per-particle data lookups out of the gradient loop.

ComputeVelocityGradient re-fetches Positions(), GridVelocities(), DataSize(), GridSpacing(), and DataOrigin() on every call. ComputeMaxVelocityGradient at Line 321 and UpdateDeformation at Line 335 call it once per particle. The lookups therefore repeat for every particle in the system.

Pass the array views and grid metadata as parameters, or compute the gradient inside a single loop that fetches them once. This removes redundant work from the per-particle hot path.

Also applies to: 319-322

🤖 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 `@Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp` around lines 286 -
291, Update ComputeVelocityGradient and its callers ComputeMaxVelocityGradient
and UpdateDeformation to hoist Positions(), GridVelocities(), DataSize(),
GridSpacing(), and DataOrigin() lookups outside the per-particle loop, passing
the cached views and metadata into the gradient calculation while preserving
existing results.

133-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Record the one-frame lag of m_maxVelocityGradient.

GetNumberOfSubTimeSteps is const and reads m_maxVelocityGradient. UpdateDeformation writes that member during the previous substep, and OnInitialize seeds it. The substep count for the current frame therefore uses the gradient from the previous frame.

This lag is intentional for an explicit scheme. Add a short comment that states the invariant.

As per coding guidelines: "keep comments focused on intent, invariants, numerical reasoning, or non-obvious constraints".

🤖 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 `@Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp` around lines 133 -
137, Add a concise comment immediately before the m_maxVelocityGradient timestep
limit in GetNumberOfSubTimeSteps, documenting that the value was computed during
the previous frame/substep and is intentionally used with a one-frame lag by the
explicit scheme. Keep the existing calculation unchanged.

Source: Coding guidelines

Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp (1)

180-188: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider validating before the dependent divisions.

Lines 183-185 validate totalDeterminant and currentDensity after Lines 153, 180, and 181 already use them. The result stays correct, because IEEE-754 division produces inf or NaN and the guard rejects it. However, the check reads as a post-condition on values that were used earlier.

Move the totalDeterminant and currentDensity checks directly after Line 153 to make the pre-conditions explicit, and keep the kappa and waveSpeed checks where they are.

🤖 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 `@Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp` around lines 180 -
188, Move the finite-and-positive validation for totalDeterminant and
currentDensity to immediately after their computation in the surrounding
constitutive-model function, before any dependent divisions or uses. Remove
those two checks from the later guard, while keeping the existing kappa and
waveSpeed validation there.
Tests/UnitTests/SnowMPMSolverTests.cpp (2)

264-275: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document how the expected value 56 is derived.

Line 274 asserts an exact substep count. The value depends on the velocity-gradient limit, the default m_timeStepLimitScale, and the ceil rounding. Any change to those constants breaks the test with no indication of the cause.

The derivation is: the lattice rate is 100, the gradient limit gives 0.2 / 100 = 0.002, and ceil(0.1 / (0.9 * 0.002)) is 56. The value is dimension-independent, which is why the same expectation holds for 2-D and 3-D.

Add that derivation as a comment.

♻️ Proposed comment
     deforming.Initialize();
+    // The velocity-gradient limit binds here: 0.2 / 100 = 0.002 s. With the
+    // default time-step limit scale of 0.9, ceil(0.1 / (0.9 * 0.002)) = 56.
+    // The bound is dimension-independent, so 2-D and 3-D agree.
     EXPECT_EQ(deforming.NumberOfSubTimeSteps(0.1), 56u);
🤖 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 `@Tests/UnitTests/SnowMPMSolverTests.cpp` around lines 264 - 275, Add a concise
explanatory comment immediately before the EXPECT_EQ assertion in the deforming
solver test, documenting that the lattice rate is 100, the velocity-gradient
limit yields 0.2 / 100 = 0.002, and ceil(0.1 / (0.9 * 0.002)) produces 56; note
that this derivation is dimension-independent.

277-288: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the constructor parameter validation.

SnowMPMSolver-Impl.hpp Lines 30-34 reject a non-finite radius, a negative radius, a non-finite mass, and a non-positive mass with std::invalid_argument. ExpectParametersAndBuilder covers SetTimeStepLimitScale but not those constructor rejections.

Add the matching EXPECT_THROW assertions so the constructor contract is verified in both dimensions.

💚 Proposed additions
     EXPECT_THROW(
         solver.SetTimeStepLimitScale(std::numeric_limits<double>::quiet_NaN()),
         std::invalid_argument);
+
+    const auto resolution8 = VectorUZ<N>::MakeConstant(8);
+    const auto unit = VectorD<N>::MakeConstant(1.0);
+    EXPECT_THROW((SnowMPMSolver<N>{ resolution8, unit, {}, -1.0, 1.0 }),
+                 std::invalid_argument);
+    EXPECT_THROW((SnowMPMSolver<N>{ resolution8, unit, {}, 0.1, 0.0 }),
+                 std::invalid_argument);
+    EXPECT_THROW((SnowMPMSolver<N>{ resolution8, unit, {}, 0.1,
+                                    std::numeric_limits<double>::infinity() }),
+                 std::invalid_argument);

As per coding guidelines: "Update or add tests for both 2-D and 3-D counterparts when behavior applies to both".

🤖 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 `@Tests/UnitTests/SnowMPMSolverTests.cpp` around lines 277 - 288, Add
constructor validation coverage to ExpectParametersAndBuilder by adding
EXPECT_THROW assertions for SnowMPMSolver construction with non-finite and
negative radius values, plus non-finite and non-positive mass values, each
expecting std::invalid_argument. Ensure the existing template-based test runs
these checks for both 2-D and 3-D solver instantiations.

Source: Coding guidelines

🤖 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 `@Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp`:
- Around line 217-224: Adopt one boundary policy for all stencil transfers,
preferably skipping entries whose indices fall outside dataSize rather than
passing them to ClampIndex. Apply it in SnowMPMSolver-Impl.hpp at the
referenceDensity calculation (lines 217-224), impulse transfer (lines 268-277),
and velocity-gradient update (lines 294-309), preserving valid in-domain
entries; add boundary-particle tests covering both supported dimensions.
- Around line 174-178: Update the solver constructor validation near the
existing radius and mass checks to reject any zero component in resolution
before storing or using it. Preserve the existing validation behavior and ensure
ClampIndex only receives positive grid extents.

In `@Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp`:
- Around line 14-19: Include SnowConstitutiveModel.hpp directly in
SnowMPMSolver.hpp because SnowConstitutiveModel<N> is stored by value; retain
the existing MPMSystemData.hpp include for CubicBSplineKernel<N>, which does not
require a separate kernel header.

---

Nitpick comments:
In `@Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp`:
- Around line 180-188: Move the finite-and-positive validation for
totalDeterminant and currentDensity to immediately after their computation in
the surrounding constitutive-model function, before any dependent divisions or
uses. Remove those two checks from the later guard, while keeping the existing
kappa and waveSpeed validation there.

In `@Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp`:
- Around line 286-291: Update ComputeVelocityGradient and its callers
ComputeMaxVelocityGradient and UpdateDeformation to hoist Positions(),
GridVelocities(), DataSize(), GridSpacing(), and DataOrigin() lookups outside
the per-particle loop, passing the cached views and metadata into the gradient
calculation while preserving existing results.
- Around line 133-137: Add a concise comment immediately before the
m_maxVelocityGradient timestep limit in GetNumberOfSubTimeSteps, documenting
that the value was computed during the previous frame/substep and is
intentionally used with a one-frame lag by the explicit scheme. Keep the
existing calculation unchanged.

In `@Tests/UnitTests/SnowMPMSolverTests.cpp`:
- Around line 264-275: Add a concise explanatory comment immediately before the
EXPECT_EQ assertion in the deforming solver test, documenting that the lattice
rate is 100, the velocity-gradient limit yields 0.2 / 100 = 0.002, and ceil(0.1
/ (0.9 * 0.002)) produces 56; note that this derivation is
dimension-independent.
- Around line 277-288: Add constructor validation coverage to
ExpectParametersAndBuilder by adding EXPECT_THROW assertions for SnowMPMSolver
construction with non-finite and negative radius values, plus non-finite and
non-positive mass values, each expecting std::invalid_argument. Ensure the
existing template-based test runs these checks for both 2-D and 3-D solver
instantiations.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 023f1474-dbbc-4130-945a-b418acd3a297

📥 Commits

Reviewing files that changed from the base of the PR and between ca7f1df and 3f3efef.

📒 Files selected for processing (10)
  • Includes/API/Python/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp
  • Sources/API/Python/main.cpp
  • Tests/PythonTests/test_snow_mpm_solver.py
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
📜 Review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: 🧪 Code Coverage - Codecov (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🪟 Build - Windows Server 2022 + Visual Studio 2022
  • GitHub Check: 🪟 CUDA Build - Windows Server 2022 + Visual Studio 2022 + CUDA 12.6.3 (Release)
  • GitHub Check: 🪟 Build - Windows Server 2025 + Visual Studio 2026
  • GitHub Check: 🪟 CUDA Build - Windows Server 2025 + Visual Studio 2026 + CUDA 13.2.0 (Release)
  • GitHub Check: 🍎 Build - macOS 15.7.4 + Xcode 16.4
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-18
  • GitHub Check: 🌞 Static Analysis - SonarCloud (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-14
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-17
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-13
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-16
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-12
  • GitHub Check: 🍎 Build - macOS 26.3 + Xcode 26.3
  • GitHub Check: 🐧 CUDA Build - Ubuntu 24.04 + gcc-12 + CUDA 12.6.3
🧰 Additional context used
📓 Path-based instructions (9)
Sources/API/Python/**/*.{cpp,hpp}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Python binding implementations synchronized with core APIs, use existing Python names and camelCase property conventions, and do not mechanically expose C++ spelling.

Files:

  • Sources/API/Python/main.cpp
  • Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp
Sources/API/Python/main.cpp

📄 CodeRabbit inference engine (AGENTS.md)

Register every exposed binding in main.cpp and preserve dependency order.

Files:

  • Sources/API/Python/main.cpp
**/*.{cpp,cc,cxx,h,hpp,cu,cuh}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{cpp,cc,cxx,h,hpp,cu,cuh}: Treat warnings as errors under the default CUBBYFLOW_WARNINGS_AS_ERRORS=ON; fix project warnings instead of globally suppressing them.
Follow .clang-format: four-space indentation, 80-column C++ limit, sorted includes, project brace style, and format only touched C++/CUDA files.
Preserve existing copyright headers and keep comments focused on intent, invariants, numerical reasoning, or non-obvious constraints.

Files:

  • Sources/API/Python/main.cpp
  • Includes/API/Python/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep 2-D and 3-D behavior aligned; inspect sibling implementations, aliases, explicit instantiations, bindings, and tests before changing one dimensional side.
Keep the public C++ API and Python-visible behavior synchronized when changing public types, methods, defaults, enums, or solver behavior.
Fix shared behavior at the shared layer; search callers, overrides, bindings, tests, and dimensional specializations before editing, and avoid one-off caller guards when an invariant belongs in a common utility or base class.
Use existing patterns and dependencies before adding abstractions, libraries, templates, builders, numerical helpers, parallel loops, serialization code, or tests.
Run the smallest relevant validation: focused C++ tests for core behavior, both dimensions for shared templates, focused pytest for Python APIs, CUDA compilation/tests for CUDA changes, fresh configure/build for build changes, and round-trip tests for serialization.
Do not commit build output, test logs, caches, IDE state, generated build files, or unrelated formatting; keep commits focused and use the appropriate conventional prefix.
Before handoff, confirm the fix is at the shared behavior source, dimensional/Python/CUDA surfaces are synchronized when relevant, focused checks pass, touched C++/CUDA files are formatted, and skipped platform/GPU/performance validation is explicitly reported.

Files:

  • Sources/API/Python/main.cpp
  • Includes/API/Python/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Tests/PythonTests/test_snow_mpm_solver.py
  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
Includes/API/Python/**/*.{hpp,h}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Python binding declarations synchronized with public Python-visible C++ APIs.

Files:

  • Includes/API/Python/Solver/Particle/MPM/SnowMPMSolver.hpp
Tests/PythonTests/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

Tests/PythonTests/test_*.py: Add or preserve focused pytest coverage for every new or changed Python-visible API.
Name Python tests test_type.py and run focused pytest files for Python API changes.

Files:

  • Tests/PythonTests/test_snow_mpm_solver.py
Includes/Core/**/*.hpp

📄 CodeRabbit inference engine (AGENTS.md)

Keep public C++ declarations and Doxygen comments under Includes/Core/; use project includes such as <Core/...> and the CubbyFlow namespace.

Files:

  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
Includes/Core/**/*.{hpp,h}

📄 CodeRabbit inference engine (AGENTS.md)

For dimensional templates, keep dimension-independent logic shared, preserve Foo2/Foo3 and pointer aliases, and follow existing builder and ownership APIs.

Files:

  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
Tests/UnitTests/**/*.{cpp,hpp}

📄 CodeRabbit inference engine (AGENTS.md)

Tests/UnitTests/**/*.{cpp,hpp}: Update or add tests for both 2-D and 3-D counterparts when behavior applies to both; use GoogleTest/GMock macros and focused regression scenarios.
Use the existing RESOURCES_DIR compile definition for C++ fixtures rather than relying on the current working directory.

Files:

  • Tests/UnitTests/SnowMPMSolverTests.cpp
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
🔇 Additional comments (21)
Includes/API/Python/Solver/Particle/MPM/SnowMPMSolver.hpp (1)

1-19: LGTM!

Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp (1)

11-47: LGTM!

Sources/API/Python/main.cpp (1)

95-95: LGTM!

Also applies to: 335-336

Tests/PythonTests/test_snow_mpm_solver.py (1)

1-39: LGTM!

Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp (1)

93-107: LGTM!

Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp (3)

116-116: LGTM!


193-205: LGTM!


159-181: 🩺 Stability & Availability

No change required: SVD normalizes every singular value to a non-negative value. The fixed-size implementation explicitly negates negative values before returning them.

Tests/UnitTests/SnowConstitutiveModelTests.cpp (1)

164-218: LGTM!

Also applies to: 381-399

Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp (2)

29-96: LGTM!

Also applies to: 125-128


103-111: 📐 Maintainability & Code Quality

Keep [[nodiscard]] on these setters. Existing CubbyFlow builders use the same annotation on chainable setters, including both 2-D and 3-D builders.

			> Likely an incorrect or invalid review comment.
Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp (8)

21-40: LGTM!


42-71: LGTM!


152-156: LGTM!


183-216: LGTM!

Also applies to: 226-233


249-266: LGTM!

Also applies to: 269-280


327-342: LGTM!

Also applies to: 344-396


146-149: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fix the upper clamp bound to avoid an out-of-range conversion.

std::numeric_limits<unsigned int>::max() is 4294967295. A 32-bit unsigned int value cannot be represented exactly as a double in this case, so the conversion at Line 147 rounds up to 4294967296.0. When count reaches or exceeds that value, std::clamp returns 4294967296.0 and the cast at Line 149 converts a value that the target type cannot represent. That conversion is undefined behavior.

This path is reachable. A very small desiredTimeStep, which follows from a large wave speed or a large velocity gradient, drives count above the bound.

Clamp with a value that is exactly representable and strictly below the maximum.

🐛 Proposed fix
     const double count = std::ceil(timeIntervalInSeconds /
                                    (m_timeStepLimitScale * desiredTimeStep));
-    const double maxCount =
-        static_cast<double>(std::numeric_limits<unsigned int>::max());
-
-    return static_cast<unsigned int>(std::clamp(count, 1.0, maxCount));
+    // Largest double that is exactly representable and converts safely to
+    // unsigned int.
+    constexpr double maxCount = 4294967295.0 - 1023.0;
+
+    return static_cast<unsigned int>(std::clamp(count, 1.0, maxCount));
 }

A clearer alternative avoids the magic constant:

constexpr unsigned int maxSteps = std::numeric_limits<unsigned int>::max();

if (!(count < static_cast<double>(maxSteps)))
{
    return maxSteps;
}

return static_cast<unsigned int>(std::max(count, 1.0));
			> Likely an incorrect or invalid review comment.

158-166: 🩺 Stability & Availability

Keep the custom OnBeginAdvanceTimeStep sequence. The ParticleSystemSolver2 and ParticleSystemSolver3 base implementations are empty, so omitting a base call does not skip per-step setup.

			> Likely an incorrect or invalid review comment.
Tests/UnitTests/SnowMPMSolverTests.cpp (2)

14-97: LGTM!

Also applies to: 99-221, 290-309, 325-358


312-323: 📐 Maintainability & Code Quality

No shared RUN_FOR_2D_AND_3D macro exists.

The two translation units contain separate duplicate definitions. No shared-header change is required.

@codecov

codecov Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.28099% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.57%. Comparing base (ca7f1df) to head (be2cd1f).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #175      +/-   ##
==========================================
+ Coverage   83.43%   83.57%   +0.14%     
==========================================
  Files         416      418       +2     
  Lines       23568    23807     +239     
==========================================
+ Hits        19663    19897     +234     
- Misses       3905     3910       +5     
🚀 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.

@sonarqubecloud

sonarqubecloud Bot commented Aug 8, 2026

Copy link
Copy Markdown

@utilForever
utilForever merged commit cb2b1cf into main Aug 8, 2026
21 checks passed
@utilForever
utilForever deleted the snow-mpm-solver branch August 24, 2026 04:47
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.

Implement explicit 2-D and 3-D snow MPM solvers

1 participant