Skip to content

Add inertia verification, correction #440#455

Merged
vreutskyy merged 19 commits into
newton-physics:mainfrom
vreutskyy:440-add-inertia-verification-correction
Jul 29, 2025
Merged

Add inertia verification, correction #440#455
vreutskyy merged 19 commits into
newton-physics:mainfrom
vreutskyy:440-add-inertia-verification-correction

Conversation

@vreutskyy

@vreutskyy vreutskyy commented Jul 22, 2025

Copy link
Copy Markdown
Member

Description

This PR adds inertia verification and correction functionality to Newton, similar to MuJoCo's balanceinertia compiler setting. This feature automatically detects and corrects invalid inertia properties during model compilation to ensure physically valid simulations.

Closes #440

Key Features Added:

  • Inertia Verification Function (verify_and_correct_inertia in newton/geometry/inertia.py):

    • Checks for negative mass and inertia values
    • Applies optional mass and inertia bounds
    • Verifies the triangle inequality for inertia tensors (Ixx + Iyy ≥ Izz, etc.)
    • Optionally balances inertia to satisfy physical constraints with minimal adjustments
  • Compiler Settings in ModelBuilder:

    • balance_inertia (default: True) - Automatically balance inertia tensors to satisfy triangle inequality
    • bound_mass (default: None) - Minimum mass for rigid bodies
    • bound_inertia (default: None) - Minimum diagonal inertia values
  • Automatic Correction during model finalization:

    • Applied before transferring data to the model
    • Issues warnings when corrections are made
    • Updates both mass/inertia and their inverses

Limitations:

  • Only diagonal inertia elements are bounded (off-diagonal elements are preserved)
  • The balancing algorithm uses an iterative approach similar to MuJoCo's, which may not find the globally optimal solution
  • Warnings are issued using Python's warnings module, which may be filtered depending on user settings

Newton Migration Guide

Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this MR.

  • The migration guide in docs/migration.rst is up to date

Before your PR is "Ready for review"

  • All commits are signed-off to indicate that your contribution adheres to the Developer Certificate of Origin requirements
  • Necessary tests have been added and new examples are tested (see newton/tests/test_examples.py)
  • Documentation is up-to-date
  • Code passes formatting and linting checks with pre-commit run -a

Summary by CodeRabbit

  • New Features

    • Added automatic validation and correction of mass and inertia tensor values for rigid bodies, ensuring physical plausibility and enforcing constraints such as triangle inequalities and minimum bounds.
    • Introduced new configuration options to control inertia balancing, minimum value bounds, and validation detail level.
    • Provided both detailed per-body validation with warnings and a fast parallel GPU-based correction option for batch processing.
  • Bug Fixes

    • ModelBuilder now corrects invalid or non-physical mass and inertia values before simulation, improving model stability.
  • Tests

    • Added comprehensive tests covering various scenarios for inertia and mass correction, including integration with model building and warning checks.
  • Improvements

    • Enhanced inertia validation tests to allow for numerical tolerance in inertia corrections, improving test robustness.

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
@vreutskyy vreutskyy had a problem deploying to external-pr-approval July 22, 2025 11:38 — with GitHub Actions Error
@coderabbitai

coderabbitai Bot commented Jul 22, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

"""

Walkthrough

A new function for verifying and correcting rigid body mass and inertia tensors was added, enforcing physical plausibility and user-specified bounds. The ModelBuilder class now applies this correction during model finalization. A comprehensive test suite was introduced to validate the correction logic and its integration with the builder.

Changes

File(s) Change Summary
Inertia validation logic
newton/geometry/inertia.py
Added verify_and_correct_inertia function and validate_and_correct_inertia_kernel Warp kernel for validating and correcting mass and inertia tensors with bounds, triangle inequality, and positive definiteness checks.
Model building and validation integration
newton/sim/builder.py
Added balance_inertia, bound_mass, bound_inertia, and validate_inertia_detailed settings; integrated inertia validation and correction in ModelBuilder.finalize() with detailed per-body and fast batch modes.
Inertia validation tests
newton/tests/test_inertia_validation.py
Introduced new comprehensive test suite for inertia and mass correction logic and integration with ModelBuilder, verifying warnings, numerical corrections, and behavior under various conditions.
Test assertion improvements
newton/tests/test_import_mjcf.py
Modified inertia tensor test assertions to use tolerance-based comparisons accounting for numerical corrections due to inertia balancing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~45 minutes

Suggested reviewers

  • eric-heiden
    """

📜 Recent review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4e8556 and 70889fa.

📒 Files selected for processing (2)
  • newton/geometry/inertia.py (2 hunks)
  • newton/sim/builder.py (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/sim/builder.py
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run GPU Benchmarks (Pull Request)
  • GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
🔇 Additional comments (13)
newton/geometry/inertia.py (13)

20-20: LGTM!

The warnings import is necessary for the inertia verification functionality.


492-521: LGTM!

The function signature and documentation are comprehensive, clearly describing the validation and correction logic similar to MuJoCo's balanceinertia.


530-546: LGTM!

The mass validation logic correctly handles negative mass and optional bounds, with appropriate warnings. The zero mass case properly ensures zero inertia.


547-552: LGTM!

The symmetry check and correction is mathematically sound, ensuring the inertia matrix is symmetric before eigenvalue computation.


554-600: Good eigenvalue handling with appropriate fallback.

The eigenvalue computation correctly identifies negative eigenvalues and applies bounds. The fallback to diagonal matrix in case of LinAlgError is a good safety measure.


634-656: Good final validation with safety fallback.

The final eigenvalue check and emergency correction provide a good safety net. The approach of adding epsilon to diagonal elements as a last resort is appropriate.


658-675: LGTM!

The kernel signature is well-designed for parallel processing with clear documentation about limitations compared to the Python version.


681-695: LGTM!

Mass validation and zero mass handling are correctly implemented for the kernel context.


696-726: Good use of wp.eig3() for eigenvalue computation.

The eigenvalue computation using wp.eig3() addresses the past review feedback. The sorting logic for principal moments is correct, and the negative eigenvalue correction is mathematically sound.


727-735: Triangle inequality check is mathematically correct.

The triangle inequality validation (I1 + I2 >= I3) and correction by adding a scalar to all eigenvalues is the same approach as the Python version, which is mathematically sound.


740-752: Inverse computation looks correct.

The inverse mass and inverse inertia computations are properly handled, with zero cases appropriately managed.


492-752: Excellent implementation addressing performance and correctness concerns.

This implementation successfully addresses the key objectives:

  1. Comprehensive validation: The Python function provides detailed validation with informative warnings
  2. Performance optimization: The Warp kernel enables parallel processing to address the performance concerns mentioned in PR objectives
  3. Mathematical correctness: Both versions correctly implement triangle inequality checks and eigenvalue-based corrections
  4. Integration ready: The dual approach allows the ModelBuilder to choose between detailed validation (Python) and fast batch processing (kernel)

The code demonstrates good engineering practices with appropriate fallbacks, edge case handling, and clear documentation.


601-632: No further action required – triangle inequality balancing is already covered by existing tests

The balancing algorithm is validated by comprehensive unit tests:

  • newton/tests/test_inertia_validation.py
    • test_triangle_inequality_violation checks that a violating inertia tensor is corrected (and that the corrected eigenvalues satisfy I1 + I2 ≥ I3).
    • test_no_balance_inertia ensures no correction when balance_inertia=False.
    • test_valid_inertia_no_correction confirms valid tensors remain unchanged.
  • newton/tests/test_import_mjcf.py verifies that importing an MJCF body with invalid inertias applies the expected scalar shift while preserving off-diagonal (rotation) components.

Since these tests already exercise and verify the triangle-inequality correction logic, no additional verification is needed.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
@vreutskyy vreutskyy had a problem deploying to external-pr-approval July 22, 2025 11:40 — with GitHub Actions Error

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
newton/geometry/inertia.py (2)

602-602: Consider making the maximum iterations configurable.

The hardcoded max_iterations = 10 may not be sufficient for severely unbalanced inertia tensors, potentially leading to incomplete corrections.

def verify_and_correct_inertia(
    mass: float,
    inertia: wp.mat33,
    balance_inertia: bool = True,
    bound_mass: float | None = None,
    bound_inertia: float | None = None,
+   max_iterations: int = 10,
) -> tuple[float, wp.mat33, bool]:

Then update the balancing loop:

-        max_iterations = 10
+        # max_iterations is now a parameter

613-613: The convergence tolerance may be too strict for some use cases.

The hardcoded tolerance of 1e-10 might be overly strict for floating-point computations, potentially causing unnecessary iterations.

Consider making the tolerance configurable or using a more appropriate value like 1e-8 or even relative to the magnitude of the inertia values:

-                if max_violation <= 1e-10:
+                if max_violation <= max(1e-8, 1e-10 * max(I)):
newton/sim/builder.py (1)

3402-3425: Excellent integration of inertia validation with proper error handling

The inertia verification and correction is well-integrated into the finalization process:

Strengths:

  • Conditional execution prevents unnecessary processing when validation is disabled
  • Proper handling of corrected mass and inertia values with appropriate inverse calculations
  • Maintains consistency with existing inverse mass/inertia computation patterns (matches lines 3187-3190)
  • Updates all related properties (mass, inertia, inv_mass, inv_inertia) when corrections occur

Minor optimization opportunity:
The condition check could be simplified since verify_and_correct_inertia handles None values gracefully:

-if self.balance_inertia or self.bound_mass is not None or self.bound_inertia is not None:
+if self.balance_inertia or self.bound_mass is not None or self.bound_inertia is not None:

However, the current approach is clearer about when validation occurs and avoids unnecessary function calls.

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0815700 and 3222c0b.

📒 Files selected for processing (3)
  • newton/geometry/inertia.py (2 hunks)
  • newton/sim/builder.py (3 hunks)
  • newton/tests/test_inertia_validation.py (1 hunks)
🧠 Learnings (1)
newton/tests/test_inertia_validation.py (1)

Learnt from: dylanturpin
PR: #394
File: newton/tests/test_ik.py:119-119
Timestamp: 2025-07-15T21:00:03.709Z
Learning: In the Newton physics engine codebase, it's acceptable to test private API functions (those prefixed with underscore) in unit and component tests, as the maintainers consider this appropriate for testing internal functionality.

🧬 Code Graph Analysis (1)
newton/sim/builder.py (1)
newton/geometry/inertia.py (1)
  • verify_and_correct_inertia (492-652)
🧰 Additional context used
🧠 Learnings (1)
newton/tests/test_inertia_validation.py (1)

Learnt from: dylanturpin
PR: #394
File: newton/tests/test_ik.py:119-119
Timestamp: 2025-07-15T21:00:03.709Z
Learning: In the Newton physics engine codebase, it's acceptable to test private API functions (those prefixed with underscore) in unit and component tests, as the maintainers consider this appropriate for testing internal functionality.

🧬 Code Graph Analysis (1)
newton/sim/builder.py (1)
newton/geometry/inertia.py (1)
  • verify_and_correct_inertia (492-652)
🔇 Additional comments (18)
newton/geometry/inertia.py (6)

20-20: LGTM: Import addition is appropriate.

The warnings import is correctly added to support the warning functionality in the new inertia verification function.


492-518: Function signature and documentation are well-designed.

The function signature appropriately handles all the key parameters mentioned in the PR objectives, and the comprehensive docstring clearly explains the functionality, parameters, and return values.


519-540: Mass validation logic is correct and handles edge cases properly.

The mass correction logic correctly handles negative masses, applies bounds when specified, and properly handles the zero-mass case by zeroing the inertia tensor. The early return for zero mass is an efficient optimization.


542-579: Inertia matrix corrections are comprehensive and correct.

The code properly handles:

  • Symmetrization of asymmetric matrices
  • Correction of negative diagonal elements
  • Application of inertia bounds

The implementation correctly extracts diagonal elements and updates them appropriately.


580-595: Triangle inequality violation detection is mathematically correct.

The three triangle inequality constraints for inertia tensors are correctly implemented:

  • Ixx + Iyy >= Izz
  • Iyy + Izz >= Ixx
  • Izz + Ixx >= Iyy

The violation detection logic properly identifies all constraint violations.


636-651: Final positive definite check is a good safety measure.

The eigenvalue check and correction mechanism provides a robust fallback for ensuring the final inertia matrix is physically valid. The error handling for LinAlgError is appropriate.

newton/sim/builder.py (2)

65-65: LGTM - Clean import integration

The import of verify_and_correct_inertia is properly placed with other geometry-related imports and follows the existing import conventions.


285-289: Well-designed compiler settings with sensible defaults

The new inertia validation settings are appropriately integrated:

  • balance_inertia=True enables automatic correction by default, ensuring physical validity
  • bound_mass=None and bound_inertia=None provide optional constraints without imposing restrictions by default
  • Clear documentation explains the purpose of each setting

The design follows the MuJoCo-inspired approach mentioned in the PR objectives.

newton/tests/test_inertia_validation.py (10)

1-26: Well-structured test file with proper imports and documentation.

The file follows good practices with comprehensive licensing header, clear docstring, and appropriate imports for testing the inertia validation functionality.


46-60: LGTM - Mass bounding test is well implemented.

The test correctly verifies that mass values below the specified bound are clamped and appropriate warnings are issued.


62-78: LGTM - Negative inertia diagonal correction test is comprehensive.

The test properly validates that negative diagonal inertia elements are corrected to non-negative values and appropriate warnings are issued.


80-99: LGTM - Inertia bounding test correctly validates diagonal element constraints.

The test appropriately verifies that inertia diagonal elements below the specified bound are clamped while maintaining mass unchanged.


100-123: LGTM - Triangle inequality test thoroughly validates physics constraints.

The test properly creates a clear triangle inequality violation and verifies that all three triangle inequality constraints are satisfied after correction. The use of numerical tolerance is appropriate.


148-159: LGTM - Valid inertia test provides good baseline validation.

The test correctly verifies that physically valid inertia tensors are left unchanged and no warnings are issued.


161-195: LGTM - Comprehensive integration test validates end-to-end workflow.

The test properly validates that the ModelBuilder applies inertia corrections during finalization, including mass bounds, inertia bounds, and triangle inequality constraints. The assertions thoroughly check the corrected values in the final model.


197-199: LGTM - Standard unittest execution pattern.

The test file follows standard Python testing conventions with proper main execution guard.


31-44: Fix the inertia comparison for zero mass case.

The test logic is correct, but the assertion on line 42 may not work as expected when comparing a matrix to a scalar.

-            self.assertTrue(np.allclose(np.array(corrected_inertia), 0.0))
+            inertia_array = np.array(corrected_inertia).reshape(3, 3)
+            self.assertTrue(np.allclose(inertia_array, np.zeros((3, 3))))

Likely an incorrect or invalid review comment.


125-146: Ignore the reported inconsistency—test is correct.

The verify_and_correct_inertia implementation sets was_corrected=True whenever a triangle‐inequality violation is detected (even if balance_inertia=False means no inertia values are actually modified). Thus expecting was_corrected=True while leaving the diagonal entries unchanged is intentional and aligns with the code. No change needed to this test.

Likely an incorrect or invalid review comment.

Comment thread newton/geometry/inertia.py Outdated
@vreutskyy vreutskyy marked this pull request as ready for review July 22, 2025 15:52
@vreutskyy vreutskyy temporarily deployed to external-pr-approval July 23, 2025 07:56 — with GitHub Actions Inactive
Comment thread newton/geometry/inertia.py Outdated
Comment thread newton/geometry/inertia.py Outdated
@eric-heiden

Copy link
Copy Markdown
Member

The performance impact seems quite invasive. Can we try to parallelize the validation / correction by moving this logic into a Warp kernel? At least to compare performance numbers. This step occurs during the finalize() step so at this point we have Warp arrays of those inertia quantities already.

@vreutskyy vreutskyy had a problem deploying to external-pr-approval July 24, 2025 09:44 — with GitHub Actions Error

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

♻️ Duplicate comments (1)
newton/geometry/inertia.py (1)

580-635: Triangle inequality validation needs convergence verification.

The triangle inequality checking and balancing algorithm implementation looks correct, but there's a missing convergence check after the iterative loop as noted in past reviews.

The balancing algorithm may not converge in pathological cases. Consider adding a post-loop verification to ensure the algorithm actually converged within max_iterations.

🧹 Nitpick comments (3)
newton/geometry/inertia.py (3)

582-588: Simplify violation detection logic.

The current implementation uses a boolean flag and multiple if statements to detect violations. This can be simplified for better readability and performance.

Consider simplifying the violation detection:

-    has_violations = False
-    if Ixx + Iyy < Izz:
-        has_violations = True  # Ixx + Iyy < Izz
-    if Iyy + Izz < Ixx:
-        has_violations = True  # Iyy + Izz < Ixx
-    if Izz + Ixx < Iyy:
-        has_violations = True  # Izz + Ixx < Iyy
+    has_violations = (Ixx + Iyy < Izz) or (Iyy + Izz < Ixx) or (Izz + Ixx < Iyy)

492-651: Consider performance optimization for batch processing.

Given the PR objectives mention performance concerns about this function being "invasive" during the finalize() step, consider the feasibility of vectorizing operations for batch processing when applied to multiple bodies.

For better performance when processing multiple rigid bodies, consider:

  1. Vectorizing the validation operations using NumPy array operations
  2. Implementing a Warp kernel version as suggested by eric-heiden in the PR comments
  3. Pre-allocating arrays for batch processing scenarios

The current implementation processes one body at a time, which may become a bottleneck for large models with many rigid bodies.


638-647: Eigenvalue computation could fail for edge cases.

While the code handles LinAlgError, there are potential edge cases where eigenvalue computation might produce NaN or infinite values that should be handled.

Consider adding additional validation for the eigenvalues:

        eigenvalues = np.linalg.eigvals(corrected_inertia)
-        if np.any(eigenvalues <= 0):
+        if np.any(eigenvalues <= 0) or np.any(~np.isfinite(eigenvalues)):
            warnings.warn("Corrected inertia matrix is not positive definite, this should not happen", stacklevel=2)
            # As a last resort, make it positive definite by adding a small value to diagonal
-            min_eigenvalue = np.min(eigenvalues)
+            min_eigenvalue = np.min(eigenvalues[np.isfinite(eigenvalues)]) if np.any(np.isfinite(eigenvalues)) else -1e-6
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3222c0b and b301b8e.

📒 Files selected for processing (1)
  • newton/geometry/inertia.py (2 hunks)
🔇 Additional comments (5)
newton/geometry/inertia.py (5)

20-20: Import addition looks good.

The warnings import is appropriately added to support the validation warnings in the new function.


492-518: Function signature and documentation are well-structured.

The function signature is clear with appropriate type hints and default values. The documentation thoroughly explains the validation steps and parameters.


519-540: Mass validation logic is correct.

The mass validation properly handles negative values, zero mass cases, and optional bounds. The zero mass constraint that forces zero inertia is physically correct.


542-579: Inertia matrix validation and bounds checking are implemented correctly.

The code properly symmetrizes non-symmetric matrices, handles negative diagonal elements, and applies bounds when specified. The diagonal element extraction and correction logic is sound.


636-651: Positive definiteness check is robust.

The eigenvalue-based check for positive definiteness with fallback correction is appropriate. The error handling for potential LinAlgError is good defensive programming.

…orrection warnings

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
@vreutskyy vreutskyy had a problem deploying to external-pr-approval July 24, 2025 12:44 — with GitHub Actions Error

@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

♻️ Duplicate comments (1)
newton/geometry/inertia.py (1)

597-636: Add convergence verification after the balancing loop.

The iterative balancing algorithm should verify convergence after the loop completes. If max_violation > tol after all iterations, a warning should be issued to alert users that the algorithm didn't fully converge.

🧹 Nitpick comments (1)
newton/tests/test_inertia_validation.py (1)

161-195: Consider adding triangle inequality verification to the fast validation test.

While the test verifies that bounds are applied, it doesn't check whether the triangle inequalities are satisfied after correction. Add assertions similar to lines 232-234 from the detailed test to ensure complete validation.

             Ixx, Iyy, Izz = body_inertia[0, 0], body_inertia[1, 1], body_inertia[2, 2]
             self.assertGreaterEqual(Ixx, builder.bound_inertia)
             self.assertGreaterEqual(Iyy, builder.bound_inertia)
             self.assertGreaterEqual(Izz, builder.bound_inertia)
+
+            # Check triangle inequalities
+            self.assertGreaterEqual(Ixx + Iyy, Izz - 1e-10)
+            self.assertGreaterEqual(Iyy + Izz, Ixx - 1e-10)
+            self.assertGreaterEqual(Izz + Ixx, Iyy - 1e-10)
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b301b8e and c86163a.

📒 Files selected for processing (3)
  • newton/geometry/inertia.py (2 hunks)
  • newton/sim/builder.py (4 hunks)
  • newton/tests/test_inertia_validation.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/sim/builder.py
🧰 Additional context used
🧠 Learnings (1)
newton/tests/test_inertia_validation.py (1)

Learnt from: dylanturpin
PR: #394
File: newton/tests/test_ik.py:119-119
Timestamp: 2025-07-15T21:00:03.709Z
Learning: In the Newton physics engine codebase, it's acceptable to test private API functions (those prefixed with underscore) in unit and component tests, as the maintainers consider this appropriate for testing internal functionality.

🔇 Additional comments (9)
newton/tests/test_inertia_validation.py (6)

31-44: LGTM! Test correctly validates negative mass correction behavior.

The test properly verifies that negative mass is corrected to zero and that the corresponding inertia tensor is also zeroed out, with appropriate warnings issued.


46-61: Test correctly validates mass bounding behavior.

The test appropriately verifies that mass values below the specified bound are clamped to the bound value with proper warning messages.


63-79: Good test coverage for negative inertia diagonal correction.

The test effectively validates that negative diagonal elements in the inertia tensor are corrected to their absolute values with appropriate warnings.


100-124: Excellent test for triangle inequality balancing.

The test effectively validates the inertia balancing algorithm with an extreme violation case. The use of 1e-10 tolerance for floating-point comparisons is appropriate.


148-159: Good test for the valid inertia case.

The test correctly verifies that valid inertia values pass through without modification or warnings.


196-259: Comprehensive integration tests for ModelBuilder validation.

Both integration tests effectively validate the inertia correction functionality within ModelBuilder, covering detailed validation with specific warnings and default validation behavior.

newton/geometry/inertia.py (3)

492-545: Well-structured initial validation logic.

The function properly handles negative mass, mass bounds, and ensures consistency between zero mass and zero inertia. The symmetrization step is essential for maintaining physical validity.


553-596: Correct implementation of inertia validation checks.

The code properly validates diagonal elements and triangle inequalities. The use of a boolean has_violations variable addresses the previous review feedback about the unused list.


637-657: Appropriate positive definiteness validation.

The eigenvalue check correctly verifies that the inertia matrix is positive definite, with a reasonable fallback mechanism for edge cases.

Comment thread newton/geometry/inertia.py
Comment thread newton/tests/test_inertia_validation.py
Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
@vreutskyy vreutskyy had a problem deploying to external-pr-approval July 24, 2025 16:04 — with GitHub Actions Error
Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
@vreutskyy vreutskyy had a problem deploying to external-pr-approval July 24, 2025 16:26 — with GitHub Actions Error

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

♻️ Duplicate comments (1)
newton/geometry/inertia.py (1)

492-649: The function logic is comprehensive but has a potential convergence issue.

The verify_and_correct_inertia function provides thorough validation and correction of mass and inertia properties. The implementation correctly handles negative mass, asymmetric matrices, negative eigenvalues, and triangle inequality violations. However, there's a concern about the balancing algorithm's convergence guarantee.

The balancing approach using scalar addition to all eigenvalues (lines 615-618) is mathematically sound and preserves eigenvectors, which is better than more complex iterative approaches. The method ensures the triangle inequality is satisfied by adding the minimum necessary adjustment.

🧹 Nitpick comments (1)
newton/geometry/inertia.py (1)

652-735: Warp kernel implementation addresses performance concerns effectively.

The parallel validation kernel provides a performance-optimized alternative to the CPU-based validation, directly addressing the performance concerns raised in the PR objectives. The kernel correctly handles:

  • Mass validation and bounds checking
  • Basic inertia validation with diagonal element bounds
  • Proper updating of both forward and inverse quantities
  • Zero-mass edge cases

The limitation to diagonal-only bounds checking (mentioned in lines 690-707) is reasonable for a parallel implementation, as eigenvalue decomposition would be computationally expensive in a kernel.

However, consider adding a small performance optimization:

    # Update inverse inertia
    if mass > 0.0:
-       inv_inertia = wp.inverse(inertia)
-       body_inv_inertia[tid] = inv_inertia
+       body_inv_inertia[tid] = wp.inverse(inertia)
    else:
        body_inv_inertia[tid] = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c86163a and ca00cff.

📒 Files selected for processing (2)
  • newton/geometry/inertia.py (2 hunks)
  • newton/tests/test_inertia_validation.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/tests/test_inertia_validation.py
🔇 Additional comments (1)
newton/geometry/inertia.py (1)

20-20: LGTM: Import addition is appropriate.

The warnings import is correctly added to support the warning functionality in the new inertia verification functions.

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>

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

🧹 Nitpick comments (1)
newton/geometry/inertia.py (1)

492-649: Comprehensive inertia validation with room for optimization.

The function correctly implements the core validation logic similar to MuJoCo's balanceinertia. However, there are several areas for improvement:

  1. Multiple eigenvalue computations: The function computes eigenvalues multiple times (lines 555, 566, 577, 621, 632), which is computationally expensive.

  2. Triangle inequality balancing: The current approach (lines 605-629) uses a simple scalar addition method which may not be globally optimal, as noted in the PR description.

Consider caching eigenvalue computations and eigenvectors to reduce redundant calculations:

# Compute eigenvalues (principal moments) for validation
try:
-   eigenvalues = np.linalg.eigvals(corrected_inertia)
+   eigenvalues, eigenvectors = np.linalg.eigh(corrected_inertia)
    
    # Check for negative eigenvalues
    if np.any(eigenvalues < 0):
        warnings.warn(
            f"Negative eigenvalues detected{body_id}: {eigenvalues}, making positive definite",
            stacklevel=2,
        )
        # Make positive definite by reconstructing from eigendecomposition
-       min_eig = np.min(eigenvalues)
-       corrected_inertia += np.eye(3) * (-min_eig + 1e-6)
-       eigenvalues = np.linalg.eigvals(corrected_inertia)
+       eigenvalues = np.maximum(eigenvalues, 1e-6)
+       corrected_inertia = eigenvectors @ np.diag(eigenvalues) @ eigenvectors.T
        was_corrected = True
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca00cff and de6823e.

📒 Files selected for processing (2)
  • newton/geometry/inertia.py (2 hunks)
  • newton/tests/test_inertia_validation.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/tests/test_inertia_validation.py
🔇 Additional comments (3)
newton/geometry/inertia.py (3)

20-20: LGTM: Import addition is appropriate.

The warnings import is necessary for the new inertia verification functionality that issues warnings when corrections are made.


605-629: Triangle inequality balancing is now a single-step process.

The current implementation uses a simple one-time scalar adjustment to satisfy the triangle inequality, which differs from the iterative approach mentioned in past review comments. This approach is mathematically sound and guarantees convergence since it's a direct calculation rather than an iterative process.

The adjustment formula deficit + 1e-6 ensures that (I1 + a) + (I2 + a) >= I3 + a is satisfied, which is correct.


652-734: Warp kernel provides efficient parallel validation with documented limitations.

The kernel implementation correctly handles the core validation tasks for parallel processing. Key observations:

  1. Diagonal-only bounds: The kernel only applies bounds to diagonal elements (lines 696-706), which is a reasonable limitation for parallel processing and aligns with the PR's documented constraints.

  2. Inverse inertia calculation: The use of wp.inverse(inertia) (line 730) correctly handles general 3x3 matrices, addressing previous concerns about diagonal-only assumptions.

  3. Simplified validation: The kernel appropriately focuses on basic corrections without complex eigenvalue analysis, which would be expensive in parallel.

The performance-focused approach aligns well with the PR objective of providing a fast validation option for the model finalization step.

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

♻️ Duplicate comments (1)
newton/geometry/inertia.py (1)

492-649: Review the convergence and error handling in the inertia balancing algorithm.

The verify_and_correct_inertia function implements comprehensive inertia validation and correction logic. While the overall approach is sound, there are several areas that need attention:

  1. Convergence verification: The iterative balancing algorithm (lines 605-629) lacks explicit convergence checking, which was flagged in previous reviews.

  2. Performance concerns: As noted by eric-heiden, this function performs extensive validation per body during model finalization, which could impact performance for large models.

  3. Error handling robustness: The eigenvalue computation fallback (lines 588-598) handles LinAlgError but could be more robust.

Consider these improvements:

        if balance_inertia:
            # For non-diagonal matrices, we need to adjust while preserving the rotation
            deficit = I3 - I1 - I2
            if deficit > 0:
                # Simple approach: add scalar to all eigenvalues to ensure validity
                # This preserves eigenvectors exactly
                # We need: (I1 + a) + (I2 + a) >= I3 + a
                # Which simplifies to: I1 + I2 + a >= I3
                # So: a >= I3 - I1 - I2 = deficit
                adjustment = deficit + 1e-6

                # Add scalar*I to shift all eigenvalues equally
                corrected_inertia = corrected_inertia + np.eye(3) * adjustment
                was_corrected = True

                # Recompute eigenvalues for the warning message
                new_eigenvalues = np.linalg.eigvals(corrected_inertia)
                new_eigenvalues = np.sort(new_eigenvalues)
+
+               # Verify convergence
+               new_I1, new_I2, new_I3 = new_eigenvalues
+               if new_I1 + new_I2 < new_I3 - 1e-10:
+                   warnings.warn(
+                       f"Inertia balancing did not fully converge{body_id}; "
+                       f"remaining violation: {new_I3 - new_I1 - new_I2:.3e}",
+                       stacklevel=2,
+                   )

                warnings.warn(
                    f"Balanced principal moments{body_id} from ({I1:.6f}, {I2:.6f}, {I3:.6f}) to "
                    f"({new_eigenvalues[0]:.6f}, {new_eigenvalues[1]:.6f}, {new_eigenvalues[2]:.6f})",
                    stacklevel=2,
                )
🧹 Nitpick comments (1)
newton/geometry/inertia.py (1)

652-734: The Warp kernel implementation addresses performance concerns effectively.

The validate_and_correct_inertia_kernel provides a parallelized alternative for batch processing, which directly addresses eric-heiden's performance concerns. However, there are some areas for improvement:

  1. Limited validation scope: The kernel only performs basic validation (negative mass, bounds, diagonal elements) compared to the comprehensive validation in verify_and_correct_inertia.

  2. Inverse inertia calculation: The kernel uses wp.inverse(inertia) which assumes the matrix is invertible, but this could fail for singular matrices.

Consider adding safeguards for the inverse calculation:

    # Update inverse inertia
    if mass > 0.0:
-       body_inv_inertia[tid] = wp.inverse(inertia)
+       # Check if inertia is invertible before computing inverse
+       det = wp.determinant(inertia)
+       if wp.abs(det) > 1e-12:
+           body_inv_inertia[tid] = wp.inverse(inertia)
+       else:
+           # Fallback for near-singular matrices
+           body_inv_inertia[tid] = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
    else:
        body_inv_inertia[tid] = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

This addresses the concerns about matrix invertibility while maintaining the performance benefits of parallel processing.

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca00cff and de6823e.

📒 Files selected for processing (2)
  • newton/geometry/inertia.py (2 hunks)
  • newton/tests/test_inertia_validation.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/tests/test_inertia_validation.py
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
🔇 Additional comments (1)
newton/geometry/inertia.py (1)

20-20: LGTM: Import addition is appropriate.

The warnings import is correctly added to support the warning functionality in the new inertia verification functions.

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
Comment thread newton/geometry/inertia.py Outdated
Comment thread newton/sim/builder.py
Comment thread newton/sim/builder.py Outdated
Comment thread newton/sim/builder.py Outdated

@eric-heiden eric-heiden left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the kernel implementation, this is a lot faster now!

@adenzler-nvidia

Copy link
Copy Markdown
Member

while we're at it, could we improve the default inertia in builder.add_body? I just hit that case where MuJoCo complains. I know this PR will correct it, but we could also have a default that's actually accepted by the solvers.

@eric-heiden

Copy link
Copy Markdown
Member

while we're at it, could we improve the default inertia in builder.add_body? I just hit that case where MuJoCo complains. I know this PR will correct it, but we could also have a default that's actually accepted by the solvers.

I think this is a separate issue, maybe related to this: #297
It can be unexpected that we use a zero mass, zero inertia for initializing rigid bodies. We should discuss this in the architecture meeting, I will add it to the backlog there. I think this PR should be good to merge in the meantime, I will approve this.

@vreutskyy vreutskyy merged commit dfdd78c into newton-physics:main Jul 29, 2025
12 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Nov 27, 2025
4 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Jan 13, 2026
eric-heiden pushed a commit to eric-heiden/newton that referenced this pull request Jan 28, 2026
…cs#455)

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
mmacklin pushed a commit to mmacklin/newton that referenced this pull request Apr 7, 2026
…cs#455)

Signed-off-by: Viktor Reutskyy <vreutskyy@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add inertia verification, correction

3 participants