Skip to content

Add semi-implicit grid integration for snow MPM - #178

Merged
utilForever merged 13 commits into
mainfrom
semi-implicit-snow-mpm
Aug 11, 2026
Merged

Add semi-implicit grid integration for snow MPM#178
utilForever merged 13 commits into
mainfrom
semi-implicit-snow-mpm

Conversation

@utilForever

@utilForever utilForever commented Aug 10, 2026

Copy link
Copy Markdown
Owner

This revision includes:

Summary by CodeRabbit

  • New Features

    • Added a conjugate-residual solver for symmetric linear systems with convergence and failure diagnostics.
    • Added first Piola stress differential calculations for snow materials.
    • Added semi-implicit integration for the snow MPM solver.
    • Exposed semi-implicit settings, iteration limits, tolerances, and solve diagnostics through the Python API.
  • Bug Fixes

    • Improved handling of invalid, non-finite, and failed solver results, including restoring previous velocities after unsuccessful solves.
  • Tests

    • Added coverage for solver convergence, stress differentials, stability, boundary handling, and semi-implicit configuration.

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

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a public conjugate-residual solver and a snow first Piola stress differential. Extends SnowMPMSolver with semi-implicit grid integration, active-node constraints, convergence diagnostics, Python properties, rollback handling, and 2D/3D tests.

Changes

Snow MPM semi-implicit integration

Layer / File(s) Summary
Conjugate-residual solver
Includes/Core/Math/CG.hpp, Includes/Core/Math/CG-Impl.hpp, Tests/UnitTests/CGTests.cpp
Adds CR for symmetric systems. The solver reports iteration count and residual norm and rejects invalid or non-finite intermediate values.
Snow stress differential
Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp, Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp, Tests/UnitTests/SnowConstitutiveModelTests.cpp
Adds ComputeFirstPiolaStressDifferential with input and finite-result validation. Tests compare the analytic differential with central finite differences in 2D and 3D.
Semi-implicit grid solve
Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp, Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp, Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp, Tests/PythonTests/test_snow_mpm_solver.py, Tests/UnitTests/SnowMPMSolverTests.cpp
Adds active-node mappings, constrained degrees of freedom, elastic-Hessian application, CR-based grid solves, failure rollback, runtime controls, diagnostics, Python properties, and integration tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SnowMPMSolver
  participant ActiveNodes
  participant ElasticHessian
  participant CR
  participant Grid
  SnowMPMSolver->>ActiveNodes: build active-node and constraint arrays
  SnowMPMSolver->>ElasticHessian: assemble grid operator
  SnowMPMSolver->>CR: solve velocity correction
  CR-->>SnowMPMSolver: return residual and iteration count
  SnowMPMSolver->>Grid: commit successful velocities or restore prior state
Loading

Possibly related PRs

Poem

A rabbit checks the snowbound grid,
Where stress differentials are hid.
CR solves each velocity,
With diagnostics for clarity.
Failed steps restore what they did.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 primary change: adding semi-implicit grid integration for snow MPM.
Linked Issues check ✅ Passed The implementation addresses issue #165 through stress linearization, a CR solver, semi-implicit integration, failure handling, API controls, and focused 2-D and 3-D tests.
Out of Scope Changes check ✅ Passed The changes support the linked objective and include required solver, constitutive-model, API, and test updates without unrelated scope.
✨ 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 semi-implicit-snow-mpm

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

@codacy-production

codacy-production Bot commented Aug 10, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 123 complexity · 12 duplication

Metric Results
Complexity 123
Duplication 12

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: 1

🧹 Nitpick comments (5)
Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp (1)

93-100: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Complete the Doxygen block for the new public method.

Update, ComputeKirchhoffStress, and ComputeWaveSpeed document their parameters and return values. Add the same for ComputeFirstPiolaStressDifferential, and state the throwing behavior, because the implementation rejects a non-finite differential and a non-finite result with std::invalid_argument.

📝 Proposed documentation
     //!
     //! \brief Computes the first Piola stress differential.
     //!
     //! Evaluates `(d^2 Psi / d F_E d F_E) : differential` while holding the
     //! plastic deformation fixed.
     //!
+    //! \param[in] state Current deformation state.
+    //! \param[in] differential Elastic deformation-gradient differential.
+    //!
+    //! \return First Piola stress differential.
+    //!
     [[nodiscard]] MatrixType ComputeFirstPiolaStressDifferential(
         const State& state, const MatrixType& differential) const;

As per path instructions: "Keep public C++ declarations and Doxygen comments under Includes/Core/".

🤖 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.hpp` around lines 93 - 100,
Complete the Doxygen block for the public ComputeFirstPiolaStressDifferential
method by documenting both parameters, its returned stress differential, and
that it throws std::invalid_argument when differential or the computed result is
non-finite. Keep the declaration and documentation within the existing
Includes/Core/ location.

Source: Path instructions

Tests/UnitTests/CGTests.cpp (1)

97-151: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the CR breakdown path.

The three new tests cover convergence, zero iterations, and an already-converged input. They do not reach the new failure branches, which set residualNorm to infinity for q == 0, rho == 0, or a non-finite residual. SnowMPMSolver::SolveGridVelocities treats that infinite residual as the failure signal, so the contract deserves a direct test.

💚 Proposed additional test
TEST(CR, SingularSystemReportsFailure)
{
    using BLASType = BLAS<double, Vector2D, Matrix2x2D>;
    const Matrix2x2D matrix(1.0, 0.0, 0.0, 0.0);
    const Vector2D rhs(0.0, 1.0);
    Vector2D x, r, d, q, s;
    unsigned int iterations = 0;
    double residual = 0.0;

    CR<BLASType>(matrix, rhs, 10, 1e-14, &x, &r, &d, &q, &s, &iterations,
                 &residual);

    EXPECT_FALSE(std::isfinite(residual));
}
🤖 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/CGTests.cpp` around lines 97 - 151, Add a CR breakdown-path
test near the existing CR tests, using a singular Matrix2x2D and incompatible
rhs to trigger failure. Verify that CR reports failure by setting residual to a
non-finite value, while preserving the existing convergence and early-exit
coverage.
Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp (2)

56-93: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Write the constrained rows of output explicitly.

Multiply assigns only unconstrained rows. output->Resize(input.GetRows(), 0.0) does not clear elements that already exist, so constrained rows keep whatever the caller's work vector held. The current call site works only because SolveGridVelocities allocates every CR vector with 0.0 and keeps the right-hand side zero on constrained rows. Make the operator self-contained so the invariant does not depend on the caller.

🛡️ Proposed fix
     output->Resize(input.GetRows(), 0.0);
+    output->Fill(0.0);
🤖 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 56 -
93, Update SnowMPMSolver<N>::LinearSystem::Multiply to explicitly assign zero to
every constrained output row, rather than relying on VectorND::Resize to clear
existing storage. Preserve the current mass-plus-Hessian computation for
unconstrained rows and ensure each constrained row is written deterministically
on every call.

562-580: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Cache per-particle quantities and parallelize the Hessian application.

ApplyElasticHessian runs once per CR iteration. For each call and each particle it walks the stencil twice and calls ComputeFirstPiolaStressDifferential, which recomputes the SVD, the inverse, the determinant, and the hardening factor. With the default limit of 100 iterations, the same SVD is computed 100 times per particle per step. The loop is also serial, while ConstrainParticlesToDomain in the same file uses ParallelFor.

Two improvements keep the operator identical:

  • Precompute per-particle SVD, hardening, volume, and F_E^T once per SolveGridVelocities call, and pass them to a differential overload.
  • Parallelize the particle loop with per-node accumulation, for example thread-local buffers reduced into output, so the scatter stays deterministic.
🤖 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 562 -
580, The Hessian application currently recomputes per-particle constitutive
quantities serially on every iteration. Update SolveGridVelocities and
ApplyElasticHessian to precompute and retain each particle’s SVD, hardening
factor, volume, and F_E^T once per solve, then use a differential
ComputeFirstPiolaStressDifferential overload that consumes those cached values;
parallelize the particle loop using thread-local per-node accumulations and a
deterministic reduction into output, preserving the existing operator result.
Includes/Core/Math/CG.hpp (1)

51-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the tolerance convention and the failure signal for CR.

CR compares the residual L2 norm against tolerance, while PCG compares the squared residual against Square(tolerance). A caller that reuses the PCG convention will request a tolerance that is off by a square. CR also reports failure by writing a non-finite lastResidualNorm and leaves a partially updated x. Both facts belong in the public header.

📝 Proposed documentation
 //!
 //! \brief Solves a symmetric linear system with conjugate residual.
 //!
+//! \param[in] A Symmetric (possibly indefinite) system operator.
+//! \param[in] b Right-hand side.
+//! \param[in] maxNumberOfIterations Iteration limit; zero permits only an
+//! already-converged input.
+//! \param[in] tolerance Absolute residual L2-norm target. Unlike `PCG`, this
+//! value is not squared internally.
+//! \param[out] x Solution; also used as the initial guess.
+//! \param[out] r, d, q, s Caller-provided work vectors.
+//! \param[out] lastNumberOfIterations Performed iteration count.
+//! \param[out] lastResidualNorm Final residual L2 norm. On breakdown or a
+//! non-finite intermediate value, this is set to infinity and `x` holds a
+//! partially updated result.
+//!
 template <typename BLASType>
🤖 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/Math/CG.hpp` around lines 51 - 61, Update the public
documentation for CR to state that tolerance is compared directly with the
residual L2 norm, unlike PCG’s squared-residual convention. Also document that
failure is signaled by writing a non-finite lastResidualNorm and that x may be
partially updated; keep the function signature and behavior unchanged.
🤖 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.hpp`:
- Around line 32-33: Update the semi-implicit integration documentation near
SolveGridVelocities to state that the path can throw both std::runtime_error and
std::invalid_argument, including failures propagated from
ComputeFirstPiolaStressDifferential. Preserve the existing exception behavior
rather than translating or altering exceptions.

---

Nitpick comments:
In `@Includes/Core/Math/CG.hpp`:
- Around line 51-61: Update the public documentation for CR to state that
tolerance is compared directly with the residual L2 norm, unlike PCG’s
squared-residual convention. Also document that failure is signaled by writing a
non-finite lastResidualNorm and that x may be partially updated; keep the
function signature and behavior unchanged.

In `@Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp`:
- Around line 93-100: Complete the Doxygen block for the public
ComputeFirstPiolaStressDifferential method by documenting both parameters, its
returned stress differential, and that it throws std::invalid_argument when
differential or the computed result is non-finite. Keep the declaration and
documentation within the existing Includes/Core/ location.

In `@Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp`:
- Around line 56-93: Update SnowMPMSolver<N>::LinearSystem::Multiply to
explicitly assign zero to every constrained output row, rather than relying on
VectorND::Resize to clear existing storage. Preserve the current
mass-plus-Hessian computation for unconstrained rows and ensure each constrained
row is written deterministically on every call.
- Around line 562-580: The Hessian application currently recomputes per-particle
constitutive quantities serially on every iteration. Update SolveGridVelocities
and ApplyElasticHessian to precompute and retain each particle’s SVD, hardening
factor, volume, and F_E^T once per solve, then use a differential
ComputeFirstPiolaStressDifferential overload that consumes those cached values;
parallelize the particle loop using thread-local per-node accumulations and a
deterministic reduction into output, preserving the existing operator result.

In `@Tests/UnitTests/CGTests.cpp`:
- Around line 97-151: Add a CR breakdown-path test near the existing CR tests,
using a singular Matrix2x2D and incompatible rhs to trigger failure. Verify that
CR reports failure by setting residual to a non-finite value, while preserving
the existing convergence and early-exit coverage.
🪄 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: dbf02c33-f759-4905-b550-fa34350bcd37

📥 Commits

Reviewing files that changed from the base of the PR and between 693bebb and 7e2b2dd.

📒 Files selected for processing (11)
  • Includes/Core/Math/CG-Impl.hpp
  • Includes/Core/Math/CG.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
  • Tests/PythonTests/test_snow_mpm_solver.py
  • Tests/UnitTests/CGTests.cpp
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
📜 Review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: 🌞 Static Analysis - SonarCloud (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🧪 Code Coverage - Codecov (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🍎 Build - macOS 15.7.4 + Xcode 16.4
  • GitHub Check: 🍎 Build - macOS 26.3 + Xcode 26.3
  • GitHub Check: 🪟 Build - Windows Server 2022 + Visual Studio 2022
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-13
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-18
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-12
  • GitHub Check: 🪟 Build - Windows Server 2025 + Visual Studio 2026
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-17
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-14
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-16
  • GitHub Check: 🪟 CUDA Build - Windows Server 2022 + Visual Studio 2022 + CUDA 12.6.3 (Release)
  • GitHub Check: 🐧 CUDA Build - Ubuntu 24.04 + gcc-12 + CUDA 12.6.3
  • GitHub Check: 🪟 CUDA Build - Windows Server 2025 + Visual Studio 2026 + CUDA 13.2.0 (Release)
  • GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
📓 Path-based instructions (7)
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
**/*

📄 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:

  • Tests/PythonTests/test_snow_mpm_solver.py
  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
  • Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp
  • Includes/Core/Math/CG.hpp
  • Includes/Core/Math/CG-Impl.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Tests/UnitTests/CGTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
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/Math/CG.hpp
  • Includes/Core/Math/CG-Impl.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.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/Math/CG.hpp
  • Includes/Core/Math/CG-Impl.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
**/*.{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:

  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Tests/UnitTests/SnowConstitutiveModelTests.cpp
  • Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp
  • Includes/Core/Math/CG.hpp
  • Includes/Core/Math/CG-Impl.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel-Impl.hpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Tests/UnitTests/CGTests.cpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.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/SnowConstitutiveModelTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
  • Tests/UnitTests/CGTests.cpp
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/Solver/Particle/MPM/SnowMPMSolver.cpp
🧠 Learnings (2)
📚 Learning: 2026-08-08T14:25:24.956Z
Learnt from: utilForever
Repo: utilForever/CubbyFlow PR: 175
File: Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp:217-224
Timestamp: 2026-08-08T14:25:24.956Z
Learning: In CubbyFlow MPM implementations, use the shared MPMSytemData policy of clamping out-of-domain cubic B-spline stencil indices to boundary grid nodes for both P2G and G2P operations. This intentionally aggregates out-of-domain weights at boundaries while preserving total stencil weight. SnowMPMSolver and other MPM solvers must follow this policy; any change requires a coordinated MPM-layer update with matching 2-D and 3-D boundary tests.

Applied to files:

  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
📚 Learning: 2026-08-08T14:24:02.736Z
Learnt from: utilForever
Repo: utilForever/CubbyFlow PR: 175
File: Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp:174-178
Timestamp: 2026-08-08T14:24:02.736Z
Learning: MPM solver implementations should rely on MPMSystemData<N>::ResizeGrid() and its shared ValidateGridParameters() validation rather than duplicating grid-parameter checks. This validation rejects zero or maximum-size resolution components, non-finite or non-positive grid spacing, and non-finite grid origin values.

Applied to files:

  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
🪛 Cppcheck (2.21.0)
Tests/UnitTests/SnowMPMSolverTests.cpp

[warning] 546-546: The address of variable 'x' might be accessed at non-zero index.

(objectIndex)


[warning] 555-555: The address of variable 'x' might be accessed at non-zero index.

(objectIndex)


[warning] 690-690: The address of variable 'x' might be accessed at non-zero index.

(objectIndex)


[warning] 827-827: The address of variable 'x' might be accessed at non-zero index.

(objectIndex)


[warning] 836-836: The address of variable 'x' might be accessed at non-zero index.

(objectIndex)

🔇 Additional comments (10)
Includes/Core/Math/CG-Impl.hpp (1)

16-17: LGTM!

Also applies to: 37-104

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

63-63: LGTM!

Also applies to: 102-102, 133-200

Tests/UnitTests/SnowConstitutiveModelTests.cpp (1)

37-82: LGTM!

Also applies to: 306-310, 396-400

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

14-15: LGTM!

Also applies to: 66-90, 118-142, 155-161

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

141-196: LGTM!

Also applies to: 210-210, 271-271, 306-327, 340-340, 454-472, 474-559, 652-757, 854-885


608-622: 🩺 Stability & Availability

No change needed: Matrix::operator*= performs matrix multiplication. ElemIMul provides the separate element-wise operation, so the Hessian action is correct.

			> Likely an incorrect or invalid review comment.
Sources/API/Python/Solver/Particle/MPM/SnowMPMSolver.cpp (1)

38-47: LGTM!

Tests/PythonTests/test_snow_mpm_solver.py (1)

43-60: LGTM!

Tests/UnitTests/SnowMPMSolverTests.cpp (2)

9-9: LGTM!

Also applies to: 94-101, 115-176, 200-343, 352-352, 361-361, 385-385, 406-418, 432-439, 450-463, 481-571, 602-602, 618-627, 636-636, 646-674, 686-703, 720-742, 768-774, 814-843


102-114: 🩺 Stability & Availability

No compilation issue in AddCompressedParticleLattice. ForEachIndex supports begin/end Vector<IndexType, N> bounds, including VectorUZ<N>.

			> Likely an incorrect or invalid review comment.

Comment thread Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp Outdated
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.20253% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.78%. Comparing base (693bebb) to head (ccc4307).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #178      +/-   ##
==========================================
+ Coverage   83.62%   83.78%   +0.16%     
==========================================
  Files         418      418              
  Lines       23855    24152     +297     
==========================================
+ Hits        19948    20236     +288     
- Misses       3907     3916       +9     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
Tests/UnitTests/CGTests.cpp (1)

97-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add 3-D counterparts for the new CR cases.

All four tests instantiate BLAS<double, Vector2D, Matrix2x2D>. The added coverage does not exercise the 3-D instantiation. Add equivalent 3-D cases, or parameterize these tests, for the symmetric, zero-iteration, already-converged, and singular cases.

As per coding guidelines, Tests/UnitTests/**/*.{cpp,hpp} requires tests for both 2-D and 3-D counterparts when behavior applies to both.

Also applies to: 123-142, 144-162, 164-183

🤖 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/CGTests.cpp` around lines 97 - 121, Add 3-D coverage matching
each CR test case—symmetric, zero-iteration, already-converged, and
singular—using the corresponding Vector3D and Matrix3x3D BLAS instantiation.
Either duplicate the existing cases or parameterize them, while preserving their
current assertions and expected behavior for both dimensions.

Source: Coding guidelines

Tests/UnitTests/SnowMPMSolverTests.cpp (1)

318-336: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Assert grid-velocity rollback.

SolveGridVelocities restores GridVelocities() from GridVelocitiesBeforeUpdate() when the solve throws. This test snapshots only particle state. The test can pass even if grid rollback is broken. Snapshot data->GridVelocities() before Update and compare it after EXPECT_THROW.

🤖 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 318 - 336, Extend the
rollback test around solver.Update in the existing SnowMPMSolver test by
snapshotting data->GridVelocities() before the call and comparing every grid
velocity after EXPECT_THROW. Preserve the existing particle-state assertions and
verify the post-failure grid velocities match the snapshot.
🧹 Nitpick comments (1)
Tests/UnitTests/SnowMPMSolverTests.cpp (1)

251-260: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Compare the complete particle state in the small-step test.

The loop checks only Velocities() and DeformationStates().elastic. A mismatch in Positions() or DeformationStates().plastic can pass. Compare positions and both deformation components before accepting explicit/semi-implicit agreement.

🤖 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 251 - 260, Extend the
particle comparison loop in the small-step test to also compare each particle’s
Positions() and DeformationStates().plastic, using the same similarity tolerance
as the existing velocity and elastic-state checks. Keep the current
NumberOfParticles(), velocity, and elastic comparisons unchanged.
🤖 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.

Outside diff comments:
In `@Tests/UnitTests/CGTests.cpp`:
- Around line 97-121: Add 3-D coverage matching each CR test case—symmetric,
zero-iteration, already-converged, and singular—using the corresponding Vector3D
and Matrix3x3D BLAS instantiation. Either duplicate the existing cases or
parameterize them, while preserving their current assertions and expected
behavior for both dimensions.

In `@Tests/UnitTests/SnowMPMSolverTests.cpp`:
- Around line 318-336: Extend the rollback test around solver.Update in the
existing SnowMPMSolver test by snapshotting data->GridVelocities() before the
call and comparing every grid velocity after EXPECT_THROW. Preserve the existing
particle-state assertions and verify the post-failure grid velocities match the
snapshot.

---

Nitpick comments:
In `@Tests/UnitTests/SnowMPMSolverTests.cpp`:
- Around line 251-260: Extend the particle comparison loop in the small-step
test to also compare each particle’s Positions() and
DeformationStates().plastic, using the same similarity tolerance as the existing
velocity and elastic-state checks. Keep the current NumberOfParticles(),
velocity, and elastic comparisons unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4f457dfc-cd40-49e4-8d3c-527bc79631ef

📥 Commits

Reviewing files that changed from the base of the PR and between 7e2b2dd and ccc4307.

📒 Files selected for processing (6)
  • Includes/Core/Math/CG.hpp
  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Tests/UnitTests/CGTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
🚧 Files skipped from review as they are similar to previous changes (4)
  • Includes/Core/Particle/MPM/SnowConstitutiveModel.hpp
  • Includes/Core/Math/CG.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver.hpp
  • Includes/Core/Solver/Particle/MPM/SnowMPMSolver-Impl.hpp
📜 Review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-16
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-12
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + clang-17
  • GitHub Check: 🐧 Build - Ubuntu 24.04 + gcc-14
  • 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-13
  • GitHub Check: 🪟 Build - Windows Server 2022 + Visual Studio 2022
  • GitHub Check: 🍎 Build - macOS 26.3 + Xcode 26.3
  • GitHub Check: 🍎 Build - macOS 15.7.4 + Xcode 16.4
  • GitHub Check: 🪟 Build - Windows Server 2025 + Visual Studio 2026
  • GitHub Check: 🐧 CUDA Build - Ubuntu 24.04 + gcc-12 + CUDA 12.6.3
  • GitHub Check: 🪟 CUDA Build - Windows Server 2025 + Visual Studio 2026 + CUDA 13.2.0 (Release)
  • GitHub Check: 🧪 Code Coverage - Codecov (Ubuntu 24.04 + gcc-14, ubuntu-24.04, gcc, 14)
  • GitHub Check: 🪟 CUDA Build - Windows Server 2022 + Visual Studio 2022 + CUDA 12.6.3 (Release)
🧰 Additional context used
📓 Path-based instructions (3)
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/CGTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.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:

  • Tests/UnitTests/CGTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
**/*

📄 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:

  • Tests/UnitTests/CGTests.cpp
  • Tests/UnitTests/SnowMPMSolverTests.cpp
🪛 Cppcheck (2.21.0)
Tests/UnitTests/SnowMPMSolverTests.cpp

[warning] 681-681: The address of variable 'x' might be accessed at non-zero index.

(objectIndex)

🔇 Additional comments (1)
Tests/UnitTests/SnowMPMSolverTests.cpp (1)

9-9: LGTM!

Also applies to: 77-78, 95-177, 201-230, 264-301, 353-353, 362-362, 386-386, 407-419, 433-440, 451-464, 482-543, 549-572, 603-689, 701-718, 735-757, 783-789

@sonarqubecloud

Copy link
Copy Markdown

@utilForever
utilForever merged commit 8f774f6 into main Aug 11, 2026
21 checks passed
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.

Add semi-implicit grid integration for snow MPM

1 participant