warp-lang 1.7.2rc1__py3-none-manylinux_2_34_aarch64.whl → 1.8.0__py3-none-manylinux_2_34_aarch64.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.so +0 -0
  5. warp/bin/warp.so +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.2rc1.dist-info → warp_lang-1.8.0.dist-info}/METADATA +20 -6
  175. {warp_lang-1.7.2rc1.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.2rc1.dist-info → warp_lang-1.8.0.dist-info}/WHEEL +0 -0
  180. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.0.dist-info}/licenses/LICENSE.md +0 -0
  181. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.0.dist-info}/top_level.txt +0 -0
warp/sim/collide.py CHANGED
@@ -232,11 +232,11 @@ def box_sdf_grad(upper: wp.vec3, p: wp.vec3):
232
232
  sz = wp.sign(p[2])
233
233
 
234
234
  # x projection
235
- if qx > qy and qx > qz or qy == 0.0 and qz == 0.0:
235
+ if (qx > qy and qx > qz) or (qy == 0.0 and qz == 0.0):
236
236
  return wp.vec3(sx, 0.0, 0.0)
237
237
 
238
238
  # y projection
239
- if qy > qx and qy > qz or qx == 0.0 and qz == 0.0:
239
+ if (qy > qx and qy > qz) or (qx == 0.0 and qz == 0.0):
240
240
  return wp.vec3(0.0, sy, 0.0)
241
241
 
242
242
  # z projection
@@ -341,9 +341,9 @@ def closest_point_box(upper: wp.vec3, point: wp.vec3):
341
341
  sy = wp.abs(wp.abs(point[1]) - upper[1])
342
342
  sz = wp.abs(wp.abs(point[2]) - upper[2])
343
343
  # return closest point on closest side, handle corner cases
344
- if sx < sy and sx < sz or sy == 0.0 and sz == 0.0:
344
+ if (sx < sy and sx < sz) or (sy == 0.0 and sz == 0.0):
345
345
  x = wp.sign(point[0]) * upper[0]
346
- elif sy < sx and sy < sz or sx == 0.0 and sz == 0.0:
346
+ elif (sy < sx and sy < sz) or (sx == 0.0 and sz == 0.0):
347
347
  y = wp.sign(point[1]) * upper[1]
348
348
  else:
349
349
  z = wp.sign(point[2]) * upper[2]
@@ -1516,11 +1516,8 @@ def handle_contact_pairs(
1516
1516
  diff = p_a_world - p_b_world
1517
1517
 
1518
1518
  # if the plane is infinite or the point is within the plane we fix the normal to prevent intersections
1519
- if (
1520
- geo_scale_b[0] == 0.0
1521
- and geo_scale_b[1] == 0.0
1522
- or wp.abs(query_b[0]) < geo_scale_b[0]
1523
- and wp.abs(query_b[2]) < geo_scale_b[1]
1519
+ if (geo_scale_b[0] == 0.0 and geo_scale_b[1] == 0.0) or (
1520
+ wp.abs(query_b[0]) < geo_scale_b[0] and wp.abs(query_b[2]) < geo_scale_b[1]
1524
1521
  ):
1525
1522
  normal = wp.transform_vector(X_ws_b, wp.vec3(0.0, 1.0, 0.0))
1526
1523
  distance = wp.dot(diff, normal)
@@ -1618,7 +1615,7 @@ def collide(
1618
1615
  device=model.device,
1619
1616
  )
1620
1617
 
1621
- if model.shape_contact_pair_count or model.ground and model.shape_ground_contact_pair_count:
1618
+ if model.shape_contact_pair_count or (model.ground and model.shape_ground_contact_pair_count):
1622
1619
  # clear old count
1623
1620
  model.rigid_contact_count.zero_()
1624
1621
 
@@ -1683,7 +1680,7 @@ def collide(
1683
1680
  record_tape=False,
1684
1681
  )
1685
1682
 
1686
- if model.shape_contact_pair_count or model.ground and model.shape_ground_contact_pair_count:
1683
+ if model.shape_contact_pair_count or (model.ground and model.shape_ground_contact_pair_count):
1687
1684
  if requires_grad:
1688
1685
  model.rigid_contact_point0 = wp.empty_like(model.rigid_contact_point0)
1689
1686
  model.rigid_contact_point1 = wp.empty_like(model.rigid_contact_point1)
@@ -1850,7 +1847,7 @@ def vertex_triangle_collision_detection_kernel(
1850
1847
  """
1851
1848
  This function applies discrete collision detection between vertices and triangles. It uses pre-allocated spaces to
1852
1849
  record the collision data. This collision detector works both ways, i.e., it records vertices' colliding triangles to
1853
- vertex_colliding_triangles, and records each triangles colliding vertices to triangle_colliding_vertices.
1850
+ `vertex_colliding_triangles`, and records each triangles colliding vertices to `triangle_colliding_vertices`.
1854
1851
 
1855
1852
  This function assumes that all the vertices are on triangles, and can be indexed from the pos argument.
1856
1853
 
@@ -1870,7 +1867,8 @@ def vertex_triangle_collision_detection_kernel(
1870
1867
  vertex_colliding_triangles_offsets (array): where each vertex' collision buffer starts
1871
1868
  vertex_colliding_triangles_buffer_sizes (array): size of each vertex' collision buffer, will be modified if resizing is needed
1872
1869
  vertex_colliding_triangles_min_dist (array): each vertex' min distance to all (non-neighbor) triangles
1873
- triangle_colliding_vertices (array): positions of all the triangles' collision vertices
1870
+ triangle_colliding_vertices (array): positions of all the triangles' collision vertices, every two elements
1871
+ records the vertex index and a triangle index it collides to
1874
1872
  triangle_colliding_vertices_count (array): number of triangles each vertex collides
1875
1873
  triangle_colliding_vertices_offsets (array): where each triangle's collision buffer starts
1876
1874
  triangle_colliding_vertices_buffer_sizes (array): size of each triangle's collision buffer, will be modified if resizing is needed
@@ -1880,6 +1878,8 @@ def vertex_triangle_collision_detection_kernel(
1880
1878
 
1881
1879
  v_index = wp.tid()
1882
1880
  v = pos[v_index]
1881
+ vertex_buffer_offset = vertex_colliding_triangles_offsets[v_index]
1882
+ vertex_buffer_size = vertex_colliding_triangles_offsets[v_index + 1] - vertex_buffer_offset
1883
1883
 
1884
1884
  lower = wp.vec3(v[0] - query_radius, v[1] - query_radius, v[2] - query_radius)
1885
1885
  upper = wp.vec3(v[0] + query_radius, v[1] + query_radius, v[2] + query_radius)
@@ -1905,13 +1905,11 @@ def vertex_triangle_collision_detection_kernel(
1905
1905
  dist = wp.length(closest_p - v)
1906
1906
 
1907
1907
  if dist < query_radius:
1908
- vertex_buffer_offset = vertex_colliding_triangles_offsets[v_index]
1909
- vertex_buffer_size = vertex_colliding_triangles_offsets[v_index + 1] - vertex_buffer_offset
1910
-
1911
1908
  # record v-f collision to vertex
1912
1909
  min_dis_to_tris = wp.min(min_dis_to_tris, dist)
1913
1910
  if vertex_num_collisions < vertex_buffer_size:
1914
- vertex_colliding_triangles[vertex_buffer_offset + vertex_num_collisions] = tri_index
1911
+ vertex_colliding_triangles[2 * (vertex_buffer_offset + vertex_num_collisions)] = v_index
1912
+ vertex_colliding_triangles[2 * (vertex_buffer_offset + vertex_num_collisions) + 1] = tri_index
1915
1913
  else:
1916
1914
  resize_flags[VERTEX_COLLISION_BUFFER_OVERFLOW_INDEX] = 1
1917
1915
 
@@ -1932,6 +1930,94 @@ def vertex_triangle_collision_detection_kernel(
1932
1930
  vertex_colliding_triangles_min_dist[v_index] = min_dis_to_tris
1933
1931
 
1934
1932
 
1933
+ @wp.kernel
1934
+ def vertex_triangle_collision_detection_no_triangle_buffers_kernel(
1935
+ query_radius: float,
1936
+ bvh_id: wp.uint64,
1937
+ pos: wp.array(dtype=wp.vec3),
1938
+ tri_indices: wp.array(dtype=wp.int32, ndim=2),
1939
+ vertex_colliding_triangles_offsets: wp.array(dtype=wp.int32),
1940
+ vertex_colliding_triangles_buffer_sizes: wp.array(dtype=wp.int32),
1941
+ # outputs
1942
+ vertex_colliding_triangles: wp.array(dtype=wp.int32),
1943
+ vertex_colliding_triangles_count: wp.array(dtype=wp.int32),
1944
+ vertex_colliding_triangles_min_dist: wp.array(dtype=float),
1945
+ triangle_colliding_vertices_min_dist: wp.array(dtype=float),
1946
+ resize_flags: wp.array(dtype=wp.int32),
1947
+ ):
1948
+ """
1949
+ This function applies discrete collision detection between vertices and triangles. It uses pre-allocated spaces to
1950
+ record the collision data. Unlike `vertex_triangle_collision_detection_kernel`, this collision detection kernel
1951
+ works only in one way, i.e., it only records vertices' colliding triangles to `vertex_colliding_triangles`.
1952
+
1953
+ This function assumes that all the vertices are on triangles, and can be indexed from the pos argument.
1954
+
1955
+ Note:
1956
+
1957
+ The collision date buffer is pre-allocated and cannot be changed during collision detection, therefore, the space
1958
+ may not be enough. If the space is not enough to record all the collision information, the function will set a
1959
+ certain element in resized_flag to be true. The user can reallocate the buffer based on vertex_colliding_triangles_count
1960
+ and vertex_colliding_triangles_count.
1961
+
1962
+ Attributes:
1963
+ bvh_id (int): the bvh id you want to collide with
1964
+ query_radius (float): the contact radius. vertex-triangle pairs whose distance are less than this will get detected
1965
+ pos (array): positions of all the vertices that make up triangles
1966
+ vertex_colliding_triangles (array): flattened buffer of vertices' collision triangles, every two elements records
1967
+ the vertex index and a triangle index it collides to
1968
+ vertex_colliding_triangles_count (array): number of triangles each vertex collides
1969
+ vertex_colliding_triangles_offsets (array): where each vertex' collision buffer starts
1970
+ vertex_colliding_triangles_buffer_sizes (array): size of each vertex' collision buffer, will be modified if resizing is needed
1971
+ vertex_colliding_triangles_min_dist (array): each vertex' min distance to all (non-neighbor) triangles
1972
+ triangle_colliding_vertices_min_dist (array): each triangle's min distance to all (non-self) vertices
1973
+ resized_flag (array): size == 3, (vertex_buffer_resize_required, triangle_buffer_resize_required, edge_buffer_resize_required)
1974
+ """
1975
+
1976
+ v_index = wp.tid()
1977
+ v = pos[v_index]
1978
+ vertex_buffer_offset = vertex_colliding_triangles_offsets[v_index]
1979
+ vertex_buffer_size = vertex_colliding_triangles_offsets[v_index + 1] - vertex_buffer_offset
1980
+
1981
+ lower = wp.vec3(v[0] - query_radius, v[1] - query_radius, v[2] - query_radius)
1982
+ upper = wp.vec3(v[0] + query_radius, v[1] + query_radius, v[2] + query_radius)
1983
+
1984
+ query = wp.bvh_query_aabb(bvh_id, lower, upper)
1985
+
1986
+ tri_index = wp.int32(0)
1987
+ vertex_num_collisions = wp.int32(0)
1988
+ min_dis_to_tris = query_radius
1989
+ while wp.bvh_query_next(query, tri_index):
1990
+ t1 = tri_indices[tri_index, 0]
1991
+ t2 = tri_indices[tri_index, 1]
1992
+ t3 = tri_indices[tri_index, 2]
1993
+ if vertex_adjacent_to_triangle(v_index, t1, t2, t3):
1994
+ continue
1995
+
1996
+ u1 = pos[t1]
1997
+ u2 = pos[t2]
1998
+ u3 = pos[t3]
1999
+
2000
+ closest_p, bary, feature_type = triangle_closest_point(u1, u2, u3, v)
2001
+
2002
+ dist = wp.length(closest_p - v)
2003
+
2004
+ if dist < query_radius:
2005
+ # record v-f collision to vertex
2006
+ min_dis_to_tris = wp.min(min_dis_to_tris, dist)
2007
+ if vertex_num_collisions < vertex_buffer_size:
2008
+ vertex_colliding_triangles[2 * (vertex_buffer_offset + vertex_num_collisions)] = v_index
2009
+ vertex_colliding_triangles[2 * (vertex_buffer_offset + vertex_num_collisions) + 1] = tri_index
2010
+ else:
2011
+ resize_flags[VERTEX_COLLISION_BUFFER_OVERFLOW_INDEX] = 1
2012
+
2013
+ vertex_num_collisions = vertex_num_collisions + 1
2014
+
2015
+ wp.atomic_min(triangle_colliding_vertices_min_dist, tri_index, dist)
2016
+
2017
+ vertex_colliding_triangles_count[v_index] = vertex_num_collisions
2018
+ vertex_colliding_triangles_min_dist[v_index] = min_dis_to_tris
2019
+
2020
+
1935
2021
  @wp.kernel
1936
2022
  def edge_colliding_edges_detection_kernel(
1937
2023
  query_radius: float,
@@ -2001,7 +2087,8 @@ def edge_colliding_edges_detection_kernel(
2001
2087
  # record e-e collision to e0, and leave e1; e1 will detect this collision from its own thread
2002
2088
  min_dis_to_edges = wp.min(min_dis_to_edges, dist)
2003
2089
  if edge_num_collisions < edge_buffer_size:
2004
- edge_colliding_edges[edge_buffer_offset + edge_num_collisions] = colliding_edge_index
2090
+ edge_colliding_edges[2 * (edge_buffer_offset + edge_num_collisions)] = e_index
2091
+ edge_colliding_edges[2 * (edge_buffer_offset + edge_num_collisions) + 1] = colliding_edge_index
2005
2092
  else:
2006
2093
  resize_flags[EDGE_COLLISION_BUFFER_OVERFLOW_INDEX] = 1
2007
2094
 
@@ -2068,6 +2155,9 @@ def triangle_triangle_collision_detection_kernel(
2068
2155
 
2069
2156
  @wp.struct
2070
2157
  class TriMeshCollisionInfo:
2158
+ vertex_indices: wp.array(dtype=wp.int32)
2159
+ # size: 2 x sum(vertex_colliding_triangles_buffer_sizes)
2160
+ # every two elements records the vertex index and a triangle index it collides to
2071
2161
  vertex_colliding_triangles: wp.array(dtype=wp.int32)
2072
2162
  vertex_colliding_triangles_offsets: wp.array(dtype=wp.int32)
2073
2163
  vertex_colliding_triangles_buffer_sizes: wp.array(dtype=wp.int32)
@@ -2080,6 +2170,8 @@ class TriMeshCollisionInfo:
2080
2170
  triangle_colliding_vertices_count: wp.array(dtype=wp.int32)
2081
2171
  triangle_colliding_vertices_min_dist: wp.array(dtype=float)
2082
2172
 
2173
+ # size: 2 x sum(edge_colliding_edges_buffer_sizes)
2174
+ # every two elements records the edge index and an edge index it collides to
2083
2175
  edge_colliding_edges: wp.array(dtype=wp.int32)
2084
2176
  edge_colliding_edges_offsets: wp.array(dtype=wp.int32)
2085
2177
  edge_colliding_edges_buffer_sizes: wp.array(dtype=wp.int32)
@@ -2095,7 +2187,13 @@ def get_vertex_colliding_triangles_count(col_info: TriMeshCollisionInfo, v: int)
2095
2187
  @wp.func
2096
2188
  def get_vertex_colliding_triangles(col_info: TriMeshCollisionInfo, v: int, i_collision: int):
2097
2189
  offset = col_info.vertex_colliding_triangles_offsets[v]
2098
- return col_info.vertex_colliding_triangles[offset + i_collision]
2190
+ return col_info.vertex_colliding_triangles[2 * (offset + i_collision) + 1]
2191
+
2192
+
2193
+ @wp.func
2194
+ def get_vertex_collision_buffer_vertex_index(col_info: TriMeshCollisionInfo, v: int, i_collision: int):
2195
+ offset = col_info.vertex_colliding_triangles_offsets[v]
2196
+ return col_info.vertex_colliding_triangles[2 * (offset + i_collision)]
2099
2197
 
2100
2198
 
2101
2199
  @wp.func
@@ -2119,13 +2217,20 @@ def get_edge_colliding_edges_count(col_info: TriMeshCollisionInfo, e: int):
2119
2217
  @wp.func
2120
2218
  def get_edge_colliding_edges(col_info: TriMeshCollisionInfo, e: int, i_collision: int):
2121
2219
  offset = col_info.edge_colliding_edges_offsets[e]
2122
- return col_info.edge_colliding_edges[offset + i_collision]
2220
+ return col_info.edge_colliding_edges[2 * (offset + i_collision) + 1]
2221
+
2222
+
2223
+ @wp.func
2224
+ def get_edge_collision_buffer_edge_index(col_info: TriMeshCollisionInfo, e: int, i_collision: int):
2225
+ offset = col_info.edge_colliding_edges_offsets[e]
2226
+ return col_info.edge_colliding_edges[2 * (offset + i_collision)]
2123
2227
 
2124
2228
 
2125
2229
  class TriMeshCollisionDetector:
2126
2230
  def __init__(
2127
2231
  self,
2128
2232
  model: Model,
2233
+ record_triangle_contacting_vertices=False,
2129
2234
  vertex_positions=None,
2130
2235
  vertex_collision_buffer_pre_alloc=8,
2131
2236
  vertex_collision_buffer_max_alloc=256,
@@ -2138,6 +2243,7 @@ class TriMeshCollisionDetector:
2138
2243
  edge_edge_parallel_epsilon=1e-5,
2139
2244
  ):
2140
2245
  self.model = model
2246
+ self.record_triangle_contacting_vertices = record_triangle_contacting_vertices
2141
2247
  self.vertex_positions = model.particle_q if vertex_positions is None else vertex_positions
2142
2248
  self.device = model.device
2143
2249
  self.vertex_collision_buffer_pre_alloc = vertex_collision_buffer_pre_alloc
@@ -2166,7 +2272,9 @@ class TriMeshCollisionDetector:
2166
2272
 
2167
2273
  # vertex collision buffers
2168
2274
  self.vertex_colliding_triangles = wp.zeros(
2169
- shape=(model.particle_count * self.vertex_collision_buffer_pre_alloc,), dtype=wp.int32, device=self.device
2275
+ shape=(2 * model.particle_count * self.vertex_collision_buffer_pre_alloc,),
2276
+ dtype=wp.int32,
2277
+ device=self.device,
2170
2278
  )
2171
2279
  self.vertex_colliding_triangles_count = wp.array(
2172
2280
  shape=(model.particle_count,), dtype=wp.int32, device=self.device
@@ -2187,26 +2295,39 @@ class TriMeshCollisionDetector:
2187
2295
  self.vertex_colliding_triangles_buffer_sizes, self.vertex_colliding_triangles_offsets
2188
2296
  )
2189
2297
 
2190
- # triangle collision buffers
2191
- self.triangle_colliding_vertices = wp.zeros(
2192
- shape=(model.tri_count * self.triangle_collision_buffer_pre_alloc,), dtype=wp.int32, device=self.device
2193
- )
2194
- self.triangle_colliding_vertices_count = wp.zeros(shape=(model.tri_count,), dtype=wp.int32, device=self.device)
2195
- self.triangle_colliding_vertices_buffer_sizes = wp.full(
2196
- shape=(model.tri_count,), value=self.triangle_collision_buffer_pre_alloc, dtype=wp.int32, device=self.device
2197
- )
2198
- self.triangle_colliding_vertices_min_dist = wp.array(shape=(model.tri_count,), dtype=float, device=self.device)
2298
+ if record_triangle_contacting_vertices:
2299
+ # triangle collision buffers
2300
+ self.triangle_colliding_vertices = wp.zeros(
2301
+ shape=(model.tri_count * self.triangle_collision_buffer_pre_alloc,), dtype=wp.int32, device=self.device
2302
+ )
2303
+ self.triangle_colliding_vertices_count = wp.zeros(
2304
+ shape=(model.tri_count,), dtype=wp.int32, device=self.device
2305
+ )
2306
+ self.triangle_colliding_vertices_buffer_sizes = wp.full(
2307
+ shape=(model.tri_count,),
2308
+ value=self.triangle_collision_buffer_pre_alloc,
2309
+ dtype=wp.int32,
2310
+ device=self.device,
2311
+ )
2199
2312
 
2200
- self.triangle_colliding_vertices_offsets = wp.array(
2201
- shape=(model.tri_count + 1,), dtype=wp.int32, device=self.device
2202
- )
2203
- self.compute_collision_buffer_offsets(
2204
- self.triangle_colliding_vertices_buffer_sizes, self.triangle_colliding_vertices_offsets
2205
- )
2313
+ self.triangle_colliding_vertices_offsets = wp.array(
2314
+ shape=(model.tri_count + 1,), dtype=wp.int32, device=self.device
2315
+ )
2316
+ self.compute_collision_buffer_offsets(
2317
+ self.triangle_colliding_vertices_buffer_sizes, self.triangle_colliding_vertices_offsets
2318
+ )
2319
+ else:
2320
+ self.triangle_colliding_vertices = None
2321
+ self.triangle_colliding_vertices_count = None
2322
+ self.triangle_colliding_vertices_buffer_sizes = None
2323
+ self.triangle_colliding_vertices_offsets = None
2324
+
2325
+ # this is need regardless of whether we record triangle contacting vertices
2326
+ self.triangle_colliding_vertices_min_dist = wp.array(shape=(model.tri_count,), dtype=float, device=self.device)
2206
2327
 
2207
2328
  # edge collision buffers
2208
2329
  self.edge_colliding_edges = wp.zeros(
2209
- shape=(model.edge_count * self.edge_collision_buffer_pre_alloc,), dtype=wp.int32, device=self.device
2330
+ shape=(2 * model.edge_count * self.edge_collision_buffer_pre_alloc,), dtype=wp.int32, device=self.device
2210
2331
  )
2211
2332
  self.edge_colliding_edges_count = wp.zeros(shape=(model.edge_count,), dtype=wp.int32, device=self.device)
2212
2333
  self.edge_colliding_edges_buffer_sizes = wp.full(
@@ -2248,10 +2369,12 @@ class TriMeshCollisionDetector:
2248
2369
  collision_info.vertex_colliding_triangles_count = self.vertex_colliding_triangles_count
2249
2370
  collision_info.vertex_colliding_triangles_min_dist = self.vertex_colliding_triangles_min_dist
2250
2371
 
2251
- collision_info.triangle_colliding_vertices = self.triangle_colliding_vertices
2252
- collision_info.triangle_colliding_vertices_offsets = self.triangle_colliding_vertices_offsets
2253
- collision_info.triangle_colliding_vertices_buffer_sizes = self.triangle_colliding_vertices_buffer_sizes
2254
- collision_info.triangle_colliding_vertices_count = self.triangle_colliding_vertices_count
2372
+ if self.record_triangle_contacting_vertices:
2373
+ collision_info.triangle_colliding_vertices = self.triangle_colliding_vertices
2374
+ collision_info.triangle_colliding_vertices_offsets = self.triangle_colliding_vertices_offsets
2375
+ collision_info.triangle_colliding_vertices_buffer_sizes = self.triangle_colliding_vertices_buffer_sizes
2376
+ collision_info.triangle_colliding_vertices_count = self.triangle_colliding_vertices_count
2377
+
2255
2378
  collision_info.triangle_colliding_vertices_min_dist = self.triangle_colliding_vertices_min_dist
2256
2379
 
2257
2380
  collision_info.edge_colliding_edges = self.edge_colliding_edges
@@ -2272,6 +2395,31 @@ class TriMeshCollisionDetector:
2272
2395
 
2273
2396
  offsets.assign(offsets_np)
2274
2397
 
2398
+ def rebuild(self, new_pos=None):
2399
+ if new_pos is not None:
2400
+ self.vertex_positions = new_pos
2401
+
2402
+ wp.launch(
2403
+ kernel=compute_tri_aabbs,
2404
+ inputs=[
2405
+ self.vertex_positions,
2406
+ self.model.tri_indices,
2407
+ ],
2408
+ outputs=[self.lower_bounds_tris, self.upper_bounds_tris],
2409
+ dim=self.model.tri_count,
2410
+ device=self.model.device,
2411
+ )
2412
+ self.bvh_tris = wp.Bvh(self.lower_bounds_tris, self.upper_bounds_tris)
2413
+
2414
+ wp.launch(
2415
+ kernel=compute_edge_aabbs,
2416
+ inputs=[self.vertex_positions, self.model.edge_indices],
2417
+ outputs=[self.lower_bounds_edges, self.upper_bounds_edges],
2418
+ dim=self.model.edge_count,
2419
+ device=self.model.device,
2420
+ )
2421
+ self.bvh_edges = wp.Bvh(self.lower_bounds_edges, self.upper_bounds_edges)
2422
+
2275
2423
  def refit(self, new_pos=None):
2276
2424
  if new_pos is not None:
2277
2425
  self.vertex_positions = new_pos
@@ -2298,46 +2446,72 @@ class TriMeshCollisionDetector:
2298
2446
  self.bvh_edges.refit()
2299
2447
 
2300
2448
  def vertex_triangle_collision_detection(self, query_radius):
2301
- wp.launch(
2302
- kernel=init_triangle_collision_data_kernel,
2303
- inputs=[
2304
- query_radius,
2305
- ],
2306
- outputs=[
2307
- self.triangle_colliding_vertices_count,
2308
- self.triangle_colliding_vertices_min_dist,
2309
- self.resize_flags,
2310
- ],
2311
- dim=self.model.tri_count,
2312
- device=self.model.device,
2313
- )
2449
+ self.vertex_colliding_triangles.fill_(-1)
2314
2450
 
2315
- wp.launch(
2316
- kernel=vertex_triangle_collision_detection_kernel,
2317
- inputs=[
2318
- query_radius,
2319
- self.bvh_tris.id,
2320
- self.vertex_positions,
2321
- self.model.tri_indices,
2322
- self.vertex_colliding_triangles_offsets,
2323
- self.vertex_colliding_triangles_buffer_sizes,
2324
- self.triangle_colliding_vertices_offsets,
2325
- self.triangle_colliding_vertices_buffer_sizes,
2326
- ],
2327
- outputs=[
2328
- self.vertex_colliding_triangles,
2329
- self.vertex_colliding_triangles_count,
2330
- self.vertex_colliding_triangles_min_dist,
2331
- self.triangle_colliding_vertices,
2332
- self.triangle_colliding_vertices_count,
2333
- self.triangle_colliding_vertices_min_dist,
2334
- self.resize_flags,
2335
- ],
2336
- dim=self.model.particle_count,
2337
- device=self.model.device,
2338
- )
2451
+ if self.record_triangle_contacting_vertices:
2452
+ wp.launch(
2453
+ kernel=init_triangle_collision_data_kernel,
2454
+ inputs=[
2455
+ query_radius,
2456
+ ],
2457
+ outputs=[
2458
+ self.triangle_colliding_vertices_count,
2459
+ self.triangle_colliding_vertices_min_dist,
2460
+ self.resize_flags,
2461
+ ],
2462
+ dim=self.model.tri_count,
2463
+ device=self.model.device,
2464
+ )
2465
+
2466
+ wp.launch(
2467
+ kernel=vertex_triangle_collision_detection_kernel,
2468
+ inputs=[
2469
+ query_radius,
2470
+ self.bvh_tris.id,
2471
+ self.vertex_positions,
2472
+ self.model.tri_indices,
2473
+ self.vertex_colliding_triangles_offsets,
2474
+ self.vertex_colliding_triangles_buffer_sizes,
2475
+ self.triangle_colliding_vertices_offsets,
2476
+ self.triangle_colliding_vertices_buffer_sizes,
2477
+ ],
2478
+ outputs=[
2479
+ self.vertex_colliding_triangles,
2480
+ self.vertex_colliding_triangles_count,
2481
+ self.vertex_colliding_triangles_min_dist,
2482
+ self.triangle_colliding_vertices,
2483
+ self.triangle_colliding_vertices_count,
2484
+ self.triangle_colliding_vertices_min_dist,
2485
+ self.resize_flags,
2486
+ ],
2487
+ dim=self.model.particle_count,
2488
+ device=self.model.device,
2489
+ )
2490
+ else:
2491
+ self.triangle_colliding_vertices_min_dist.fill_(query_radius)
2492
+ wp.launch(
2493
+ kernel=vertex_triangle_collision_detection_no_triangle_buffers_kernel,
2494
+ inputs=[
2495
+ query_radius,
2496
+ self.bvh_tris.id,
2497
+ self.vertex_positions,
2498
+ self.model.tri_indices,
2499
+ self.vertex_colliding_triangles_offsets,
2500
+ self.vertex_colliding_triangles_buffer_sizes,
2501
+ ],
2502
+ outputs=[
2503
+ self.vertex_colliding_triangles,
2504
+ self.vertex_colliding_triangles_count,
2505
+ self.vertex_colliding_triangles_min_dist,
2506
+ self.triangle_colliding_vertices_min_dist,
2507
+ self.resize_flags,
2508
+ ],
2509
+ dim=self.model.particle_count,
2510
+ device=self.model.device,
2511
+ )
2339
2512
 
2340
2513
  def edge_edge_collision_detection(self, query_radius):
2514
+ self.edge_colliding_edges.fill_(-1)
2341
2515
  wp.launch(
2342
2516
  kernel=edge_colliding_edges_detection_kernel,
2343
2517
  inputs=[
@@ -178,6 +178,13 @@ def color_trimesh(
178
178
  algorithm: the parameter passed to `color_graph`, see `color_graph`'s document
179
179
 
180
180
  """
181
+ if num_nodes == 0:
182
+ return []
183
+
184
+ if trimesh_edge_indices.shape[0] == 0:
185
+ # no edge, all the particle can have same color
186
+ return [np.arange(0, num_nodes, dtype=int)]
187
+
181
188
  if include_bending_energy:
182
189
  graph_edge_indices = construct_trimesh_graph_edges(trimesh_edge_indices, return_wp_array=True)
183
190
  else:
@@ -218,7 +225,7 @@ def color_graph(
218
225
  Ordered Greedy: Ton-That, Q. M., Kry, P. G., & Andrews, S. (2023). Parallel block Neo-Hookean XPBD using graph clustering. Computers & Graphics, 110, 1-10.
219
226
  """
220
227
  if num_nodes == 0:
221
- return
228
+ return []
222
229
 
223
230
  particle_colors = wp.empty(shape=(num_nodes), dtype=wp.int32, device="cpu")
224
231
 
warp/sim/import_mjcf.py CHANGED
@@ -13,11 +13,12 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from __future__ import annotations
17
+
16
18
  import math
17
19
  import os
18
20
  import re
19
21
  import xml.etree.ElementTree as ET
20
- from typing import Union
21
22
 
22
23
  import numpy as np
23
24
 
@@ -30,7 +31,7 @@ def parse_mjcf(
30
31
  builder,
31
32
  xform=None,
32
33
  floating=False,
33
- base_joint: Union[dict, str, None] = None,
34
+ base_joint: dict | str | None = None,
34
35
  density=1000.0,
35
36
  stiffness=100.0,
36
37
  damping=10.0,
@@ -447,7 +448,7 @@ def parse_mjcf(
447
448
 
448
449
  return shapes
449
450
 
450
- def parse_body(body, parent, incoming_defaults: dict, childclass: str = None):
451
+ def parse_body(body, parent, incoming_defaults: dict, childclass: str | None = None):
451
452
  body_class = body.get("class")
452
453
  if body_class is None:
453
454
  body_class = childclass
warp/sim/import_usd.py CHANGED
@@ -13,6 +13,8 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from __future__ import annotations
17
+
16
18
  import re
17
19
 
18
20
  import numpy as np
@@ -810,17 +812,19 @@ def parse_usd(
810
812
  }
811
813
 
812
814
 
813
- def resolve_usd_from_url(url: str, target_folder_name: str = None, export_usda: bool = False):
814
- """
815
- Downloads a USD file from a URL and resolves all references to other USD files to be downloaded to the given target folder.
815
+ def resolve_usd_from_url(url: str, target_folder_name: str | None = None, export_usda: bool = False) -> str:
816
+ """Download a USD file from a URL and resolves all references to other USD files to be downloaded to the given target folder.
816
817
 
817
818
  Args:
818
- url (str): URL to the USD file.
819
- target_folder_name (str): Target folder name. If None, a timestamped folder will be created in the current directory.
820
- export_usda (bool): If True, converts each downloaded USD file to USDA and saves the additional USDA file in the target folder with the same base name as the original USD file.
819
+ url: URL to the USD file.
820
+ target_folder_name: Target folder name. If ``None``, a time-stamped
821
+ folder will be created in the current directory.
822
+ export_usda: If ``True``, converts each downloaded USD file to USDA and
823
+ saves the additional USDA file in the target folder with the same
824
+ base name as the original USD file.
821
825
 
822
826
  Returns:
823
- str: File path to the downloaded USD file.
827
+ File path to the downloaded USD file.
824
828
  """
825
829
  import datetime
826
830
  import os
warp/sim/integrator.py CHANGED
@@ -32,11 +32,14 @@ def integrate_particles(
32
32
  v_new: wp.array(dtype=wp.vec3),
33
33
  ):
34
34
  tid = wp.tid()
35
+ x0 = x[tid]
36
+ v0 = v[tid]
37
+
35
38
  if (particle_flags[tid] & PARTICLE_FLAG_ACTIVE) == 0:
39
+ x_new[tid] = x0
40
+ v_new[tid] = wp.vec3(0.0)
36
41
  return
37
42
 
38
- x0 = x[tid]
39
- v0 = v[tid]
40
43
  f0 = f[tid]
41
44
 
42
45
  inv_mass = w[tid]
@@ -1781,7 +1781,7 @@ def eval_tetrahedral_forces(model: Model, state: State, control: Control, partic
1781
1781
 
1782
1782
  def eval_body_contact_forces(model: Model, state: State, particle_f: wp.array, friction_smoothing: float = 1.0):
1783
1783
  if model.rigid_contact_max and (
1784
- model.ground and model.shape_ground_contact_pair_count or model.shape_contact_pair_count
1784
+ (model.ground and model.shape_ground_contact_pair_count) or model.shape_contact_pair_count
1785
1785
  ):
1786
1786
  wp.launch(
1787
1787
  kernel=eval_rigid_contacts,
@@ -1825,7 +1825,7 @@ class FeatherstoneIntegrator(Integrator):
1825
1825
  )
1826
1826
 
1827
1827
  if model.rigid_contact_max and (
1828
- model.ground and model.shape_ground_contact_pair_count or model.shape_contact_pair_count
1828
+ (model.ground and model.shape_ground_contact_pair_count) or model.shape_contact_pair_count
1829
1829
  ):
1830
1830
  wp.launch(
1831
1831
  kernel=eval_rigid_contacts,