Migrate diffsim examples#616
Conversation
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
📝 WalkthroughWalkthroughAdds five new DiffSim example scripts (ball, cloth, drone, spring_cage, soft_body), registers them in the examples CLI mapping, adds tests to exercise them across devices with device-specific frame counts, and inserts duplicated DiffSim galleries and options blocks into README. No core API or exported-signature changes. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as newton.examples CLI
participant Ex as Example (diffsim_*)
participant Model as Model/Solver
participant Tape as wp.Tape / CUDA capture
User->>CLI: python -m newton.examples diffsim_*
CLI->>Ex: instantiate Example(viewer, opts)
Ex->>Model: build differentiable model + solver
Ex->>Tape: start capture (if CUDA) or begin Tape
loop training iteration
Ex->>Model: forward simulate (many substeps)
Ex->>Ex: compute loss (kernel)
Ex->>Tape: backward -> grads
Ex->>Ex: apply gradient update (kernel / optimizer)
Ex->>Ex: clear grads / update iter
end
Ex-->>User: render frames / viewer updates
sequenceDiagram
autonumber
participant Ex as Drone Example
participant Ref as Reference Drone
participant Roll as Rollout Drones (N)
participant Kern as Warp Kernels
participant Sol as SemiImplicit Solver
participant Tape as wp.Tape
Ex->>Ref: init state & control seed
Ex->>Kern: sample_gaussian -> rollout control points
Ex->>Kern: replicate_states -> create Roll states
Ex->>Tape: start recording (if applicable)
loop horizon timesteps
Roll->>Sol: integrate one step (per rollout)
Roll->>Kern: compute drone_cost + collision_cost
end
Tape-->>Ex: grads wrt control points
Ex->>Kern: enforce_control_limits
Ex->>Kern: pick_best_trajectory
Ex->>Ref: apply best control -> simulate next step
Ex-->>User: render (reference + optional rollouts)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
📜 Recent review detailsConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
🧰 Additional context used🧠 Learnings (1)📓 Common learnings⏰ 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). (3)
🔇 Additional comments (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (14)
newton/examples/diffsim/example_diffsim_ball.py (2)
43-47: Consider extracting the gradient descent update logic to a generic utilityThe gradient descent step pattern is duplicated across multiple DiffSim examples (ball, cloth, etc.). Consider extracting this to a shared utility function or base class to promote code reuse and maintainability.
196-241: Move non-runtime dependencies inside the functionThe
numpyimport should be moved to the top of the file with other imports for consistency.+import numpy as np import warp as wp import newton import newton.examples ... def check_grad(self): - import numpy as np # noqa: PLC0415 - param = self.states[0].particle_qdnewton/examples/diffsim/example_diffsim_cloth.py (2)
36-40: Ensure thread-safe atomic operations in the COM kernelThe
com_kerneluses atomic operations to accumulate the center of mass across particles. While this is correct, the division bynhappens within each thread, which could lead to numerical precision issues with large particle counts. Consider accumulating the sum first and then dividing once.@wp.kernel def com_kernel(positions: wp.array(dtype=wp.vec3), n: int, com: wp.array(dtype=wp.vec3)): tid = wp.tid() # compute center of mass - wp.atomic_add(com, 0, positions[tid] / float(n)) + wp.atomic_add(com, 0, positions[tid])Then divide after the kernel launch:
# After kernel launch in forward() self.com[0] = self.com[0] / float(self.model.particle_count)
121-124: Consider making camera positioning configurableThe hard-coded camera position should be configurable through command-line arguments or configuration to improve usability across different viewing scenarios.
if isinstance(self.viewer, newton.viewer.ViewerGL): - pos = type(self.viewer.camera.pos)(12.5, 0.0, 2.0) + # Allow camera position override via args + default_pos = (12.5, 0.0, 2.0) + pos = type(self.viewer.camera.pos)(*default_pos) self.viewer.camera.pos = posnewton/examples/diffsim/example_diffsim_spring_cage.py (1)
204-204: Address the TODO comment for drawing springsThe TODO comment indicates that springs should be drawn inside
log_state(). This functionality appears to be missing from the framework.Would you like me to help implement the spring visualization functionality within the
log_state()method or create a new issue to track this enhancement?newton/examples/diffsim/example_diffsim_bear.py (3)
33-36: Organize imports following Python conventionsThe imports should be organized in the standard order: standard library, third-party packages, then local imports. Also,
warp.optimshould be grouped with the mainwarpimport.import numpy as np -import warp as wp -import warp.optim from pxr import Usd, UsdGeom + +import warp as wp +import warp.optim import newton import newton.examples
75-77: Missing docstring for the tanh functionThe
tanhfunction applies activation scaling but lacks documentation explaining the purpose ofACTIVATION_STRENGTH.@wp.func def tanh(x: float): + """Apply tanh activation with scaling factor for controlling activation magnitude.""" return wp.tanh(x) * ACTIVATION_STRENGTH
51-58: Document the loss function's objectiveThe loss kernel implements a specific objective function that rewards forward velocity while penalizing lateral/vertical movement. This should be documented for clarity.
@wp.kernel def loss_kernel(com: wp.array(dtype=wp.vec3), loss: wp.array(dtype=float)): + """Compute loss that encourages forward (x) velocity while penalizing lateral (y) and vertical (z) movement.""" tid = wp.tid() vx = com[tid][0] vy = com[tid][1] vz = com[tid][2] + # Maximize forward velocity (vx) while minimizing lateral and vertical velocities delta = wp.sqrt(vy * vy) + wp.sqrt(vz * vz) - vx wp.atomic_add(loss, 0, delta)newton/tests/test_examples.py (1)
356-409: Consider adding a comment explaining the frame calculation.The
num_framescalculations (e.g.,250 * 36,64 * 120) representtrain_iters * sim_steps, which may not be immediately obvious to future maintainers.add_example_test( TestDiffSimExamples, name="diffsim.example_diffsim_ball", devices=test_devices, - test_options={"num_frames": 250 * 36}, # train_iters * sim_steps + test_options={"num_frames": 250 * 36}, # train_iters * sim_steps = 250 * 36 test_options_cpu={"num_frames": 2 * 36}, use_viewer=True, )newton/examples/diffsim/example_diffsim_soft_body.py (2)
112-112: Consider making soft_contact_margin configurable.The hard-coded
soft_contact_margin=0.001appears both here and in line 248. Consider making this a class attribute for easier tuning.class Example: def __init__(self, viewer, material_behavior="anisotropic", verbose=False): # setup simulation parameters first self.fps = 60 self.frame = 0 self.frame_dt = 1.0 / self.fps self.sim_steps = 60 # 1.0 seconds self.sim_substeps = 16 self.sim_substeps_count = self.sim_steps * self.sim_substeps self.sim_dt = self.frame_dt / self.sim_substeps + self.soft_contact_margin = 0.001 # ... rest of __init__ ... - self.contacts = self.model.collide(self.states[0], soft_contact_margin=0.001) + self.contacts = self.model.collide(self.states[0], soft_contact_margin=self.soft_contact_margin)And update line 248 similarly:
- self.contacts = self.model.collide(self.states[i], soft_contact_margin=0.001) + self.contacts = self.model.collide(self.states[i], soft_contact_margin=self.soft_contact_margin)
323-324: Remove empty test method or add TODO comment.The empty
testmethod doesn't serve any purpose. Either remove it or add a TODO comment explaining what testing functionality is planned.- def test(self): - passnewton/examples/diffsim/example_diffsim_drone.py (3)
207-207: Address the TODO comment about mesh scaling.The comment indicates that mesh scaling needs proper handling. This could lead to incorrect collision detection.
The TODO comment suggests mesh scaling isn't handled properly, which could affect collision accuracy. Would you like me to help implement proper mesh scaling or create an issue to track this?
549-564: Check for USD viewer type before USD-specific operations.The USD-specific code assumes
pxris available whenever the viewer is aViewerUSD. Consider adding error handling for the import.if isinstance(self.viewer, newton.viewer.ViewerUSD): - from pxr import UsdGeom # noqa: PLC0415 + try: + from pxr import UsdGeom # noqa: PLC0415 + except ImportError: + print("Warning: USD Python bindings not available, skipping drone geometry customization") + return # Remove the default drone geometries.
776-776: Use more robust state swapping.Direct tuple assignment for swapping could be more clearly expressed and is more maintainable using standard Python idioms.
- (self.drone.states[0], self.drone.states[1]) = (self.drone.states[1], self.drone.states[0]) + self.drone.states[0], self.drone.states[1] = self.drone.states[1], self.drone.states[0]
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (7)
docs/images/examples/example_diffsim_ball.jpgis excluded by!**/*.jpgdocs/images/examples/example_diffsim_bear.jpgis excluded by!**/*.jpgdocs/images/examples/example_diffsim_bear.pngis excluded by!**/*.pngdocs/images/examples/example_diffsim_cloth.jpgis excluded by!**/*.jpgdocs/images/examples/example_diffsim_drone.jpgis excluded by!**/*.jpgdocs/images/examples/example_diffsim_soft_body.jpgis excluded by!**/*.jpgdocs/images/examples/example_diffsim_spring_cage.jpgis excluded by!**/*.jpg
📒 Files selected for processing (9)
README.md(1 hunks)newton/examples/__init__.py(1 hunks)newton/examples/diffsim/example_diffsim_ball.py(1 hunks)newton/examples/diffsim/example_diffsim_bear.py(1 hunks)newton/examples/diffsim/example_diffsim_cloth.py(1 hunks)newton/examples/diffsim/example_diffsim_drone.py(1 hunks)newton/examples/diffsim/example_diffsim_soft_body.py(1 hunks)newton/examples/diffsim/example_diffsim_spring_cage.py(1 hunks)newton/tests/test_examples.py(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
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.
🧬 Code graph analysis (6)
newton/examples/diffsim/example_diffsim_spring_cage.py (3)
newton/_src/sim/builder.py (3)
add_particle(2699-2733)particle_count(506-507)add_spring(2767-2795)newton/_src/solvers/euler/solver_euler.py (1)
SolverSemiImplicit(35-149)newton/examples/__init__.py (3)
create_parser(97-123)init(126-167)run(36-44)
newton/examples/diffsim/example_diffsim_drone.py (3)
newton/_src/geometry/kernels.py (7)
box_sdf(188-196)capsule_sdf(230-237)cone_sdf(268-272)cylinder_sdf(252-255)mesh_sdf(523-533)plane_sdf(295-300)sphere_sdf(178-179)newton/examples/__init__.py (4)
get_asset_directory(28-29)create_parser(97-123)init(126-167)run(36-44)newton/_src/geometry/types.py (2)
GeoType(25-36)SDF(43-70)
newton/examples/diffsim/example_diffsim_ball.py (4)
newton/examples/diffsim/example_diffsim_bear.py (5)
loss_kernel(51-58)capture(216-222)forward_backward(224-229)forward(231-272)step(274-301)newton/examples/diffsim/example_diffsim_cloth.py (6)
loss_kernel(44-48)step_kernel(52-56)capture(128-134)forward_backward(136-140)forward(142-156)step(158-178)newton/_src/sim/builder.py (6)
dot(3110-3111)ModelBuilder(67-4099)add_particle(2699-2733)add_shape_box(2260-2297)ShapeConfig(142-194)add_ground_plane(2205-2225)newton/_src/solvers/euler/solver_euler.py (1)
SolverSemiImplicit(35-149)
newton/examples/diffsim/example_diffsim_cloth.py (5)
newton/_src/sim/builder.py (2)
ModelBuilder(67-4099)add_cloth_grid(3133-3247)newton/_src/solvers/euler/solver_euler.py (1)
SolverSemiImplicit(35-149)newton/_src/viewer/viewer_gl.py (1)
ViewerGL(35-1133)newton/_src/viewer/viewer.py (1)
log_shapes(164-245)newton/examples/__init__.py (2)
create_parser(97-123)init(126-167)
newton/examples/diffsim/example_diffsim_soft_body.py (4)
newton/examples/diffsim/example_diffsim_bear.py (7)
com_kernel(62-66)loss_kernel(51-58)Example(97-312)capture(216-222)forward_backward(224-229)forward(231-272)step(274-301)newton/examples/diffsim/example_diffsim_cloth.py (7)
com_kernel(36-40)loss_kernel(44-48)Example(59-211)capture(128-134)forward_backward(136-140)forward(142-156)step(158-178)newton/_src/sim/builder.py (3)
dot(3110-3111)add_soft_grid(3406-3538)particle_count(506-507)newton/_src/sim/model.py (1)
collide(510-564)
newton/examples/diffsim/example_diffsim_bear.py (4)
newton/examples/__init__.py (3)
get_asset(32-33)create_parser(97-123)init(126-167)newton/_src/sim/builder.py (5)
add_soft_mesh(3540-3626)add_ground_plane(2205-2225)ShapeConfig(142-194)particle_count(506-507)tet_count(514-515)newton/_src/solvers/euler/solver_euler.py (1)
SolverSemiImplicit(35-149)newton/_src/sim/model.py (1)
collide(510-564)
⏰ 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-newton-tests / newton-unittests (ubuntu-latest)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
🔇 Additional comments (3)
newton/examples/diffsim/example_diffsim_bear.py (1)
112-116: Ensure thebear.usdasset is present and add graceful error handlingI searched the repository (using
fd -t f bear.usd) and didn’t locatebear.usdunder the expected paths, so it’s unclear whether this asset is bundled with the repo or supplied at runtime. Please verify wherebear.usdlives and update the code to handle its absence gracefully.• Confirm that
newton.examples.get_asset("bear.usd")returns a valid filesystem path—if the asset is hosted outside the repo, document its location or include it.
• Before opening the stage, check for file existence and raise a clear exception if missing. For example:import os from pxr import Usd, UsdGeom asset_path = newton.examples.get_asset("bear.usd") if not os.path.exists(asset_path): raise FileNotFoundError(f"Required USD asset not found: {asset_path}") usd_stage = Usd.Stage.Open(asset_path) usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/root/bear")) tet_vertices = np.array(usd_geom.GetPointsAttr().Get()) tet_indices = np.array(usd_geom.GetPrim().GetAttribute("tetraIndices").Get())• Optionally, wrap
Usd.Stage.Openin a try/except to catch USD errors and provide additional context.newton/examples/__init__.py (1)
186-191: LGTM! Clean integration of diffsim examples.The new diffsim example mappings follow the established pattern and are properly organized under the
newton.examples.diffsimmodule namespace.newton/tests/test_examples.py (1)
352-354: LGTM!The test class follows the same pattern as other test classes in the file.
a32ad9d
into
newton-physics:main
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com> Co-authored-by: Eric Heiden <eheiden@nvidia.com> Co-authored-by: Miles Macklin <mmacklin@nvidia.com>
Signed-off-by: Miguel Angel Zamora Mora <mzamoramora@nvidia.com> Co-authored-by: Eric Heiden <eheiden@nvidia.com> Co-authored-by: Miles Macklin <mmacklin@nvidia.com>
Description
Porting examples from warp/optim to address #558
This PR replaces #560
Newton Migration Guide
Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this MR.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit
New Features
Documentation
Tests