From 667c9a35016f4f71ccbd72947aa8d8efd1008c62 Mon Sep 17 00:00:00 2001 From: chhsiao93 Date: Thu, 27 Aug 2026 03:09:51 -0500 Subject: [PATCH] Fix particle_clip_cells for NCLaw shape scenes: was 0.5 for all scenes, but bunny/blub/spot use sim.bound (3) and armadillo uses 1 NCLaw's own nclaw_bc grid semantics were being replayed with a single particle_clip_cells=0.5 for every scene, matching every material's base env/blob/*.yaml. But their mesh-shape configs (bunny.yaml, blub.yaml, spot.yaml) override clip_bound to ${sim.bound} (3 at both the low and high quality presets used here), and armadillo.yaml fixes it at 1. Missing this let our rollouts settle roughly one grid cell past NCLaw's actual floor on plasticine/sand/water's shape scenes -- confirmed by comparing settled particle height against both engines' own grid_op_freeslip kernels (identical index arithmetic) and against NCLaw's own advection clamp (nclaw/sim/mpm.py, new_x = wp.clamp(new_x, bound, 1-bound)). It was the sole cause of those scenes diverging hard from NCLaw's own trajectory even when seeded from the exact truth parameters: plasticine/shape_bunny's truth-theta MSE went from 2.7e-04 to 6.0e-11 (full tier) after this fix, in line with every other scene. --- experiments/nclaw/suite.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/experiments/nclaw/suite.py b/experiments/nclaw/suite.py index 7ca7a65..e6d48c1 100644 --- a/experiments/nclaw/suite.py +++ b/experiments/nclaw/suite.py @@ -108,6 +108,16 @@ def assets() -> Path: NCLAW_GRID_SEMANTICS = {"freeslip_bound": BOUND_CELLS, "mass_eps": 1.0e-7, "empty_node_gravity": True, "mls_transfer": True, "particle_clip_cells": 0.5} + +# particle_clip_cells above is right for every env/blob/*.yaml EXCEPT the +# mesh-shape scenes, which override clip_bound per NCLaw's own configs: +# bunny.yaml, blub.yaml and spot.yaml set it to ${sim.bound} (BOUND_CELLS at +# both the low and high quality presets we use), armadillo.yaml fixes it at 1. +# Missing this made the shape scenes rest against a clip 6x looser than +# NCLaw's, which is why they were the one axis where truth-theta rollouts +# diverged hard from NCLaw's own trajectory even with the correct law. +NCLAW_SHAPE_CLIP_BOUND = {"bunny": BOUND_CELLS, "blub": BOUND_CELLS, + "spot": BOUND_CELLS, "armadillo": 1.0} T_END = 0.5 # 1000 steps of dt 5e-4 N_FRAMES = 125 # our dump cadence, 4 ms CENTER = np.array([0.5, 0.5, 0.5]) @@ -442,6 +452,10 @@ def run_scene(material: str, shape: str, out_path: Path, theta: dict | None = No # their sim/low.yaml (grid 20) sets 1e-7; high and super set 0.0, so # the epsilon follows the trajectory's grid rather than a constant kw_bc["mass_eps"] = 1.0e-7 if n_grid == 20 else 0.0 + # a compare.py scene label like "shape_bunny" has that prefix stripped + # to match NCLAW_SHAPE_CLIP_BOUND's bare shape-name keys + kw_bc["particle_clip_cells"] = NCLAW_SHAPE_CLIP_BOUND.get( + shape.removeprefix("shape_"), 0.5) if isinstance(nclaw_bc, dict): kw_bc.update(nclaw_bc) s.set_grid_semantics(**kw_bc)