|
1 | 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 The Newton Developers |
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | 3 |
|
| 4 | +import numpy as np |
4 | 5 | import warp as wp |
5 | | -from asv_runner.benchmarks.mark import skip_benchmark_if |
| 6 | +from asv_runner.benchmarks.mark import SkipNotImplemented, skip_benchmark_if |
6 | 7 |
|
7 | 8 | wp.config.log_level = wp.LOG_WARNING |
8 | 9 |
|
|
15 | 16 | from benchmark_config import pr_gate_repeat |
16 | 17 |
|
17 | 18 | import newton.examples |
| 19 | +from newton._src.geometry.tri_mesh_collision import TriMeshCollisionDetector |
18 | 20 | from newton.examples.cloth.example_cloth_franka import Example as ExampleClothManipulation |
19 | 21 | from newton.examples.cloth.example_cloth_twist import Example as ExampleClothTwist |
20 | 22 | from newton.viewer import ViewerNull |
21 | 23 |
|
| 24 | +DEFORMABLE_COLLISION_CASES = ((256, 1), (16, 1024)) |
| 25 | + |
| 26 | + |
| 27 | +def _make_collision_grid(resolution, height): |
| 28 | + x, y = np.meshgrid(np.arange(resolution) * 0.01, np.arange(resolution) * 0.01) |
| 29 | + vertices = np.column_stack((x.ravel(), y.ravel(), np.full(x.size, height))).astype(np.float32) |
| 30 | + triangles = [] |
| 31 | + for row in range(resolution - 1): |
| 32 | + for column in range(resolution - 1): |
| 33 | + lower = row * resolution + column |
| 34 | + triangles.extend( |
| 35 | + ((lower, lower + 1, lower + resolution), (lower + 1, lower + resolution + 1, lower + resolution)) |
| 36 | + ) |
| 37 | + return vertices, np.asarray(triangles, dtype=np.int32) |
| 38 | + |
| 39 | + |
| 40 | +def _make_collision_world(resolution): |
| 41 | + vertices_a, triangles_a = _make_collision_grid(resolution, 0.0) |
| 42 | + vertices_b, triangles_b = _make_collision_grid(resolution, 0.006) |
| 43 | + triangles_b += len(vertices_a) |
| 44 | + world = newton.ModelBuilder(gravity=wp.vec3(0.0)) |
| 45 | + world.add_cloth_mesh( |
| 46 | + pos=wp.vec3(0.0), |
| 47 | + rot=wp.quat_identity(), |
| 48 | + scale=1.0, |
| 49 | + vel=wp.vec3(0.0), |
| 50 | + vertices=np.concatenate((vertices_a, vertices_b)), |
| 51 | + indices=np.concatenate((triangles_a, triangles_b)).reshape(-1), |
| 52 | + density=1.0, |
| 53 | + tri_ke=1.0, |
| 54 | + tri_ka=1.0, |
| 55 | + tri_kd=0.0, |
| 56 | + edge_ke=0.0, |
| 57 | + edge_kd=0.0, |
| 58 | + ) |
| 59 | + return world |
| 60 | + |
| 61 | + |
| 62 | +class DeformableSelfCollision: |
| 63 | + """Benchmark dense self-collision in one large and many RL-style worlds.""" |
| 64 | + |
| 65 | + params = (DEFORMABLE_COLLISION_CASES,) |
| 66 | + param_names = ["case"] |
| 67 | + repeat = pr_gate_repeat(5) |
| 68 | + number = 1 |
| 69 | + |
| 70 | + def setup(self, case): |
| 71 | + device = wp.get_device() |
| 72 | + if not device.is_cuda: |
| 73 | + raise SkipNotImplemented |
| 74 | + |
| 75 | + resolution, world_count = case |
| 76 | + builder = newton.ModelBuilder() |
| 77 | + builder.replicate(_make_collision_world(resolution), world_count) |
| 78 | + self.model = builder.finalize(device=device) |
| 79 | + self.detector = TriMeshCollisionDetector( |
| 80 | + self.model, |
| 81 | + init_collision_info=True, |
| 82 | + topological_contact_filter_threshold=0, |
| 83 | + vertex_collision_buffer_pre_alloc=32, |
| 84 | + edge_collision_buffer_pre_alloc=64, |
| 85 | + ) |
| 86 | + self.radius = 0.012 |
| 87 | + self.launch_count = 20 |
| 88 | + |
| 89 | + for _ in range(5): |
| 90 | + self._detect() |
| 91 | + with wp.ScopedCapture(device=device) as capture: |
| 92 | + self._detect() |
| 93 | + self.graph = capture.graph |
| 94 | + |
| 95 | + def _detect(self): |
| 96 | + self.detector.refit(self.model.particle_q) |
| 97 | + self.detector.vertex_triangle_collision_detection(self.radius) |
| 98 | + self.detector.edge_edge_collision_detection(self.radius) |
| 99 | + |
| 100 | + @skip_benchmark_if(wp.get_cuda_device_count() == 0) |
| 101 | + def time_detect(self, case): |
| 102 | + for _ in range(self.launch_count): |
| 103 | + wp.capture_launch(self.graph) |
| 104 | + wp.synchronize_device() |
| 105 | + |
22 | 106 |
|
23 | 107 | class FastExampleClothManipulation: |
24 | 108 | timeout = 300 |
@@ -65,6 +149,7 @@ def time_simulate(self): |
65 | 149 | from newton.utils import run_benchmark |
66 | 150 |
|
67 | 151 | benchmark_list = { |
| 152 | + "DeformableSelfCollision": DeformableSelfCollision, |
68 | 153 | "FastExampleClothManipulation": FastExampleClothManipulation, |
69 | 154 | "FastExampleClothTwist": FastExampleClothTwist, |
70 | 155 | } |
|
0 commit comments