warp-lang 1.7.2__py3-none-win_amd64.whl → 1.8.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (181) hide show
  1. warp/__init__.py +3 -1
  2. warp/__init__.pyi +3489 -1
  3. warp/autograd.py +45 -122
  4. warp/bin/warp-clang.dll +0 -0
  5. warp/bin/warp.dll +0 -0
  6. warp/build.py +241 -252
  7. warp/build_dll.py +125 -26
  8. warp/builtins.py +1907 -384
  9. warp/codegen.py +257 -101
  10. warp/config.py +12 -1
  11. warp/constants.py +1 -1
  12. warp/context.py +657 -223
  13. warp/dlpack.py +1 -1
  14. warp/examples/benchmarks/benchmark_cloth.py +2 -2
  15. warp/examples/benchmarks/benchmark_tile_sort.py +155 -0
  16. warp/examples/core/example_sample_mesh.py +1 -1
  17. warp/examples/core/example_spin_lock.py +93 -0
  18. warp/examples/core/example_work_queue.py +118 -0
  19. warp/examples/fem/example_adaptive_grid.py +5 -5
  20. warp/examples/fem/example_apic_fluid.py +1 -1
  21. warp/examples/fem/example_burgers.py +1 -1
  22. warp/examples/fem/example_convection_diffusion.py +9 -6
  23. warp/examples/fem/example_darcy_ls_optimization.py +489 -0
  24. warp/examples/fem/example_deformed_geometry.py +1 -1
  25. warp/examples/fem/example_diffusion.py +2 -2
  26. warp/examples/fem/example_diffusion_3d.py +1 -1
  27. warp/examples/fem/example_distortion_energy.py +1 -1
  28. warp/examples/fem/example_elastic_shape_optimization.py +387 -0
  29. warp/examples/fem/example_magnetostatics.py +5 -3
  30. warp/examples/fem/example_mixed_elasticity.py +5 -3
  31. warp/examples/fem/example_navier_stokes.py +11 -9
  32. warp/examples/fem/example_nonconforming_contact.py +5 -3
  33. warp/examples/fem/example_streamlines.py +8 -3
  34. warp/examples/fem/utils.py +9 -8
  35. warp/examples/interop/example_jax_ffi_callback.py +2 -2
  36. warp/examples/optim/example_drone.py +1 -1
  37. warp/examples/sim/example_cloth.py +1 -1
  38. warp/examples/sim/example_cloth_self_contact.py +48 -54
  39. warp/examples/tile/example_tile_block_cholesky.py +502 -0
  40. warp/examples/tile/example_tile_cholesky.py +2 -1
  41. warp/examples/tile/example_tile_convolution.py +1 -1
  42. warp/examples/tile/example_tile_filtering.py +1 -1
  43. warp/examples/tile/example_tile_matmul.py +1 -1
  44. warp/examples/tile/example_tile_mlp.py +2 -0
  45. warp/fabric.py +7 -7
  46. warp/fem/__init__.py +5 -0
  47. warp/fem/adaptivity.py +1 -1
  48. warp/fem/cache.py +152 -63
  49. warp/fem/dirichlet.py +2 -2
  50. warp/fem/domain.py +136 -6
  51. warp/fem/field/field.py +141 -99
  52. warp/fem/field/nodal_field.py +85 -39
  53. warp/fem/field/virtual.py +97 -52
  54. warp/fem/geometry/adaptive_nanogrid.py +91 -86
  55. warp/fem/geometry/closest_point.py +13 -0
  56. warp/fem/geometry/deformed_geometry.py +102 -40
  57. warp/fem/geometry/element.py +56 -2
  58. warp/fem/geometry/geometry.py +323 -22
  59. warp/fem/geometry/grid_2d.py +157 -62
  60. warp/fem/geometry/grid_3d.py +116 -20
  61. warp/fem/geometry/hexmesh.py +86 -20
  62. warp/fem/geometry/nanogrid.py +166 -86
  63. warp/fem/geometry/partition.py +59 -25
  64. warp/fem/geometry/quadmesh.py +86 -135
  65. warp/fem/geometry/tetmesh.py +47 -119
  66. warp/fem/geometry/trimesh.py +77 -270
  67. warp/fem/integrate.py +107 -52
  68. warp/fem/linalg.py +25 -58
  69. warp/fem/operator.py +124 -27
  70. warp/fem/quadrature/pic_quadrature.py +36 -14
  71. warp/fem/quadrature/quadrature.py +40 -16
  72. warp/fem/space/__init__.py +1 -1
  73. warp/fem/space/basis_function_space.py +66 -46
  74. warp/fem/space/basis_space.py +17 -4
  75. warp/fem/space/dof_mapper.py +1 -1
  76. warp/fem/space/function_space.py +2 -2
  77. warp/fem/space/grid_2d_function_space.py +4 -1
  78. warp/fem/space/hexmesh_function_space.py +4 -2
  79. warp/fem/space/nanogrid_function_space.py +3 -1
  80. warp/fem/space/partition.py +11 -2
  81. warp/fem/space/quadmesh_function_space.py +4 -1
  82. warp/fem/space/restriction.py +5 -2
  83. warp/fem/space/shape/__init__.py +10 -8
  84. warp/fem/space/tetmesh_function_space.py +4 -1
  85. warp/fem/space/topology.py +52 -21
  86. warp/fem/space/trimesh_function_space.py +4 -1
  87. warp/fem/utils.py +53 -8
  88. warp/jax.py +1 -2
  89. warp/jax_experimental/ffi.py +12 -17
  90. warp/jax_experimental/xla_ffi.py +37 -24
  91. warp/math.py +171 -1
  92. warp/native/array.h +99 -0
  93. warp/native/builtin.h +174 -31
  94. warp/native/coloring.cpp +1 -1
  95. warp/native/exports.h +118 -63
  96. warp/native/intersect.h +3 -3
  97. warp/native/mat.h +5 -10
  98. warp/native/mathdx.cpp +11 -5
  99. warp/native/matnn.h +1 -123
  100. warp/native/quat.h +28 -4
  101. warp/native/sparse.cpp +121 -258
  102. warp/native/sparse.cu +181 -274
  103. warp/native/spatial.h +305 -17
  104. warp/native/tile.h +583 -72
  105. warp/native/tile_radix_sort.h +1108 -0
  106. warp/native/tile_reduce.h +237 -2
  107. warp/native/tile_scan.h +240 -0
  108. warp/native/tuple.h +189 -0
  109. warp/native/vec.h +6 -16
  110. warp/native/warp.cpp +36 -4
  111. warp/native/warp.cu +574 -51
  112. warp/native/warp.h +47 -74
  113. warp/optim/linear.py +5 -1
  114. warp/paddle.py +7 -8
  115. warp/py.typed +0 -0
  116. warp/render/render_opengl.py +58 -29
  117. warp/render/render_usd.py +124 -61
  118. warp/sim/__init__.py +9 -0
  119. warp/sim/collide.py +252 -78
  120. warp/sim/graph_coloring.py +8 -1
  121. warp/sim/import_mjcf.py +4 -3
  122. warp/sim/import_usd.py +11 -7
  123. warp/sim/integrator.py +5 -2
  124. warp/sim/integrator_euler.py +1 -1
  125. warp/sim/integrator_featherstone.py +1 -1
  126. warp/sim/integrator_vbd.py +751 -320
  127. warp/sim/integrator_xpbd.py +1 -1
  128. warp/sim/model.py +265 -260
  129. warp/sim/utils.py +10 -7
  130. warp/sparse.py +303 -166
  131. warp/tape.py +52 -51
  132. warp/tests/cuda/test_conditional_captures.py +1046 -0
  133. warp/tests/cuda/test_streams.py +1 -1
  134. warp/tests/geometry/test_volume.py +2 -2
  135. warp/tests/interop/test_dlpack.py +9 -9
  136. warp/tests/interop/test_jax.py +0 -1
  137. warp/tests/run_coverage_serial.py +1 -1
  138. warp/tests/sim/disabled_kinematics.py +2 -2
  139. warp/tests/sim/{test_vbd.py → test_cloth.py} +296 -113
  140. warp/tests/sim/test_collision.py +159 -51
  141. warp/tests/sim/test_coloring.py +15 -1
  142. warp/tests/test_array.py +254 -2
  143. warp/tests/test_array_reduce.py +2 -2
  144. warp/tests/test_atomic_cas.py +299 -0
  145. warp/tests/test_codegen.py +142 -19
  146. warp/tests/test_conditional.py +47 -1
  147. warp/tests/test_ctypes.py +0 -20
  148. warp/tests/test_devices.py +8 -0
  149. warp/tests/test_fabricarray.py +4 -2
  150. warp/tests/test_fem.py +58 -25
  151. warp/tests/test_func.py +42 -1
  152. warp/tests/test_grad.py +1 -1
  153. warp/tests/test_lerp.py +1 -3
  154. warp/tests/test_map.py +481 -0
  155. warp/tests/test_mat.py +1 -24
  156. warp/tests/test_quat.py +6 -15
  157. warp/tests/test_rounding.py +10 -38
  158. warp/tests/test_runlength_encode.py +7 -7
  159. warp/tests/test_smoothstep.py +1 -1
  160. warp/tests/test_sparse.py +51 -2
  161. warp/tests/test_spatial.py +507 -1
  162. warp/tests/test_struct.py +2 -2
  163. warp/tests/test_tuple.py +265 -0
  164. warp/tests/test_types.py +2 -2
  165. warp/tests/test_utils.py +24 -18
  166. warp/tests/tile/test_tile.py +420 -1
  167. warp/tests/tile/test_tile_mathdx.py +518 -14
  168. warp/tests/tile/test_tile_reduce.py +213 -0
  169. warp/tests/tile/test_tile_shared_memory.py +130 -1
  170. warp/tests/tile/test_tile_sort.py +117 -0
  171. warp/tests/unittest_suites.py +4 -6
  172. warp/types.py +462 -308
  173. warp/utils.py +647 -86
  174. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/METADATA +20 -6
  175. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/RECORD +178 -166
  176. warp/stubs.py +0 -3381
  177. warp/tests/sim/test_xpbd.py +0 -399
  178. warp/tests/test_mlp.py +0 -282
  179. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/WHEEL +0 -0
  180. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/licenses/LICENSE.md +0 -0
  181. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/top_level.txt +0 -0
@@ -492,7 +492,7 @@ class TestStreams(unittest.TestCase):
492
492
 
493
493
  # Can't get the stream on a CPU device
494
494
  with self.assertRaises(RuntimeError):
495
- cpu_stream = cpu_device.stream # noqa: F841
495
+ cpu_stream = cpu_device.stream
496
496
 
497
497
  @unittest.skipUnless(len(wp.get_cuda_devices()) > 1, "Requires at least two CUDA devices")
498
498
  @unittest.skipUnless(check_p2p(), "Peer-to-Peer transfers not supported")
@@ -893,7 +893,7 @@ def test_volume_from_numpy_3d(test, device):
893
893
  nums = np.ceil((maxs - mins) / (voxel_size)).astype(dtype=int)
894
894
  centers = np.array([[-1.0, -1.0, -1.0], [0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
895
895
  rad = 2.5
896
- sphere_sdf_np = np.zeros(tuple(nums) + (3,))
896
+ sphere_sdf_np = np.zeros((*tuple(nums), 3))
897
897
  for x in range(nums[0]):
898
898
  for y in range(nums[1]):
899
899
  for z in range(nums[2]):
@@ -935,7 +935,7 @@ def test_volume_aniso_transform(test, device):
935
935
  def test_volume_write(test, device):
936
936
  codecs = ["none", "zip", "blosc"]
937
937
  try:
938
- import blosc # noqa: F401 I001
938
+ import blosc # noqa: F401
939
939
  except ImportError:
940
940
  codecs.pop()
941
941
 
@@ -412,8 +412,8 @@ def test_dlpack_warp_to_jax(test, device):
412
412
 
413
413
  test.assertEqual(a.ptr, j1.unsafe_buffer_pointer())
414
414
  test.assertEqual(a.ptr, j2.unsafe_buffer_pointer())
415
- test.assertEqual(a.device, wp.device_from_jax(list(j1.devices())[0]))
416
- test.assertEqual(a.device, wp.device_from_jax(list(j2.devices())[0]))
415
+ test.assertEqual(a.device, wp.device_from_jax(next(iter(j1.devices()))))
416
+ test.assertEqual(a.device, wp.device_from_jax(next(iter(j2.devices()))))
417
417
  test.assertEqual(a.shape, j1.shape)
418
418
  test.assertEqual(a.shape, j2.shape)
419
419
 
@@ -460,8 +460,8 @@ def test_dlpack_warp_to_jax_v2(test, device):
460
460
 
461
461
  test.assertEqual(a.ptr, j1.unsafe_buffer_pointer())
462
462
  test.assertEqual(a.ptr, j2.unsafe_buffer_pointer())
463
- test.assertEqual(a.device, wp.device_from_jax(list(j1.devices())[0]))
464
- test.assertEqual(a.device, wp.device_from_jax(list(j2.devices())[0]))
463
+ test.assertEqual(a.device, wp.device_from_jax(next(iter(j1.devices()))))
464
+ test.assertEqual(a.device, wp.device_from_jax(next(iter(j2.devices()))))
465
465
  test.assertEqual(a.shape, j1.shape)
466
466
  test.assertEqual(a.shape, j2.shape)
467
467
 
@@ -543,15 +543,15 @@ def test_dlpack_jax_to_warp(test, device):
543
543
  j = jax.numpy.arange(N, dtype=jax.numpy.float32)
544
544
 
545
545
  # use generic dlpack conversion
546
- a1 = wp.from_dlpack(jax.dlpack.to_dlpack(j))
546
+ a1 = wp.from_dlpack(j)
547
547
 
548
548
  # use jax wrapper
549
549
  a2 = wp.from_jax(j)
550
550
 
551
551
  test.assertEqual(a1.ptr, j.unsafe_buffer_pointer())
552
552
  test.assertEqual(a2.ptr, j.unsafe_buffer_pointer())
553
- test.assertEqual(a1.device, wp.device_from_jax(list(j.devices())[0]))
554
- test.assertEqual(a2.device, wp.device_from_jax(list(j.devices())[0]))
553
+ test.assertEqual(a1.device, wp.device_from_jax(next(iter(j.devices()))))
554
+ test.assertEqual(a2.device, wp.device_from_jax(next(iter(j.devices()))))
555
555
  test.assertEqual(a1.shape, j.shape)
556
556
  test.assertEqual(a2.shape, j.shape)
557
557
 
@@ -586,8 +586,8 @@ def test_dlpack_jax_to_warp_v2(test, device):
586
586
 
587
587
  test.assertEqual(a1.ptr, j.unsafe_buffer_pointer())
588
588
  test.assertEqual(a2.ptr, j.unsafe_buffer_pointer())
589
- test.assertEqual(a1.device, wp.device_from_jax(list(j.devices())[0]))
590
- test.assertEqual(a2.device, wp.device_from_jax(list(j.devices())[0]))
589
+ test.assertEqual(a1.device, wp.device_from_jax(next(iter(j.devices()))))
590
+ test.assertEqual(a2.device, wp.device_from_jax(next(iter(j.devices()))))
591
591
  test.assertEqual(a1.shape, j.shape)
592
592
  test.assertEqual(a2.shape, j.shape)
593
593
 
@@ -319,7 +319,6 @@ try:
319
319
  os.environ["XLA_PYTHON_CLIENT_ALLOCATOR"] = "platform"
320
320
 
321
321
  import jax
322
- import jax.dlpack
323
322
 
324
323
  # NOTE: we must enable 64-bit types in Jax to test the full gamut of types
325
324
  jax.config.update("jax_enable_x64", True)
@@ -28,7 +28,7 @@ cover = coverage.Coverage(config_file=True, messages=True)
28
28
  cover.start()
29
29
 
30
30
  with cover.collect():
31
- import unittest_serial # noqa: E402
31
+ import unittest_serial
32
32
 
33
33
  unittest_serial.run_specified()
34
34
 
@@ -123,7 +123,7 @@ def build_complex_joint_mechanism(chain_length):
123
123
  parent_xform=tf1,
124
124
  child_xform=tf2,
125
125
  )
126
- builder.joint_q[-7:] = [0.5, -0.9, 1.4] + list(wp.quat_rpy(0.3, -0.5, 0.7))
126
+ builder.joint_q[-7:] = [0.5, -0.9, 1.4, *wp.quat_rpy(0.3, -0.5, 0.7)]
127
127
  builder.joint_qd[-6:] = [1.0, -1.0, 0.5, 0.8, -0.3, 0.1]
128
128
 
129
129
  b8 = builder.add_body(com=com2)
@@ -133,7 +133,7 @@ def build_complex_joint_mechanism(chain_length):
133
133
  parent_xform=tf1,
134
134
  child_xform=tf2,
135
135
  )
136
- builder.joint_q[-7:] = [-0.3, -0.7, 0.2] + list(wp.quat_rpy(0.1, 0.1, 0.4))
136
+ builder.joint_q[-7:] = [-0.3, -0.7, 0.2, *wp.quat_rpy(0.1, 0.1, 0.4)]
137
137
  builder.joint_qd[-6:] = [-0.34, 0.5, -0.6, -0.4, 0.2, 0.1]
138
138
 
139
139
  # D6 joint that behaves like a fixed joint
@@ -13,15 +13,18 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- import contextlib
17
- import io
18
16
  import unittest
17
+ from functools import partial
18
+
19
+ import numpy as np
19
20
 
20
21
  import warp as wp
21
- import warp.optim
22
22
  import warp.sim
23
- import warp.sim.graph_coloring
23
+ import warp.sim.integrator
24
+ import warp.sim.integrator_euler
24
25
  import warp.sim.integrator_vbd
26
+ import warp.sim.integrator_xpbd
27
+ import warp.sim.particles
25
28
  from warp.sim.model import PARTICLE_FLAG_ACTIVE
26
29
  from warp.tests.unittest_utils import *
27
30
 
@@ -295,40 +298,62 @@ CLOTH_FACES = [
295
298
  ]
296
299
 
297
300
  # fmt: on
298
- class VBDClothSim:
299
- def __init__(self, device, use_cuda_graph=False):
301
+ class ClothSim:
302
+ def __init__(self, device, solver, use_cuda_graph=False):
300
303
  self.frame_dt = 1 / 60
301
- self.num_test_frames = 100
302
- self.num_substeps = 10
303
- self.iterations = 10
304
- self.dt = self.frame_dt / self.num_substeps
304
+ self.num_test_frames = 50
305
+ self.iterations = 5
305
306
  self.device = device
306
307
  self.use_cuda_graph = self.device.is_cuda and use_cuda_graph
307
308
  self.builder = wp.sim.ModelBuilder()
309
+ self.solver = solver
308
310
 
309
- def set_up_sagging_experiment(self):
310
- stiffness = 1e5
311
- kd = 1.0e-7
311
+ if solver != "semi_implicit":
312
+ self.num_substeps = 10
313
+ else:
314
+ self.num_substeps = 32
315
+ self.dt = self.frame_dt / self.num_substeps
312
316
 
317
+ def set_up_sagging_experiment(self):
313
318
  self.input_scale_factor = 1.0
314
319
  self.renderer_scale_factor = 0.01
315
320
  vertices = [wp.vec3(v) * self.input_scale_factor for v in CLOTH_POINTS]
316
321
  faces_flatten = [fv - 1 for fv in CLOTH_FACES]
317
322
 
323
+ kd = 1.0e-7
324
+
325
+ if self.solver != "semi_implicit":
326
+ stretching_stiffness = 1e4
327
+ spring_ke = 1e3
328
+ bending_ke = 10
329
+ else:
330
+ stretching_stiffness = 1e5
331
+ spring_ke = 1e2
332
+ bending_ke = 0.0
333
+
318
334
  self.builder.add_cloth_mesh(
319
- pos=wp.vec3(0.0, 200.0, 0.0),
335
+ pos=wp.vec3(0.0, 0.0, 0.0),
320
336
  rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
321
337
  scale=1.0,
322
338
  vertices=vertices,
323
339
  indices=faces_flatten,
324
340
  vel=wp.vec3(0.0, 0.0, 0.0),
325
- density=0.02,
326
- tri_ke=stiffness,
327
- tri_ka=stiffness,
341
+ density=0.1,
342
+ tri_ke=stretching_stiffness,
343
+ tri_ka=stretching_stiffness,
328
344
  tri_kd=kd,
345
+ edge_ke=bending_ke,
346
+ add_springs=self.solver == "xpbd",
347
+ spring_ke=spring_ke,
348
+ spring_kd=0.0,
329
349
  )
350
+
330
351
  self.fixed_particles = [0, 9]
331
352
 
353
+ self.finalize(ground=False)
354
+
355
+ self.state1.particle_q.fill_(0.0)
356
+
332
357
  def set_up_bending_experiment(self):
333
358
  stretching_stiffness = 1e4
334
359
  stretching_damping = 1e-6
@@ -364,6 +389,9 @@ class VBDClothSim:
364
389
  tri_kd=stretching_damping,
365
390
  edge_ke=10,
366
391
  edge_kd=bending_damping,
392
+ add_springs=self.solver == "xpbd",
393
+ spring_ke=1.0e3,
394
+ spring_kd=0.0,
367
395
  )
368
396
 
369
397
  self.builder.add_cloth_mesh(
@@ -379,6 +407,9 @@ class VBDClothSim:
379
407
  tri_kd=stretching_damping,
380
408
  edge_ke=100,
381
409
  edge_kd=bending_damping,
410
+ add_springs=self.solver == "xpbd",
411
+ spring_ke=1.0e3,
412
+ spring_kd=0.0,
382
413
  )
383
414
 
384
415
  self.builder.add_cloth_mesh(
@@ -394,57 +425,117 @@ class VBDClothSim:
394
425
  tri_kd=stretching_damping,
395
426
  edge_ke=1000,
396
427
  edge_kd=bending_damping,
428
+ add_springs=self.solver == "xpbd",
429
+ spring_ke=1.0e3,
430
+ spring_kd=0.0,
397
431
  )
398
432
 
399
433
  self.fixed_particles = [0, 29, 36, 65, 72, 101]
400
434
 
435
+ self.finalize()
436
+
437
+ def set_collision_experiment(self):
438
+ elasticity_ke = 1e4
439
+ elasticity_kd = 1e-6
440
+
441
+ vs1 = [wp.vec3(v) for v in [[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1]]]
442
+ fs1 = [0, 1, 2, 0, 2, 3]
443
+
444
+ self.builder.add_cloth_mesh(
445
+ pos=wp.vec3(0.0, 0.0, 0.0),
446
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
447
+ scale=1.0,
448
+ vertices=vs1,
449
+ indices=fs1,
450
+ vel=wp.vec3(0.0, 0.0, 0.0),
451
+ density=0.02,
452
+ tri_ke=elasticity_ke,
453
+ tri_ka=elasticity_ke,
454
+ tri_kd=elasticity_kd,
455
+ add_springs=self.solver == "xpbd",
456
+ spring_ke=1.0e3,
457
+ spring_kd=0.0,
458
+ )
459
+
460
+ vs2 = [wp.vec3(v) for v in [[0.3, 0, 0.7], [0.3, 0, 0.2], [0.8, 0, 0.4]]]
461
+ fs2 = [0, 1, 2]
462
+
463
+ self.builder.add_cloth_mesh(
464
+ pos=wp.vec3(0.0, 0.5, 0.0),
465
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
466
+ scale=1.0,
467
+ vertices=vs2,
468
+ indices=fs2,
469
+ vel=wp.vec3(0.0, 0.0, 0.0),
470
+ density=0.02,
471
+ tri_ke=elasticity_ke,
472
+ tri_ka=elasticity_ke,
473
+ tri_kd=elasticity_kd,
474
+ add_springs=self.solver == "xpbd",
475
+ spring_ke=1.0e3,
476
+ spring_kd=0.0,
477
+ )
478
+
479
+ self.fixed_particles = range(0, 4)
480
+
481
+ self.finalize(handle_self_contact=True, ground=False)
482
+ self.model.soft_contact_radius = 0.1
483
+ self.model.soft_contact_margin = 0.1
484
+ self.model.soft_contact_ke = 1e4
485
+ self.model.soft_contact_kd = 1e-3
486
+ self.model.soft_contact_mu = 0.2
487
+ self.model.gravity = wp.vec3(0.0, -1000.0, 0)
488
+ self.num_test_frames = 30
489
+
401
490
  def set_up_non_zero_rest_angle_bending_experiment(self):
402
491
  # fmt: off
403
- vs = [
404
- [ 0. , 10. , -10. ],
405
- [ 0. , 10. , 10. ],
406
- [ 7.07107, 7.07107, -10. ],
407
- [ 7.07107, 7.07107, 10. ],
408
- [ 10. , 0. , -10. ],
409
- [ 10. , -0. , 10. ],
410
- [ 7.07107, -7.07107, -10. ],
411
- [ 7.07107, -7.07107, 10. ],
412
- [ 0. , -10. , -10. ],
413
- [ 0. , -10. , 10. ],
414
- [ -7.07107, -7.07107, -10. ],
415
- [ -7.07107, -7.07107, 10. ],
416
- [-10. , 0. , -10. ],
417
- [-10. , -0. , 10. ],
418
- [ -7.07107, 7.07107, -10. ],
419
- [ -7.07107, 7.07107, 10. ],
492
+ vs =[
493
+ [ 0. , 1. , -1. ],
494
+ [ 0. , 1. , 1. ],
495
+ [ 0.70711, 0.70711, -1. ],
496
+ [ 0.70711, 0.70711, 1. ],
497
+ [ 1. , 0. , -1. ],
498
+ [ 1. , -0. , 1. ],
499
+ [ 0.70711, -0.70711, -1. ],
500
+ [ 0.70711, -0.70711, 1. ],
501
+ [ 0. , -1. , -1. ],
502
+ [ 0. , -1. , 1. ],
503
+ [-0.70711, -0.70711, -1. ],
504
+ [-0.70711, -0.70711, 1. ],
505
+ [-1. , 0. , -1. ],
506
+ [-1. , -0. , 1. ],
507
+ [-0.70711, 0.70711, -1. ],
508
+ [-0.70711, 0.70711, 1. ],
420
509
  ]
421
510
  fs = [
422
- 1, 2, 0,
423
- 3, 4, 2,
424
- 5, 6, 4,
425
- 7, 8, 6,
426
- 9, 10, 8,
427
- 11, 12, 10,
428
- 3, 5, 4,
429
- 13, 14, 12,
430
- 15, 0, 14,
431
- 1, 3, 2,
432
- 5, 7, 6,
433
- 7, 9, 8,
434
- 9, 11, 10,
435
- 11, 13, 12,
511
+ 1, 2, 0,
512
+ 3, 4, 2,
513
+ 5, 6, 4,
514
+ 7, 8, 6,
515
+ 9, 10, 8,
516
+ 11, 12, 10,
517
+ 3, 5, 4,
518
+ 13, 14, 12,
519
+ 15, 0, 14,
520
+ 1, 3, 2,
521
+ 5, 7, 6,
522
+ 7, 9, 8,
523
+ 9, 11, 10,
524
+ 11, 13, 12,
525
+ 13, 15, 14,
526
+ 15, 1, 0,
436
527
  ]
437
528
  # fmt: on
438
529
 
439
- stretching_stiffness = 1e4
440
- stretching_damping = 1e-6
441
- edge_ke = 1000
442
- bending_damping = 1e-2
530
+ stretching_stiffness = 1e5
531
+ stretching_damping = 1e-5
532
+ edge_ke = 100
533
+ bending_damping = 1e-4
443
534
  vs = [wp.vec3(v) for v in vs]
444
535
 
445
536
  self.builder.add_cloth_mesh(
446
- pos=wp.vec3(0.0, 10.0, 0.0),
447
- rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), np.pi / 2),
537
+ pos=wp.vec3(0.0, 0.0, 0.0),
538
+ rot=wp.quat_identity(),
448
539
  scale=1.0,
449
540
  vertices=vs,
450
541
  indices=fs,
@@ -455,21 +546,71 @@ class VBDClothSim:
455
546
  tri_kd=stretching_damping,
456
547
  edge_ke=edge_ke,
457
548
  edge_kd=bending_damping,
549
+ add_springs=self.solver == "xpbd",
550
+ spring_ke=1.0e3,
551
+ spring_kd=0.0,
458
552
  )
459
553
  self.fixed_particles = [0, 1]
460
554
 
461
- def finalize(self):
462
- self.builder.color()
555
+ self.finalize(handle_self_contact=False, ground=False)
556
+
557
+ def set_free_falling_experiment(self):
558
+ self.input_scale_factor = 1.0
559
+ self.renderer_scale_factor = 0.01
560
+ vertices = [wp.vec3(v) * self.input_scale_factor for v in CLOTH_POINTS]
561
+ faces_flatten = [fv - 1 for fv in CLOTH_FACES]
562
+ if self.solver != "semi_implicit":
563
+ stretching_stiffness = 1e4
564
+ spring_ke = 1e3
565
+ bending_ke = 10
566
+ else:
567
+ stretching_stiffness = 1e2
568
+ spring_ke = 1e2
569
+ bending_ke = 10
570
+
571
+ self.builder.add_cloth_mesh(
572
+ vertices=vertices,
573
+ indices=faces_flatten,
574
+ scale=0.1,
575
+ density=2,
576
+ pos=wp.vec3(0.0, 4.0, 0.0),
577
+ rot=wp.quat_identity(),
578
+ vel=wp.vec3(0.0, 0.0, 0.0),
579
+ edge_ke=bending_ke,
580
+ edge_kd=0.0,
581
+ tri_ke=stretching_stiffness,
582
+ tri_ka=stretching_stiffness,
583
+ tri_kd=0.0,
584
+ add_springs=self.solver == "xpbd",
585
+ spring_ke=spring_ke,
586
+ spring_kd=0.0,
587
+ )
588
+ self.fixed_particles = []
589
+ self.num_test_frames = 30
590
+ self.finalize(ground=False)
591
+
592
+ def finalize(self, handle_self_contact=False, ground=True):
593
+ self.builder.color(include_bending=True)
463
594
 
464
595
  self.model = self.builder.finalize(device=self.device)
465
- self.model.ground = True
596
+ self.model.ground = ground
466
597
  self.model.gravity = wp.vec3(0, -1000.0, 0)
467
598
  self.model.soft_contact_ke = 1.0e4
468
- self.model.soft_contact_kd = 1.0e2
599
+ self.model.soft_contact_kd = 1.0e-2
469
600
 
470
601
  self.set_points_fixed(self.model, self.fixed_particles)
471
602
 
472
- self.integrator = wp.sim.VBDIntegrator(self.model, self.iterations)
603
+ if self.solver == "vbd":
604
+ self.integrator = wp.sim.VBDIntegrator(self.model, self.iterations, handle_self_contact=handle_self_contact)
605
+ elif self.solver == "xpbd":
606
+ self.integrator = wp.sim.XPBDIntegrator(
607
+ self.iterations,
608
+ )
609
+ elif self.solver == "semi_implicit":
610
+ self.integrator = wp.sim.SemiImplicitIntegrator()
611
+ else:
612
+ raise ValueError("Unsupported solver type: " + self.solver)
613
+
473
614
  self.state0 = self.model.state()
474
615
  self.state1 = self.model.state()
475
616
 
@@ -477,23 +618,37 @@ class VBDClothSim:
477
618
 
478
619
  self.graph = None
479
620
  if self.use_cuda_graph:
621
+ if self.solver == "vbd":
622
+ wp.set_module_options({"block_dim": 256}, warp.sim.integrator_vbd)
623
+ wp.load_module(warp.sim.integrator_vbd, device=self.device)
624
+ elif self.solver == "xpbd":
625
+ wp.set_module_options({"block_dim": 256}, warp.sim.integrator_xpbd)
626
+ wp.load_module(warp.sim.integrator_xpbd, device=self.device)
627
+ elif self.solver == "semi_implicit":
628
+ wp.set_module_options({"block_dim": 256}, warp.sim.integrator_euler)
629
+ wp.load_module(warp.sim.integrator_euler, device=self.device)
630
+ wp.load_module(warp.sim.particles, device=self.device)
631
+ wp.load_module(warp.sim.integrator, device=self.device)
480
632
  wp.load_module(device=self.device)
481
- wp.set_module_options({"block_dim": 256}, warp.sim.integrator_vbd)
482
- wp.load_module(warp.sim.integrator_vbd, device=self.device)
483
633
  with wp.ScopedCapture(device=self.device, force_module_load=False) as capture:
484
634
  self.simulate()
485
635
  self.graph = capture.graph
486
636
 
487
637
  def simulate(self):
488
- for _step in range(self.num_substeps * self.num_test_frames):
638
+ for _step in range(self.num_substeps):
639
+ self.state0.clear_forces()
640
+
489
641
  self.integrator.simulate(self.model, self.state0, self.state1, self.dt, None)
490
642
  (self.state0, self.state1) = (self.state1, self.state0)
491
643
 
492
644
  def run(self):
493
- if self.graph:
494
- wp.capture_launch(self.graph)
495
- else:
496
- self.simulate()
645
+ self.sim_time = 0.0
646
+ for _frame in range(self.num_test_frames):
647
+ if self.graph:
648
+ wp.capture_launch(self.graph)
649
+ else:
650
+ self.simulate()
651
+ self.sim_time = self.sim_time + self.frame_dt
497
652
 
498
653
  def set_points_fixed(self, model, fixed_particles):
499
654
  if len(fixed_particles):
@@ -504,94 +659,122 @@ class VBDClothSim:
504
659
  model.particle_flags = wp.array(flags, device=model.device)
505
660
 
506
661
 
507
- def test_vbd_cloth(test, device):
508
- with contextlib.redirect_stdout(io.StringIO()) as f:
509
- example = VBDClothSim(device)
510
- example.set_up_bending_experiment()
511
- example.finalize()
512
- example.model.ground = False
662
+ def test_cloth_sagging(test, device, solver):
663
+ example = ClothSim(device, solver, use_cuda_graph=True)
664
+ example.set_up_sagging_experiment()
513
665
 
514
- test.assertRegex(
515
- f.getvalue(),
516
- r"Warp UserWarning: The graph is not optimizable anymore, terminated with a max/min ratio: 2.0 without reaching the target ratio: 1.1",
517
- )
666
+ initial_pos = example.state0.particle_q.numpy().copy()
518
667
 
519
668
  example.run()
520
669
 
670
+ fixed_points = np.where(np.logical_not(example.model.particle_flags.numpy()))
521
671
  # examine that the simulation does not explode
522
672
  final_pos = example.state0.particle_q.numpy()
673
+ test.assertTrue((initial_pos[fixed_points, :] == final_pos[fixed_points, :]).all())
523
674
  test.assertTrue((final_pos < 1e5).all())
524
- # examine that the simulation have moved
675
+ # examine that the simulation has moved
525
676
  test.assertTrue((example.init_pos != final_pos).any())
526
677
 
527
678
 
528
- def test_vbd_cloth_cuda_graph(test, device):
529
- with contextlib.redirect_stdout(io.StringIO()) as f:
530
- example = VBDClothSim(device, use_cuda_graph=True)
531
- example.set_up_sagging_experiment()
532
- example.finalize()
533
-
534
- test.assertRegex(
535
- f.getvalue(),
536
- r"Warp UserWarning: The graph is not optimizable anymore, terminated with a max/min ratio: 2.0 without reaching the target ratio: 1.1",
537
- )
679
+ def test_cloth_bending(test, device, solver):
680
+ example = ClothSim(device, solver, use_cuda_graph=True)
681
+ example.set_up_bending_experiment()
538
682
 
539
683
  example.run()
540
684
 
541
685
  # examine that the simulation does not explode
542
686
  final_pos = example.state0.particle_q.numpy()
543
687
  test.assertTrue((final_pos < 1e5).all())
544
- # examine that the simulation have moved
688
+ # examine that the simulation has moved
545
689
  test.assertTrue((example.init_pos != final_pos).any())
546
690
 
547
691
 
548
- def test_vbd_bending(test, device):
549
- example = VBDClothSim(device, use_cuda_graph=True)
550
- example.set_up_bending_experiment()
551
- example.finalize()
692
+ def test_cloth_bending_non_zero_rest_angle_bending(test, device, solver):
693
+ example = ClothSim(device, solver, use_cuda_graph=True)
694
+ example.set_up_non_zero_rest_angle_bending_experiment()
552
695
 
553
696
  example.run()
554
697
 
555
698
  # examine that the simulation does not explode
556
699
  final_pos = example.state0.particle_q.numpy()
557
- test.assertTrue((final_pos < 1e5).all())
558
- # examine that the simulation have moved
700
+ test.assertTrue((np.abs(final_pos) < 1e5).all())
701
+ # examine that the simulation has moved
559
702
  test.assertTrue((example.init_pos != final_pos).any())
560
703
 
561
704
 
562
- def test_vbd_bending_non_zero_rest_angle_bending(test, device):
563
- example = VBDClothSim(device, use_cuda_graph=True)
564
- example.set_up_non_zero_rest_angle_bending_experiment()
565
- example.finalize()
705
+ def test_cloth_collision(test, device, solver):
706
+ example = ClothSim(device, solver, use_cuda_graph=True)
707
+ example.set_collision_experiment()
708
+
709
+ example.run()
710
+
711
+ # examine that the velocity has died out
712
+ final_vel = example.state0.particle_qd.numpy()
713
+ final_pos = example.state0.particle_q.numpy()
714
+ test.assertTrue((np.linalg.norm(final_vel, axis=0) < 1.0).all())
715
+ # examine that the simulation has moved
716
+ test.assertTrue((example.init_pos != final_pos).any())
717
+
718
+
719
+ def test_cloth_free_fall(test, device, solver):
720
+ example = ClothSim(device, solver)
721
+ example.set_free_falling_experiment()
722
+
723
+ initial_pos = example.state0.particle_q.numpy().copy()
724
+
566
725
  example.run()
567
726
 
568
727
  # examine that the simulation does not explode
569
728
  final_pos = example.state0.particle_q.numpy()
570
729
  test.assertTrue((final_pos < 1e5).all())
571
- # examine that the simulation have moved
730
+ # examine that the simulation has moved
572
731
  test.assertTrue((example.init_pos != final_pos).any())
573
732
 
733
+ gravity = np.array(example.model.gravity)
734
+ diff = final_pos - initial_pos
735
+ vertical_translation_norm = diff @ gravity[..., None] / (np.linalg.norm(gravity) ** 2)
736
+ # ensure it's free-falling
737
+ test.assertTrue((np.abs(vertical_translation_norm - 0.5 * np.linalg.norm(gravity) * (example.dt**2)) < 2e-1).all())
738
+ horizontal_move = diff - (vertical_translation_norm * gravity)
739
+ # ensure its horizontal translation is minimal
740
+ test.assertTrue((np.abs(horizontal_move) < 1e-1).all())
574
741
 
575
- devices = get_test_devices()
576
- cuda_devices = get_selected_cuda_test_devices()
577
742
 
743
+ devices = get_test_devices(mode="basic")
578
744
 
579
- class TestVbd(unittest.TestCase):
745
+
746
+ class TestCloth(unittest.TestCase):
580
747
  pass
581
748
 
582
749
 
583
- add_function_test(TestVbd, "test_vbd_cloth", test_vbd_cloth, devices=devices)
584
- add_function_test(TestVbd, "test_vbd_cloth_cuda_graph", test_vbd_cloth_cuda_graph, devices=cuda_devices)
585
- add_function_test(TestVbd, "test_vbd_bending", test_vbd_bending, devices=devices, check_output=False)
586
- add_function_test(
587
- TestVbd,
588
- "test_vbd_bending_non_zero_rest_angle_bending",
589
- test_vbd_bending_non_zero_rest_angle_bending,
590
- devices=devices,
591
- check_output=False,
592
- )
750
+ tests_to_run = {
751
+ "xpbd": [
752
+ test_cloth_free_fall,
753
+ test_cloth_sagging,
754
+ test_cloth_bending,
755
+ test_cloth_bending_non_zero_rest_angle_bending,
756
+ ],
757
+ "semi_implicit": [
758
+ test_cloth_free_fall,
759
+ test_cloth_sagging,
760
+ test_cloth_bending,
761
+ ],
762
+ "vbd": [
763
+ test_cloth_free_fall,
764
+ test_cloth_sagging,
765
+ test_cloth_bending,
766
+ test_cloth_collision,
767
+ test_cloth_bending_non_zero_rest_angle_bending,
768
+ ],
769
+ }
770
+
771
+ for solver, tests in tests_to_run.items():
772
+ for test in tests:
773
+ add_function_test(
774
+ TestCloth, f"{test.__name__}_{solver}", partial(test, solver=solver), devices=devices, check_output=False
775
+ )
593
776
 
594
777
 
595
778
  if __name__ == "__main__":
596
779
  wp.clear_kernel_cache()
597
- unittest.main(verbosity=2)
780
+ unittest.main(verbosity=2, failfast=True)