Introduce the NarrowPhase class#1014
Conversation
…new NarrowPhase class would look like
📝 WalkthroughWalkthroughAdds a new collision_core module (GJK/MPR drivers and utilities), a Warp-based NarrowPhase with kernels and orchestrator, integrates NarrowPhase into CollisionPipelineUnified via prepare/convert kernels and updated constructor/buffers, and adds a comprehensive narrow-phase unit test suite. Changes
Sequence Diagram(s)sequenceDiagram
participant Pipeline as CollisionPipelineUnified
participant Prep as prepare_geom_data_kernel
participant NP as NarrowPhase.launch()
participant Scale as extract_shape_data
participant GJK as narrow_phase_kernel_gjk_mpr
participant MeshOverlap as narrow_phase_find_mesh_triangle_overlaps_kernel
participant TriProc as narrow_phase_process_mesh_triangle_contacts_kernel
participant PlaneProc as narrow_phase_process_mesh_plane_contacts_kernel
participant Conv as convert_narrow_phase_to_contacts_kernel
Pipeline->>Prep: build geom_data & geom_transform
Prep-->>Pipeline: geom buffers
Pipeline->>NP: candidate_pairs + geom types/data/transforms
NP->>Scale: extract per-shape scale/thickness
Scale-->>NP: scale_array
NP->>GJK: run per-pair GJK/MPR kernel
GJK->>GJK: compute tight AABBs, pre_contact_check
GJK->>GJK: call collision_core.find_contacts / compute_gjk_mpr_contacts
GJK-->>NP: contact buffers + mesh/plane work items
NP->>MeshOverlap: find overlapping mesh triangles (if any)
MeshOverlap-->>NP: triangle_pairs
NP->>TriProc: process triangle contacts
TriProc-->>NP: contact buffers
NP->>PlaneProc: process mesh-plane contacts
PlaneProc-->>NP: contact buffers
NP-->>Pipeline: narrow-phase contact buffers
Pipeline->>Conv: convert to canonical Contacts
Conv-->>Pipeline: Contacts arrays
sequenceDiagram
participant Caller as find_contacts()
participant Pre as pre_contact_check()
participant Bsphere as compute_bounding_sphere_from_aabb()
participant PlaneCheck as check_infinite_plane_bsphere_overlap()
participant Convert as convert_infinite_plane_to_cube()
participant Solver as compute_gjk_mpr_contacts()
Caller->>Pre: shapes + transforms + margins
Pre->>Bsphere: compute bounding spheres
Bsphere-->>Pre: centers & radii
Pre->>PlaneCheck: plane vs bsphere overlap test
PlaneCheck-->>Pre: overlap result
alt overlap OK
Caller->>Convert: (if infinite plane) create finite cube proxy
Convert-->>Caller: proxy shape_data, offset
Caller->>Solver: run GJK/MPR driver (convex/discrete)
Solver-->>Caller: contact count, normal, contact points, penetrations
else rejected
Pre-->>Caller: early-out (no contacts)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Areas needing extra attention:
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
newton/_src/geometry/collision_core.py (1)
445-504: Drop the unused plane argument
convert_infinite_plane_to_cube()no longer touches the incomingshape_data, so Ruff quite rightly warns about ARG001. Easiest fix is to delete that parameter (and matching call sites still compile because we’re just passing the plane data through).-def convert_infinite_plane_to_cube( - shape_data: GenericShapeData, +def convert_infinite_plane_to_cube( plane_rotation: wp.quat,
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
newton/__init__.py(2 hunks)newton/_src/geometry/collision_core.py(1 hunks)newton/_src/geometry/narrow_phase.py(1 hunks)newton/_src/sim/__init__.py(2 hunks)newton/_src/sim/collide_api.py(1 hunks)newton/_src/sim/collide_unified.py(5 hunks)newton/tests/test_narrow_phase.py(1 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).
📚 Learning: 2025-08-12T17:51:37.474Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).
Applied to files:
newton/_src/sim/__init__.pynewton/__init__.pynewton/tests/test_narrow_phase.pynewton/_src/sim/collide_api.pynewton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.pynewton/_src/geometry/collision_core.py
📚 Learning: 2025-08-14T17:38:36.106Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/__init__.py:25-29
Timestamp: 2025-08-14T17:38:36.106Z
Learning: The Newton project prefers incremental __all__ building using __all__ += [...] pattern to group exports with their related imports, rather than a single consolidated __all__ at the end of the file.
Applied to files:
newton/_src/sim/__init__.pynewton/__init__.py
📚 Learning: 2025-08-12T17:58:00.815Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/_src/solvers/featherstone/kernels.py:18-20
Timestamp: 2025-08-12T17:58:00.815Z
Learning: In newton/_src/core/__init__.py, the function transform_twist is properly re-exported from the spatial module via "from .spatial import (..., transform_twist, ...)" and included in __all__, making it available for import as "from ...core import transform_twist" from other modules.
Applied to files:
newton/_src/sim/__init__.pynewton/__init__.py
📚 Learning: 2025-08-12T17:58:16.929Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/tests/test_ik.py:25-26
Timestamp: 2025-08-12T17:58:16.929Z
Learning: In the Newton physics engine codebase, it's acceptable for tests to import and use private `_src` internal modules and functions when needed for testing purposes, even though this breaks the public API boundary. This is an intentional project decision for test code.
Applied to files:
newton/_src/sim/__init__.pynewton/__init__.pynewton/tests/test_narrow_phase.py
📚 Learning: 2025-10-10T10:47:41.082Z
Learnt from: nvtw
PR: newton-physics/newton#899
File: newton/tests/test_rigid_contact.py:214-268
Timestamp: 2025-10-10T10:47:41.082Z
Learning: In `newton/tests/test_rigid_contact.py`, using `add_shape_plane(width=0, length=0)` for an infinite plane works correctly with the collision system and does not cause degenerate AABB issues in the test scenario `test_shape_collisions_gjk_mpr_multicontact`.
Applied to files:
newton/tests/test_narrow_phase.pynewton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.pynewton/_src/geometry/collision_core.py
📚 Learning: 2025-07-15T21:00:03.709Z
Learnt from: dylanturpin
PR: newton-physics/newton#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.
Applied to files:
newton/tests/test_narrow_phase.py
📚 Learning: 2025-09-26T05:58:21.013Z
Learnt from: WenchaoHuang
PR: newton-physics/newton#835
File: newton/_src/solvers/style3d/collision/collision.py:49-53
Timestamp: 2025-09-26T05:58:21.013Z
Learning: In newton/_src/solvers/style3d/collision/collision.py, the broad_phase buffers (broad_phase_ee, broad_phase_ef, broad_phase_vf) created with wp.array() don't need zero-initialization because they follow a write-first-read-later pattern: BVH query kernels in frame_begin() populate these buffers completely (write-only operations), and collision kernels only read from them afterward in accumulate_contact_force(), ensuring no undefined reads occur.
Applied to files:
newton/tests/test_narrow_phase.pynewton/_src/sim/collide_api.pynewton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.pynewton/_src/geometry/collision_core.py
📚 Learning: 2025-10-24T07:56:14.792Z
Learnt from: nvtw
PR: newton-physics/newton#981
File: newton/_src/geometry/collision_convex.py:180-289
Timestamp: 2025-10-24T07:56:14.792Z
Learning: In newton/_src/geometry/collision_convex.py, the single-contact solver (create_solve_convex_single_contact) intentionally returns count=1 even when shapes are separated (signed_distance > contact_threshold). The calling code is responsible for deciding whether to accept the contact based on the signed distance value. This design pushes filtering responsibility to the caller.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/collision_core.py
📚 Learning: 2025-09-26T05:58:21.013Z
Learnt from: WenchaoHuang
PR: newton-physics/newton#835
File: newton/_src/solvers/style3d/collision/collision.py:49-53
Timestamp: 2025-09-26T05:58:21.013Z
Learning: In newton/_src/solvers/style3d/collision/collision.py, the broad_phase buffers (broad_phase_ee, broad_phase_ef, broad_phase_vf) created with wp.array() don't need zero-initialization because the BVH query kernels that use them always write the count to query_results[0, tid] = 0 first before populating any data, ensuring no undefined reads occur.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.py
📚 Learning: 2025-10-30T07:28:13.077Z
Learnt from: nvtw
PR: newton-physics/newton#984
File: newton/_src/geometry/broad_phase_nxn.py:318-336
Timestamp: 2025-10-30T07:28:13.077Z
Learning: In Newton's BroadPhaseAllPairs class (newton/_src/geometry/broad_phase_nxn.py), device management is the caller's responsibility. The library intentionally does not perform automatic device transfers for precomputed arrays in the launch method, even if there's a device mismatch. Users must ensure that the device specified in __init__ matches the device used in launch.
Applied to files:
newton/_src/geometry/narrow_phase.py
📚 Learning: 2025-08-12T05:17:34.423Z
Learnt from: shi-eric
PR: newton-physics/newton#521
File: newton/examples/example_cloth_hanging.py:36-36
Timestamp: 2025-08-12T05:17:34.423Z
Learning: The Newton migration guide (docs/migration.rst) is specifically for documenting how to migrate existing warp.sim functionality to Newton equivalents. New Newton-only features that didn't exist in warp.sim do not need migration documentation.
Applied to files:
newton/_src/geometry/narrow_phase.py
📚 Learning: 2025-08-12T18:04:06.577Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/_src/solvers/featherstone/kernels.py:75-75
Timestamp: 2025-08-12T18:04:06.577Z
Learning: The Newton physics framework requires nightly Warp builds, which means compatibility concerns with older stable Warp versions (like missing functions such as wp.spatial_adjoint) are not relevant for this project.
Applied to files:
newton/_src/geometry/narrow_phase.py
🧬 Code graph analysis (7)
newton/_src/sim/__init__.py (1)
newton/_src/sim/collide_api.py (1)
CollisionPipelineAPI(160-477)
newton/__init__.py (1)
newton/_src/sim/collide_api.py (1)
CollisionPipelineAPI(160-477)
newton/tests/test_narrow_phase.py (2)
newton/_src/geometry/narrow_phase.py (1)
NarrowPhase(649-849)newton/_src/geometry/types.py (1)
GeoType(25-67)
newton/_src/sim/collide_api.py (6)
newton/_src/geometry/broad_phase_nxn.py (2)
BroadPhaseAllPairs(126-207)BroadPhaseExplicit(210-273)newton/_src/geometry/broad_phase_sap.py (1)
BroadPhaseSAP(298-491)newton/_src/geometry/narrow_phase.py (1)
NarrowPhase(649-849)newton/_src/sim/contacts.py (1)
Contacts(23-93)newton/_src/sim/model.py (1)
Model(152-852)newton/_src/sim/collide_unified.py (1)
compute_shape_aabbs(746-810)
newton/_src/sim/collide_unified.py (1)
newton/_src/geometry/collision_core.py (7)
compute_gjk_mpr_contacts(241-363)compute_tight_aabb_from_support(367-427)find_contacts(563-625)find_pair_from_cumulative_index(850-880)get_triangle_shape_from_mesh(884-932)mesh_vs_convex_midphase(750-846)pre_contact_check(629-746)
newton/_src/geometry/narrow_phase.py (3)
newton/_src/geometry/collision_core.py (7)
compute_gjk_mpr_contacts(241-363)compute_tight_aabb_from_support(367-427)find_contacts(563-625)find_pair_from_cumulative_index(850-880)get_triangle_shape_from_mesh(884-932)mesh_vs_convex_midphase(750-846)pre_contact_check(629-746)newton/_src/geometry/support_function.py (3)
GenericShapeData(90-109)SupportMapDataProvider(56-64)pack_mesh_ptr(68-75)newton/_src/geometry/types.py (1)
GeoType(25-67)
newton/_src/geometry/collision_core.py (4)
newton/_src/geometry/broad_phase_common.py (1)
binary_search(42-50)newton/_src/geometry/collision_convex.py (4)
create_solve_convex_multi_contact(54-177)create_solve_convex_single_contact(180-289)solve_convex_multi_contact(73-175)solve_convex_single_contact(198-287)newton/_src/geometry/support_function.py (5)
GenericShapeData(90-109)GeoTypeEx(51-52)SupportMapDataProvider(56-64)pack_mesh_ptr(68-75)support_map(113-339)newton/_src/geometry/types.py (1)
GeoType(25-67)
🪛 Ruff (0.14.2)
newton/tests/test_narrow_phase.py
279-279: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
279-279: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
279-279: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
279-279: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
302-302: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
302-302: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
302-302: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
344-344: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
344-344: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
344-344: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
383-383: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
383-383: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
383-383: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
383-383: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
411-411: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
411-411: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
411-411: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
411-411: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
439-439: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
439-439: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
439-439: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
439-439: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
472-472: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
472-472: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
519-519: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
519-519: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
519-519: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
519-519: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
519-519: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
543-543: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
543-543: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
543-543: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
543-543: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
570-570: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
570-570: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
570-570: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
570-570: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
592-592: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
592-592: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
592-592: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
592-592: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
614-614: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
614-614: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
614-614: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
614-614: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
614-614: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
637-637: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
637-637: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
637-637: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
637-637: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
659-659: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
659-659: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
659-659: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
659-659: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
685-685: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
685-685: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
685-685: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
716-716: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
716-716: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
755-755: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
755-755: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
755-755: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
755-755: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
785-785: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
785-785: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
785-785: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
785-785: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
812-812: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
812-812: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
812-812: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
812-812: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
830-830: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
830-830: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
830-830: Unpacked variable normals is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
830-830: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
830-830: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
858-858: Unpacked variable contact_pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
858-858: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
858-858: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
858-858: Unpacked variable tangents is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
882-882: Unpacked variable pairs is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
882-882: Unpacked variable positions is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
882-882: Unpacked variable penetrations is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
newton/_src/sim/collide_api.py
136-136: Unused function argument: shape_type
(ARG001)
229-229: Avoid specifying long messages outside the exception class
(TRY003)
newton/_src/geometry/narrow_phase.py
61-61: Unused function argument: tid
(ARG001)
188-188: Unused function argument: rigid_contact_margin
(ARG001)
240-240: Unpacked variable scale_a is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
248-248: Unpacked variable scale_b is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
475-475: Unpacked variable scale_b is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
532-532: Unused function argument: geom_types
(ARG001)
newton/_src/geometry/collision_core.py
212-212: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
446-446: Unused function argument: shape_data
(ARG001)
643-643: Unused function argument: mesh_id_a
(ARG001)
874-874: Value being cast to int is already an integer
Remove unnecessary int call
(RUF046)
⏰ 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 Benchmarks (Pull Request)
02821b1 to
1084f50
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
newton/_src/sim/collide_unified.py (2)
322-348: Remove unused parameter.The
shape_typeparameter (line 327) is never used in the kernel body. This adds unnecessary overhead and clutter.Apply this diff:
@wp.kernel def prepare_geom_data_kernel( shape_transform: wp.array(dtype=wp.transform), shape_body: wp.array(dtype=int), - shape_type: wp.array(dtype=int), shape_scale: wp.array(dtype=wp.vec3), shape_thickness: wp.array(dtype=float), body_q: wp.array(dtype=wp.transform), # Outputs geom_data: wp.array(dtype=wp.vec4), # scale xyz, thickness w geom_transform: wp.array(dtype=wp.transform), # world space transform ):And update the launch call at line 546:
inputs=[ model.shape_transform, model.shape_body, - model.shape_type, model.shape_scale, model.shape_thickness, state.body_q, ],
358-613: LGTM with minor suggestion.The refactored
CollisionPipelineUnifiedclass correctly integrates the NarrowPhase workflow with proper device management and buffer handling.Regarding line 419, while the exception message is descriptive, if you prefer to follow the static analysis suggestion strictly, you could extract it to a module-level constant. However, this is a minor style point and the current approach is acceptable.
newton/_src/geometry/narrow_phase.py (3)
50-131: Consider removing unused parameter.The
tidparameter (line 61) is never used in the function body. Unlike the similarwrite_contactfunction in collide_unified.py which storestidinout_tids, this simplified version doesn't have that output array.If
tidis not needed for API compatibility or future use, remove it:@wp.func def write_contact_simple( contact_point_center: wp.vec3, contact_normal_a_to_b: wp.vec3, contact_distance: float, radius_eff_a: float, radius_eff_b: float, thickness_a: float, thickness_b: float, shape_a: int, shape_b: int, - tid: int, rigid_contact_margin: float, contact_max: int, # outputs contact_count: wp.array(dtype=int), contact_pair: wp.array(dtype=wp.vec2i), contact_position: wp.array(dtype=wp.vec3), contact_normal: wp.array(dtype=wp.vec3), contact_penetration: wp.array(dtype=float), contact_tangent: wp.array(dtype=wp.vec3), ):And update all call sites (lines 349, 534, 653).
179-369: Address unused parameter.The
rigid_contact_marginparameter (line 189) is never used in the kernel. Instead, per-geometry cutoff values fromgeom_cutoffare used (lines 327-330). Consider either:
- Removing the parameter if per-geometry cutoff is always preferred
- Using it as a fallback when
geom_cutoffvalues are zeroOption 1 - Remove the parameter:
@wp.kernel(enable_backward=False) def narrow_phase_kernel_gjk_mpr( candidate_pair: wp.array(dtype=wp.vec2i), num_candidate_pair: wp.array(dtype=int), geom_types: wp.array(dtype=int), geom_data: wp.array(dtype=wp.vec4), geom_transform: wp.array(dtype=wp.transform), geom_source: wp.array(dtype=wp.uint64), geom_cutoff: wp.array(dtype=float), geom_collision_radius: wp.array(dtype=float), - rigid_contact_margin: float, contact_max: int, total_num_threads: int, # outputs ...And update the launch call in NarrowPhase.launch (line 777).
556-673: Remove unused parameter, but logic is correct.The
geom_typesparameter (line 558) is never used in the kernel. The kernel correctly processes mesh-plane collisions by checking each mesh vertex against the infinite plane.Apply this diff:
@wp.kernel(enable_backward=False) def narrow_phase_process_mesh_plane_contacts_kernel( - geom_types: wp.array(dtype=int), geom_data: wp.array(dtype=wp.vec4), geom_transform: wp.array(dtype=wp.transform), geom_source: wp.array(dtype=wp.uint64), geom_cutoff: wp.array(dtype=float), # Per-geometry cutoff distances shape_pairs_mesh_plane: wp.array(dtype=wp.vec2i), shape_pairs_mesh_plane_cumsum: wp.array(dtype=int), shape_pairs_mesh_plane_count: wp.array(dtype=int), mesh_plane_vertex_total_count: wp.array(dtype=int), contact_max: int, total_num_threads: int, # outputs ...And update the launch call at line 804.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
newton/_src/geometry/narrow_phase.py(1 hunks)newton/_src/sim/collide_unified.py(8 hunks)newton/tests/test_narrow_phase.py(1 hunks)
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).
Learnt from: WenchaoHuang
Repo: newton-physics/newton PR: 835
File: newton/_src/solvers/style3d/collision/collision.py:49-53
Timestamp: 2025-09-26T05:58:21.013Z
Learning: In newton/_src/solvers/style3d/collision/collision.py, the broad_phase buffers (broad_phase_ee, broad_phase_ef, broad_phase_vf) created with wp.array() don't need zero-initialization because they follow a write-first-read-later pattern: BVH query kernels in frame_begin() populate these buffers completely (write-only operations), and collision kernels only read from them afterward in accumulate_contact_force(), ensuring no undefined reads occur.
📚 Learning: 2025-08-12T17:51:37.474Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.pynewton/tests/test_narrow_phase.py
📚 Learning: 2025-09-26T05:58:21.013Z
Learnt from: WenchaoHuang
Repo: newton-physics/newton PR: 835
File: newton/_src/solvers/style3d/collision/collision.py:49-53
Timestamp: 2025-09-26T05:58:21.013Z
Learning: In newton/_src/solvers/style3d/collision/collision.py, the broad_phase buffers (broad_phase_ee, broad_phase_ef, broad_phase_vf) created with wp.array() don't need zero-initialization because they follow a write-first-read-later pattern: BVH query kernels in frame_begin() populate these buffers completely (write-only operations), and collision kernels only read from them afterward in accumulate_contact_force(), ensuring no undefined reads occur.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.pynewton/tests/test_narrow_phase.py
📚 Learning: 2025-09-26T05:58:21.013Z
Learnt from: WenchaoHuang
Repo: newton-physics/newton PR: 835
File: newton/_src/solvers/style3d/collision/collision.py:49-53
Timestamp: 2025-09-26T05:58:21.013Z
Learning: In newton/_src/solvers/style3d/collision/collision.py, the broad_phase buffers (broad_phase_ee, broad_phase_ef, broad_phase_vf) created with wp.array() don't need zero-initialization because the BVH query kernels that use them always write the count to query_results[0, tid] = 0 first before populating any data, ensuring no undefined reads occur.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.py
📚 Learning: 2025-10-24T07:56:14.792Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 981
File: newton/_src/geometry/collision_convex.py:180-289
Timestamp: 2025-10-24T07:56:14.792Z
Learning: In newton/_src/geometry/collision_convex.py, the single-contact solver (create_solve_convex_single_contact) intentionally returns count=1 even when shapes are separated (signed_distance > contact_threshold). The calling code is responsible for deciding whether to accept the contact based on the signed distance value. This design pushes filtering responsibility to the caller.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.py
📚 Learning: 2025-10-10T10:47:41.082Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 899
File: newton/tests/test_rigid_contact.py:214-268
Timestamp: 2025-10-10T10:47:41.082Z
Learning: In `newton/tests/test_rigid_contact.py`, using `add_shape_plane(width=0, length=0)` for an infinite plane works correctly with the collision system and does not cause degenerate AABB issues in the test scenario `test_shape_collisions_gjk_mpr_multicontact`.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.pynewton/tests/test_narrow_phase.py
📚 Learning: 2025-10-30T07:28:13.077Z
Learnt from: nvtw
Repo: newton-physics/newton PR: 984
File: newton/_src/geometry/broad_phase_nxn.py:318-336
Timestamp: 2025-10-30T07:28:13.077Z
Learning: In Newton's BroadPhaseAllPairs class (newton/_src/geometry/broad_phase_nxn.py), device management is the caller's responsibility. The library intentionally does not perform automatic device transfers for precomputed arrays in the launch method, even if there's a device mismatch. Users must ensure that the device specified in __init__ matches the device used in launch.
Applied to files:
newton/_src/sim/collide_unified.pynewton/_src/geometry/narrow_phase.py
📚 Learning: 2025-08-12T18:04:06.577Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 519
File: newton/_src/solvers/featherstone/kernels.py:75-75
Timestamp: 2025-08-12T18:04:06.577Z
Learning: The Newton physics framework requires nightly Warp builds, which means compatibility concerns with older stable Warp versions (like missing functions such as wp.spatial_adjoint) are not relevant for this project.
Applied to files:
newton/_src/geometry/narrow_phase.py
📚 Learning: 2025-08-12T05:17:34.423Z
Learnt from: shi-eric
Repo: newton-physics/newton PR: 521
File: newton/examples/example_cloth_hanging.py:36-36
Timestamp: 2025-08-12T05:17:34.423Z
Learning: The Newton migration guide (docs/migration.rst) is specifically for documenting how to migrate existing warp.sim functionality to Newton equivalents. New Newton-only features that didn't exist in warp.sim do not need migration documentation.
Applied to files:
newton/_src/geometry/narrow_phase.py
📚 Learning: 2025-08-12T17:58:16.929Z
Learnt from: nvlukasz
Repo: newton-physics/newton PR: 519
File: newton/tests/test_ik.py:25-26
Timestamp: 2025-08-12T17:58:16.929Z
Learning: In the Newton physics engine codebase, it's acceptable for tests to import and use private `_src` internal modules and functions when needed for testing purposes, even though this breaks the public API boundary. This is an intentional project decision for test code.
Applied to files:
newton/tests/test_narrow_phase.py
📚 Learning: 2025-07-15T21:00:03.709Z
Learnt from: dylanturpin
Repo: newton-physics/newton 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.
Applied to files:
newton/tests/test_narrow_phase.py
🧬 Code graph analysis (3)
newton/_src/sim/collide_unified.py (4)
newton/_src/geometry/collision_core.py (1)
compute_tight_aabb_from_support(367-427)newton/_src/geometry/narrow_phase.py (2)
NarrowPhase(675-878)launch(676-878)newton/_src/geometry/support_function.py (2)
GenericShapeData(90-109)SupportMapDataProvider(56-64)newton/_src/sim/contacts.py (1)
Contacts(23-93)
newton/_src/geometry/narrow_phase.py (3)
newton/_src/geometry/collision_core.py (7)
compute_gjk_mpr_contacts(241-363)compute_tight_aabb_from_support(367-427)find_contacts(563-625)find_pair_from_cumulative_index(850-880)get_triangle_shape_from_mesh(884-932)mesh_vs_convex_midphase(750-846)pre_contact_check(629-746)newton/_src/geometry/support_function.py (3)
GenericShapeData(90-109)SupportMapDataProvider(56-64)pack_mesh_ptr(68-75)newton/_src/geometry/types.py (1)
GeoType(25-67)
newton/tests/test_narrow_phase.py (2)
newton/_src/geometry/narrow_phase.py (2)
NarrowPhase(675-878)launch(676-878)newton/_src/geometry/types.py (1)
GeoType(25-67)
🪛 Ruff (0.14.2)
newton/_src/sim/collide_unified.py
326-326: Unused function argument: shape_type
(ARG001)
419-419: Avoid specifying long messages outside the exception class
(TRY003)
newton/_src/geometry/narrow_phase.py
61-61: Unused function argument: tid
(ARG001)
189-189: Unused function argument: rigid_contact_margin
(ARG001)
558-558: Unused function argument: geom_types
(ARG001)
⏰ 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 (11)
newton/_src/sim/collide_unified.py (4)
26-36: LGTM!The imports are clean and necessary for the refactored collision pipeline using NarrowPhase.
53-151: LGTM!The
write_contactfunction correctly handles contact data conversion with proper coordinate frame transforms and thread-safe atomic operations.
153-218: LGTM!The AABB computation correctly uses support functions for tight bounds on convex shapes and conservative bounding spheres for infinite planes and meshes.
615-668: LGTM!The
from_modelfactory method correctly handles default parameter extraction from the Model and properly configures the collision pipeline for different broad phase modes.newton/_src/geometry/narrow_phase.py (4)
39-48: LGTM!Simple utility kernel that correctly extracts scale components from packed geometry data.
133-177: LGTM!The
extract_shape_datahelper correctly unpacks geometry data from the narrow phase API arrays and handles special cases like convex meshes.
371-449: LGTM!The mesh triangle overlap detection correctly uses BVH queries with tiled operations when enabled, and properly handles mesh vs convex shape pairs.
451-554: LGTM!The triangle contact processing correctly extracts triangle geometry from meshes and generates contacts using GJK/MPR collision detection.
newton/tests/test_narrow_phase.py (3)
41-147: LGTM!The helper functions provide comprehensive validation for contact conventions including normal directions, contact positions, and surface reconstruction. The validation logic is sound and well-documented.
149-287: LGTM!The test infrastructure is well-designed with clean helper methods for creating geometry arrays and running the narrow phase. The
_create_geometry_arraysmethod provides a flexible, declarative way to specify test geometries.
288-924: Excellent test coverage!The test suite comprehensively covers:
- All major primitive collision pairs (sphere, box, capsule, cylinder, plane)
- Various contact scenarios (separated, touching, penetrating)
- Edge cases (self-collision, multiple pairs, rotated geometries)
- Contact convention validation (unit normals, perpendicular tangents, surface reconstruction)
The tests follow the documented conventions and provide thorough validation of the NarrowPhase API.
Description
Implemented a narrow phase with the API we agreed upon in the Zurich meeting
Key Changes:
collision_core.pywith shared collision detection functions (GJK/MPR contacts, AABB computation, mesh handling, plane conversion)narrow_phase.pywith standaloneNarrowPhaseclass for collision detection - the launch method of that class has exactly the API we agreed on in the Zurich meetingCollisionPipelineUnifiedto use the newNarrowPhaseclass at the cost of 2 additional data conversion kernel launchestest_narrow_phase.py) validating contact conventions across all primitive pairsNewton Migration Guide
Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this PR.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit