warp-lang 1.7.2rc1__py3-none-win_amd64.whl → 1.8.1__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 (193) 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 +130 -26
  8. warp/builtins.py +1907 -384
  9. warp/codegen.py +272 -104
  10. warp/config.py +12 -1
  11. warp/constants.py +1 -1
  12. warp/context.py +770 -238
  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_callable.py +34 -4
  36. warp/examples/interop/example_jax_ffi_callback.py +2 -2
  37. warp/examples/interop/example_jax_kernel.py +27 -1
  38. warp/examples/optim/example_drone.py +1 -1
  39. warp/examples/sim/example_cloth.py +1 -1
  40. warp/examples/sim/example_cloth_self_contact.py +48 -54
  41. warp/examples/tile/example_tile_block_cholesky.py +502 -0
  42. warp/examples/tile/example_tile_cholesky.py +2 -1
  43. warp/examples/tile/example_tile_convolution.py +1 -1
  44. warp/examples/tile/example_tile_filtering.py +1 -1
  45. warp/examples/tile/example_tile_matmul.py +1 -1
  46. warp/examples/tile/example_tile_mlp.py +2 -0
  47. warp/fabric.py +7 -7
  48. warp/fem/__init__.py +5 -0
  49. warp/fem/adaptivity.py +1 -1
  50. warp/fem/cache.py +152 -63
  51. warp/fem/dirichlet.py +2 -2
  52. warp/fem/domain.py +136 -6
  53. warp/fem/field/field.py +141 -99
  54. warp/fem/field/nodal_field.py +85 -39
  55. warp/fem/field/virtual.py +99 -52
  56. warp/fem/geometry/adaptive_nanogrid.py +91 -86
  57. warp/fem/geometry/closest_point.py +13 -0
  58. warp/fem/geometry/deformed_geometry.py +102 -40
  59. warp/fem/geometry/element.py +56 -2
  60. warp/fem/geometry/geometry.py +323 -22
  61. warp/fem/geometry/grid_2d.py +157 -62
  62. warp/fem/geometry/grid_3d.py +116 -20
  63. warp/fem/geometry/hexmesh.py +86 -20
  64. warp/fem/geometry/nanogrid.py +166 -86
  65. warp/fem/geometry/partition.py +59 -25
  66. warp/fem/geometry/quadmesh.py +86 -135
  67. warp/fem/geometry/tetmesh.py +47 -119
  68. warp/fem/geometry/trimesh.py +77 -270
  69. warp/fem/integrate.py +181 -95
  70. warp/fem/linalg.py +25 -58
  71. warp/fem/operator.py +124 -27
  72. warp/fem/quadrature/pic_quadrature.py +36 -14
  73. warp/fem/quadrature/quadrature.py +40 -16
  74. warp/fem/space/__init__.py +1 -1
  75. warp/fem/space/basis_function_space.py +66 -46
  76. warp/fem/space/basis_space.py +17 -4
  77. warp/fem/space/dof_mapper.py +1 -1
  78. warp/fem/space/function_space.py +2 -2
  79. warp/fem/space/grid_2d_function_space.py +4 -1
  80. warp/fem/space/hexmesh_function_space.py +4 -2
  81. warp/fem/space/nanogrid_function_space.py +3 -1
  82. warp/fem/space/partition.py +11 -2
  83. warp/fem/space/quadmesh_function_space.py +4 -1
  84. warp/fem/space/restriction.py +5 -2
  85. warp/fem/space/shape/__init__.py +10 -8
  86. warp/fem/space/tetmesh_function_space.py +4 -1
  87. warp/fem/space/topology.py +52 -21
  88. warp/fem/space/trimesh_function_space.py +4 -1
  89. warp/fem/utils.py +53 -8
  90. warp/jax.py +1 -2
  91. warp/jax_experimental/ffi.py +210 -67
  92. warp/jax_experimental/xla_ffi.py +37 -24
  93. warp/math.py +171 -1
  94. warp/native/array.h +103 -4
  95. warp/native/builtin.h +182 -35
  96. warp/native/coloring.cpp +6 -2
  97. warp/native/cuda_util.cpp +1 -1
  98. warp/native/exports.h +118 -63
  99. warp/native/intersect.h +5 -5
  100. warp/native/mat.h +8 -13
  101. warp/native/mathdx.cpp +11 -5
  102. warp/native/matnn.h +1 -123
  103. warp/native/mesh.h +1 -1
  104. warp/native/quat.h +34 -6
  105. warp/native/rand.h +7 -7
  106. warp/native/sparse.cpp +121 -258
  107. warp/native/sparse.cu +181 -274
  108. warp/native/spatial.h +305 -17
  109. warp/native/svd.h +23 -8
  110. warp/native/tile.h +603 -73
  111. warp/native/tile_radix_sort.h +1112 -0
  112. warp/native/tile_reduce.h +239 -13
  113. warp/native/tile_scan.h +240 -0
  114. warp/native/tuple.h +189 -0
  115. warp/native/vec.h +10 -20
  116. warp/native/warp.cpp +36 -4
  117. warp/native/warp.cu +588 -52
  118. warp/native/warp.h +47 -74
  119. warp/optim/linear.py +5 -1
  120. warp/paddle.py +7 -8
  121. warp/py.typed +0 -0
  122. warp/render/render_opengl.py +110 -80
  123. warp/render/render_usd.py +124 -62
  124. warp/sim/__init__.py +9 -0
  125. warp/sim/collide.py +253 -80
  126. warp/sim/graph_coloring.py +8 -1
  127. warp/sim/import_mjcf.py +4 -3
  128. warp/sim/import_usd.py +11 -7
  129. warp/sim/integrator.py +5 -2
  130. warp/sim/integrator_euler.py +1 -1
  131. warp/sim/integrator_featherstone.py +1 -1
  132. warp/sim/integrator_vbd.py +761 -322
  133. warp/sim/integrator_xpbd.py +1 -1
  134. warp/sim/model.py +265 -260
  135. warp/sim/utils.py +10 -7
  136. warp/sparse.py +303 -166
  137. warp/tape.py +54 -51
  138. warp/tests/cuda/test_conditional_captures.py +1046 -0
  139. warp/tests/cuda/test_streams.py +1 -1
  140. warp/tests/geometry/test_volume.py +2 -2
  141. warp/tests/interop/test_dlpack.py +9 -9
  142. warp/tests/interop/test_jax.py +0 -1
  143. warp/tests/run_coverage_serial.py +1 -1
  144. warp/tests/sim/disabled_kinematics.py +2 -2
  145. warp/tests/sim/{test_vbd.py → test_cloth.py} +378 -112
  146. warp/tests/sim/test_collision.py +159 -51
  147. warp/tests/sim/test_coloring.py +91 -2
  148. warp/tests/test_array.py +254 -2
  149. warp/tests/test_array_reduce.py +2 -2
  150. warp/tests/test_assert.py +53 -0
  151. warp/tests/test_atomic_cas.py +312 -0
  152. warp/tests/test_codegen.py +142 -19
  153. warp/tests/test_conditional.py +47 -1
  154. warp/tests/test_ctypes.py +0 -20
  155. warp/tests/test_devices.py +8 -0
  156. warp/tests/test_fabricarray.py +4 -2
  157. warp/tests/test_fem.py +58 -25
  158. warp/tests/test_func.py +42 -1
  159. warp/tests/test_grad.py +1 -1
  160. warp/tests/test_lerp.py +1 -3
  161. warp/tests/test_map.py +481 -0
  162. warp/tests/test_mat.py +23 -24
  163. warp/tests/test_quat.py +28 -15
  164. warp/tests/test_rounding.py +10 -38
  165. warp/tests/test_runlength_encode.py +7 -7
  166. warp/tests/test_smoothstep.py +1 -1
  167. warp/tests/test_sparse.py +83 -2
  168. warp/tests/test_spatial.py +507 -1
  169. warp/tests/test_static.py +48 -0
  170. warp/tests/test_struct.py +2 -2
  171. warp/tests/test_tape.py +38 -0
  172. warp/tests/test_tuple.py +265 -0
  173. warp/tests/test_types.py +2 -2
  174. warp/tests/test_utils.py +24 -18
  175. warp/tests/test_vec.py +38 -408
  176. warp/tests/test_vec_constructors.py +325 -0
  177. warp/tests/tile/test_tile.py +438 -131
  178. warp/tests/tile/test_tile_mathdx.py +518 -14
  179. warp/tests/tile/test_tile_matmul.py +179 -0
  180. warp/tests/tile/test_tile_reduce.py +307 -5
  181. warp/tests/tile/test_tile_shared_memory.py +136 -7
  182. warp/tests/tile/test_tile_sort.py +121 -0
  183. warp/tests/unittest_suites.py +14 -6
  184. warp/types.py +462 -308
  185. warp/utils.py +647 -86
  186. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/METADATA +20 -6
  187. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/RECORD +190 -176
  188. warp/stubs.py +0 -3381
  189. warp/tests/sim/test_xpbd.py +0 -399
  190. warp/tests/test_mlp.py +0 -282
  191. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/WHEEL +0 -0
  192. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/licenses/LICENSE.md +0 -0
  193. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,6 @@
12
12
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
-
16
15
  import numpy as np
17
16
 
18
17
  import warp as wp
@@ -21,22 +20,16 @@ from ..types import float32, matrix
21
20
  from .collide import (
22
21
  TriMeshCollisionDetector,
23
22
  TriMeshCollisionInfo,
24
- get_edge_colliding_edges,
25
- get_edge_colliding_edges_count,
26
- get_triangle_colliding_vertices,
27
- get_triangle_colliding_vertices_count,
28
- get_vertex_colliding_triangles,
29
- get_vertex_colliding_triangles_count,
30
23
  triangle_closest_point,
31
24
  )
32
25
  from .integrator import Integrator
33
26
  from .model import PARTICLE_FLAG_ACTIVE, Control, Model, ModelShapeMaterials, State
34
27
 
35
- wp.set_module_options({"enable_backward": False})
36
-
37
28
  VBD_DEBUG_PRINTING_OPTIONS = {
38
29
  # "elasticity_force_hessian",
39
30
  # "contact_force_hessian",
31
+ # "contact_force_hessian_vt",
32
+ # "contact_force_hessian_ee",
40
33
  # "overall_force_hessian",
41
34
  # "inertia_force_hessian",
42
35
  # "connectivity",
@@ -52,15 +45,19 @@ class mat32(matrix(shape=(3, 2), dtype=float32)):
52
45
  pass
53
46
 
54
47
 
48
+ class mat43(matrix(shape=(4, 3), dtype=float32)):
49
+ pass
50
+
51
+
55
52
  @wp.struct
56
53
  class ForceElementAdjacencyInfo:
57
54
  r"""
58
55
  - vertex_adjacent_[element]: the flatten adjacency information. Its size is \sum_{i\inV} 2*N_i, where N_i is the
59
- number of vertex is adjacent [element]. For each adjacent element it stores 2 information:
56
+ number of vertex i's adjacent [element]. For each adjacent element it stores 2 information:
60
57
  - the id of the adjacent element
61
58
  - the order of the vertex in the element, which is essential to compute the force and hessian for the vertex
62
- - vertex_adjacent_[element]_offsets: stores where each vertex information starts in the flatten adjacency array.
63
- Its size is |V|+1 such that the number of vertex is adjacent [element] can be computed as
59
+ - vertex_adjacent_[element]_offsets: stores where each vertex information starts in the flatten adjacency array.
60
+ Its size is |V|+1 such that the number of vertex i's adjacent [element] can be computed as
64
61
  vertex_adjacent_[element]_offsets[i+1]-vertex_adjacent_[element]_offsets[i].
65
62
  """
66
63
 
@@ -520,6 +517,7 @@ def evaluate_ground_contact_force_hessian(
520
517
  ground_normal: wp.vec3,
521
518
  ground_level: float,
522
519
  soft_contact_ke: float,
520
+ soft_contact_kd: float,
523
521
  friction_mu: float,
524
522
  friction_epsilon: float,
525
523
  dt: float,
@@ -533,6 +531,11 @@ def evaluate_ground_contact_force_hessian(
533
531
 
534
532
  dx = particle_pos - particle_prev_pos
535
533
 
534
+ if wp.dot(dx, ground_normal) < 0:
535
+ damping_hessian = (soft_contact_kd / dt) * ground_contact_hessian
536
+ ground_contact_hessian = ground_contact_hessian + damping_hessian
537
+ ground_contact_force = ground_contact_force - damping_hessian * dx
538
+
536
539
  # friction
537
540
  e0, e1 = build_orthonormal_basis(ground_normal)
538
541
 
@@ -559,6 +562,7 @@ def evaluate_body_particle_contact(
559
562
  particle_prev_pos: wp.vec3,
560
563
  contact_index: int,
561
564
  soft_contact_ke: float,
565
+ soft_contact_kd: float,
562
566
  friction_mu: float,
563
567
  friction_epsilon: float,
564
568
  particle_radius: wp.array(dtype=float),
@@ -594,10 +598,15 @@ def evaluate_body_particle_contact(
594
598
  body_contact_force = n * body_contact_force_norm
595
599
  body_contact_hessian = soft_contact_ke * wp.outer(n, n)
596
600
 
597
- mu = 0.5 * (friction_mu + shape_materials.mu[shape_index])
601
+ mu = shape_materials.mu[shape_index]
598
602
 
599
603
  dx = particle_pos - particle_prev_pos
600
604
 
605
+ if wp.dot(n, dx) < 0:
606
+ damping_hessian = (soft_contact_kd / dt) * body_contact_hessian
607
+ body_contact_hessian = body_contact_hessian + damping_hessian
608
+ body_contact_force = body_contact_force - damping_hessian * dx
609
+
601
610
  # body velocity
602
611
  body_v_s = wp.spatial_vector()
603
612
  if body_index >= 0:
@@ -652,6 +661,22 @@ def evaluate_self_contact_force_norm(dis: float, collision_radius: float, k: flo
652
661
  return dEdD, d2E_dDdD
653
662
 
654
663
 
664
+ @wp.func
665
+ def damp_collision(
666
+ displacement: wp.vec3,
667
+ collision_normal: wp.vec3,
668
+ collision_hessian: wp.mat33,
669
+ collision_damping: float,
670
+ dt: float,
671
+ ):
672
+ if wp.dot(displacement, collision_normal) > 0:
673
+ damping_hessian = (collision_damping / dt) * collision_hessian
674
+ damping_force = damping_hessian * displacement
675
+ return damping_force, damping_hessian
676
+ else:
677
+ return wp.vec3(0.0), wp.mat33(0.0)
678
+
679
+
655
680
  @wp.func
656
681
  def evaluate_edge_edge_contact(
657
682
  v: int,
@@ -663,6 +688,7 @@ def evaluate_edge_edge_contact(
663
688
  edge_indices: wp.array(dtype=wp.int32, ndim=2),
664
689
  collision_radius: float,
665
690
  collision_stiffness: float,
691
+ collision_damping: float,
666
692
  friction_coefficient: float,
667
693
  friction_epsilon: float,
668
694
  dt: float,
@@ -676,10 +702,12 @@ def evaluate_edge_edge_contact(
676
702
  e0
677
703
  e1
678
704
  pos
705
+ pos_prev,
679
706
  edge_indices
680
707
  collision_radius
681
708
  collision_stiffness
682
709
  dt
710
+ edge_edge_parallel_epsilon: threshold to determine whether 2 edges are parallel
683
711
  """
684
712
  e1_v1 = edge_indices[e1, 2]
685
713
  e1_v2 = edge_indices[e1, 3]
@@ -721,15 +749,14 @@ def evaluate_edge_edge_contact(
721
749
  c2_prev = pos_prev[e2_v1] + (pos_prev[e2_v2] - pos_prev[e2_v1]) * t
722
750
 
723
751
  dx = (c1 - c1_prev) - (c2 - c2_prev)
724
- e1_vec_normalized = wp.normalize(e1_vec)
725
- axis_2 = wp.normalize(wp.cross(e1_vec_normalized, collision_normal))
752
+ axis_1, axis_2 = build_orthonormal_basis(collision_normal)
726
753
 
727
754
  T = mat32(
728
- e1_vec_normalized[0],
755
+ axis_1[0],
729
756
  axis_2[0],
730
- e1_vec_normalized[1],
757
+ axis_1[1],
731
758
  axis_2[1],
732
- e1_vec_normalized[2],
759
+ axis_1[2],
733
760
  axis_2[2],
734
761
  )
735
762
 
@@ -737,7 +764,7 @@ def evaluate_edge_edge_contact(
737
764
  eps_U = friction_epsilon * dt
738
765
 
739
766
  # fmt: off
740
- if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
767
+ if wp.static("contact_force_hessian_ee" in VBD_DEBUG_PRINTING_OPTIONS):
741
768
  wp.printf(
742
769
  " collision force:\n %f %f %f,\n collision hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
743
770
  collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
@@ -748,21 +775,174 @@ def evaluate_edge_edge_contact(
748
775
  friction_force = friction_force * v_bary
749
776
  friction_hessian = friction_hessian * v_bary * v_bary
750
777
 
778
+ # # fmt: off
779
+ # if wp.static("contact_force_hessian_ee" in VBD_DEBUG_PRINTING_OPTIONS):
780
+ # wp.printf(
781
+ # " friction force:\n %f %f %f,\n friction hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
782
+ # friction_force[0], friction_force[1], friction_force[2], friction_hessian[0, 0], friction_hessian[0, 1], friction_hessian[0, 2], friction_hessian[1, 0], friction_hessian[1, 1], friction_hessian[1, 2], friction_hessian[2, 0], friction_hessian[2, 1], friction_hessian[2, 2],
783
+ # )
784
+ # # fmt: on
785
+
786
+ if v_order == 0:
787
+ displacement = pos_prev[e1_v1] - e1_v1_pos
788
+ elif v_order == 1:
789
+ displacement = pos_prev[e1_v2] - e1_v2_pos
790
+ elif v_order == 2:
791
+ displacement = pos_prev[e2_v1] - e2_v1_pos
792
+ else:
793
+ displacement = pos_prev[e2_v2] - e2_v2_pos
794
+
795
+ collision_normal_normal_sign = wp.vec4(1.0, 1.0, -1.0, -1.0)
796
+ if wp.dot(displacement, collision_normal * collision_normal_normal_sign[v_order]) > 0:
797
+ damping_hessian = (collision_damping / dt) * collision_hessian
798
+ collision_hessian = collision_hessian + damping_hessian
799
+ collision_force = collision_force + damping_hessian * displacement
800
+
801
+ collision_force = collision_force + friction_force
802
+ collision_hessian = collision_hessian + friction_hessian
803
+ else:
804
+ collision_force = wp.vec3(0.0, 0.0, 0.0)
805
+ collision_hessian = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
806
+
807
+ return collision_force, collision_hessian
808
+
809
+
810
+ @wp.func
811
+ def evaluate_edge_edge_contact_2_vertices(
812
+ e1: int,
813
+ e2: int,
814
+ pos: wp.array(dtype=wp.vec3),
815
+ pos_prev: wp.array(dtype=wp.vec3),
816
+ edge_indices: wp.array(dtype=wp.int32, ndim=2),
817
+ collision_radius: float,
818
+ collision_stiffness: float,
819
+ collision_damping: float,
820
+ friction_coefficient: float,
821
+ friction_epsilon: float,
822
+ dt: float,
823
+ edge_edge_parallel_epsilon: float,
824
+ ):
825
+ r"""
826
+ Returns the edge-edge contact force and hessian, including the friction force.
827
+ Args:
828
+ v:
829
+ v_order: \in {0, 1, 2, 3}, 0, 1 is vertex 0, 1 of e1, 2,3 is vertex 0, 1 of e2
830
+ e0
831
+ e1
832
+ pos
833
+ edge_indices
834
+ collision_radius
835
+ collision_stiffness
836
+ dt
837
+ """
838
+ e1_v1 = edge_indices[e1, 2]
839
+ e1_v2 = edge_indices[e1, 3]
840
+
841
+ e1_v1_pos = pos[e1_v1]
842
+ e1_v2_pos = pos[e1_v2]
843
+
844
+ e2_v1 = edge_indices[e2, 2]
845
+ e2_v2 = edge_indices[e2, 3]
846
+
847
+ e2_v1_pos = pos[e2_v1]
848
+ e2_v2_pos = pos[e2_v2]
849
+
850
+ st = wp.closest_point_edge_edge(e1_v1_pos, e1_v2_pos, e2_v1_pos, e2_v2_pos, edge_edge_parallel_epsilon)
851
+ s = st[0]
852
+ t = st[1]
853
+ e1_vec = e1_v2_pos - e1_v1_pos
854
+ e2_vec = e2_v2_pos - e2_v1_pos
855
+ c1 = e1_v1_pos + e1_vec * s
856
+ c2 = e2_v1_pos + e2_vec * t
857
+
858
+ # c1, c2, s, t = closest_point_edge_edge_2(e1_v1_pos, e1_v2_pos, e2_v1_pos, e2_v2_pos)
859
+
860
+ diff = c1 - c2
861
+ dis = st[2]
862
+ collision_normal = diff / dis
863
+
864
+ if dis < collision_radius:
865
+ bs = wp.vec4(1.0 - s, s, -1.0 + t, -t)
866
+
867
+ dEdD, d2E_dDdD = evaluate_self_contact_force_norm(dis, collision_radius, collision_stiffness)
868
+
869
+ collision_force = -dEdD * collision_normal
870
+ collision_hessian = d2E_dDdD * wp.outer(collision_normal, collision_normal)
871
+
872
+ # friction
873
+ c1_prev = pos_prev[e1_v1] + (pos_prev[e1_v2] - pos_prev[e1_v1]) * s
874
+ c2_prev = pos_prev[e2_v1] + (pos_prev[e2_v2] - pos_prev[e2_v1]) * t
875
+
876
+ dx = (c1 - c1_prev) - (c2 - c2_prev)
877
+ axis_1, axis_2 = build_orthonormal_basis(collision_normal)
878
+
879
+ T = mat32(
880
+ axis_1[0],
881
+ axis_2[0],
882
+ axis_1[1],
883
+ axis_2[1],
884
+ axis_1[2],
885
+ axis_2[2],
886
+ )
887
+
888
+ u = wp.transpose(T) * dx
889
+ eps_U = friction_epsilon * dt
890
+
751
891
  # fmt: off
752
- if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
892
+ if wp.static("contact_force_hessian_ee" in VBD_DEBUG_PRINTING_OPTIONS):
753
893
  wp.printf(
754
- " friction force:\n %f %f %f,\n friction hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
755
- friction_force[0], friction_force[1], friction_force[2], friction_hessian[0, 0], friction_hessian[0, 1], friction_hessian[0, 2], friction_hessian[1, 0], friction_hessian[1, 1], friction_hessian[1, 2], friction_hessian[2, 0], friction_hessian[2, 1], friction_hessian[2, 2],
894
+ " collision force:\n %f %f %f,\n collision hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
895
+ collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
756
896
  )
757
897
  # fmt: on
758
898
 
759
- collision_force = collision_force + friction_force
760
- collision_hessian = collision_hessian + friction_hessian
899
+ friction_force, friction_hessian = compute_friction(friction_coefficient, -dEdD, T, u, eps_U)
900
+
901
+ # # fmt: off
902
+ # if wp.static("contact_force_hessian_ee" in VBD_DEBUG_PRINTING_OPTIONS):
903
+ # wp.printf(
904
+ # " friction force:\n %f %f %f,\n friction hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
905
+ # friction_force[0], friction_force[1], friction_force[2], friction_hessian[0, 0], friction_hessian[0, 1], friction_hessian[0, 2], friction_hessian[1, 0], friction_hessian[1, 1], friction_hessian[1, 2], friction_hessian[2, 0], friction_hessian[2, 1], friction_hessian[2, 2],
906
+ # )
907
+ # # fmt: on
908
+
909
+ displacement_0 = pos_prev[e1_v1] - e1_v1_pos
910
+ displacement_1 = pos_prev[e1_v2] - e1_v2_pos
911
+
912
+ collision_force_0 = collision_force * bs[0]
913
+ collision_force_1 = collision_force * bs[1]
914
+
915
+ collision_hessian_0 = collision_hessian * bs[0] * bs[0]
916
+ collision_hessian_1 = collision_hessian * bs[1] * bs[1]
917
+
918
+ collision_normal_normal_sign = wp.vec4(1.0, 1.0, -1.0, -1.0)
919
+ damping_force, damping_hessian = damp_collision(
920
+ displacement_0,
921
+ collision_normal * collision_normal_normal_sign[0],
922
+ collision_hessian_0,
923
+ collision_damping,
924
+ dt,
925
+ )
926
+
927
+ collision_force_0 += damping_force + bs[0] * friction_force
928
+ collision_hessian_0 += damping_hessian + bs[0] * bs[0] * friction_hessian
929
+
930
+ damping_force, damping_hessian = damp_collision(
931
+ displacement_1,
932
+ collision_normal * collision_normal_normal_sign[1],
933
+ collision_hessian_1,
934
+ collision_damping,
935
+ dt,
936
+ )
937
+ collision_force_1 += damping_force + bs[1] * friction_force
938
+ collision_hessian_1 += damping_hessian + bs[1] * bs[1] * friction_hessian
939
+
940
+ return True, collision_force_0, collision_force_1, collision_hessian_0, collision_hessian_1
761
941
  else:
762
942
  collision_force = wp.vec3(0.0, 0.0, 0.0)
763
943
  collision_hessian = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
764
944
 
765
- return collision_force, collision_hessian
945
+ return False, collision_force, collision_force, collision_hessian, collision_hessian
766
946
 
767
947
 
768
948
  @wp.func
@@ -775,6 +955,7 @@ def evaluate_vertex_triangle_collision_force_hessian(
775
955
  tri_indices: wp.array(dtype=wp.int32, ndim=2),
776
956
  collision_radius: float,
777
957
  collision_stiffness: float,
958
+ collision_damping: float,
778
959
  friction_coefficient: float,
779
960
  friction_epsilon: float,
780
961
  dt: float,
@@ -811,8 +992,7 @@ def evaluate_vertex_triangle_collision_force_hessian(
811
992
 
812
993
  dx = dx_v - (closest_p - closest_p_prev)
813
994
 
814
- e0 = wp.normalize(b - a)
815
- e1 = wp.normalize(wp.cross(e0, collision_normal))
995
+ e0, e1 = build_orthonormal_basis(collision_normal)
816
996
 
817
997
  T = mat32(e0[0], e1[0], e0[1], e1[1], e0[2], e1[2])
818
998
 
@@ -822,7 +1002,7 @@ def evaluate_vertex_triangle_collision_force_hessian(
822
1002
  friction_force, friction_hessian = compute_friction(friction_coefficient, -dEdD, T, u, eps_U)
823
1003
 
824
1004
  # fmt: off
825
- if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
1005
+ if wp.static("contact_force_hessian_vt" in VBD_DEBUG_PRINTING_OPTIONS):
826
1006
  wp.printf(
827
1007
  "v: %d dEdD: %f\nnormal force: %f %f %f\nfriction force: %f %f %f\n",
828
1008
  v,
@@ -831,6 +1011,21 @@ def evaluate_vertex_triangle_collision_force_hessian(
831
1011
  )
832
1012
  # fmt: on
833
1013
 
1014
+ if v_order == 0:
1015
+ displacement = pos_prev[tri_indices[tri, 0]] - a
1016
+ elif v_order == 1:
1017
+ displacement = pos_prev[tri_indices[tri, 1]] - b
1018
+ elif v_order == 2:
1019
+ displacement = pos_prev[tri_indices[tri, 2]] - c
1020
+ else:
1021
+ displacement = pos_prev[v] - p
1022
+
1023
+ collision_normal_normal_sign = wp.vec4(-1.0, -1.0, -1.0, 1.0)
1024
+ if wp.dot(displacement, collision_normal * collision_normal_normal_sign[v_order]) > 0:
1025
+ damping_hessian = (collision_damping / dt) * collision_hessian
1026
+ collision_hessian = collision_hessian + damping_hessian
1027
+ collision_force = collision_force + damping_hessian * displacement
1028
+
834
1029
  collision_force = collision_force + v_bary * friction_force
835
1030
  collision_hessian = collision_hessian + v_bary * v_bary * friction_hessian
836
1031
  else:
@@ -840,6 +1035,155 @@ def evaluate_vertex_triangle_collision_force_hessian(
840
1035
  return collision_force, collision_hessian
841
1036
 
842
1037
 
1038
+ @wp.func
1039
+ def evaluate_vertex_triangle_collision_force_hessian_4_vertices(
1040
+ v: int,
1041
+ tri: int,
1042
+ pos: wp.array(dtype=wp.vec3),
1043
+ pos_prev: wp.array(dtype=wp.vec3),
1044
+ tri_indices: wp.array(dtype=wp.int32, ndim=2),
1045
+ collision_radius: float,
1046
+ collision_stiffness: float,
1047
+ collision_damping: float,
1048
+ friction_coefficient: float,
1049
+ friction_epsilon: float,
1050
+ dt: float,
1051
+ ):
1052
+ a = pos[tri_indices[tri, 0]]
1053
+ b = pos[tri_indices[tri, 1]]
1054
+ c = pos[tri_indices[tri, 2]]
1055
+
1056
+ p = pos[v]
1057
+
1058
+ closest_p, bary, feature_type = triangle_closest_point(a, b, c, p)
1059
+
1060
+ diff = p - closest_p
1061
+ dis = wp.length(diff)
1062
+ collision_normal = diff / dis
1063
+
1064
+ if dis < collision_radius:
1065
+ bs = wp.vec4(-bary[0], -bary[1], -bary[2], 1.0)
1066
+
1067
+ dEdD, d2E_dDdD = evaluate_self_contact_force_norm(dis, collision_radius, collision_stiffness)
1068
+
1069
+ collision_force = -dEdD * collision_normal
1070
+ collision_hessian = d2E_dDdD * wp.outer(collision_normal, collision_normal)
1071
+
1072
+ # friction force
1073
+ dx_v = p - pos_prev[v]
1074
+
1075
+ closest_p_prev = (
1076
+ bary[0] * pos_prev[tri_indices[tri, 0]]
1077
+ + bary[1] * pos_prev[tri_indices[tri, 1]]
1078
+ + bary[2] * pos_prev[tri_indices[tri, 2]]
1079
+ )
1080
+
1081
+ dx = dx_v - (closest_p - closest_p_prev)
1082
+
1083
+ e0, e1 = build_orthonormal_basis(collision_normal)
1084
+
1085
+ T = mat32(e0[0], e1[0], e0[1], e1[1], e0[2], e1[2])
1086
+
1087
+ u = wp.transpose(T) * dx
1088
+ eps_U = friction_epsilon * dt
1089
+
1090
+ friction_force, friction_hessian = compute_friction(friction_coefficient, -dEdD, T, u, eps_U)
1091
+
1092
+ # fmt: off
1093
+ if wp.static("contact_force_hessian_vt" in VBD_DEBUG_PRINTING_OPTIONS):
1094
+ wp.printf(
1095
+ "v: %d dEdD: %f\nnormal force: %f %f %f\nfriction force: %f %f %f\n",
1096
+ v,
1097
+ dEdD,
1098
+ collision_force[0], collision_force[1], collision_force[2], friction_force[0], friction_force[1],
1099
+ friction_force[2],
1100
+ )
1101
+ # fmt: on
1102
+
1103
+ displacement_0 = pos_prev[tri_indices[tri, 0]] - a
1104
+ displacement_1 = pos_prev[tri_indices[tri, 1]] - b
1105
+ displacement_2 = pos_prev[tri_indices[tri, 2]] - c
1106
+ displacement_3 = pos_prev[v] - p
1107
+
1108
+ collision_force_0 = collision_force * bs[0]
1109
+ collision_force_1 = collision_force * bs[1]
1110
+ collision_force_2 = collision_force * bs[2]
1111
+ collision_force_3 = collision_force * bs[3]
1112
+
1113
+ collision_hessian_0 = collision_hessian * bs[0] * bs[0]
1114
+ collision_hessian_1 = collision_hessian * bs[1] * bs[1]
1115
+ collision_hessian_2 = collision_hessian * bs[2] * bs[2]
1116
+ collision_hessian_3 = collision_hessian * bs[3] * bs[3]
1117
+
1118
+ collision_normal_normal_sign = wp.vec4(-1.0, -1.0, -1.0, 1.0)
1119
+ damping_force, damping_hessian = damp_collision(
1120
+ displacement_0,
1121
+ collision_normal * collision_normal_normal_sign[0],
1122
+ collision_hessian_0,
1123
+ collision_damping,
1124
+ dt,
1125
+ )
1126
+
1127
+ collision_force_0 += damping_force + bs[0] * friction_force
1128
+ collision_hessian_0 += damping_hessian + bs[0] * bs[0] * friction_hessian
1129
+
1130
+ damping_force, damping_hessian = damp_collision(
1131
+ displacement_1,
1132
+ collision_normal * collision_normal_normal_sign[1],
1133
+ collision_hessian_1,
1134
+ collision_damping,
1135
+ dt,
1136
+ )
1137
+ collision_force_1 += damping_force + bs[1] * friction_force
1138
+ collision_hessian_1 += damping_hessian + bs[1] * bs[1] * friction_hessian
1139
+
1140
+ damping_force, damping_hessian = damp_collision(
1141
+ displacement_2,
1142
+ collision_normal * collision_normal_normal_sign[2],
1143
+ collision_hessian_2,
1144
+ collision_damping,
1145
+ dt,
1146
+ )
1147
+ collision_force_2 += damping_force + bs[2] * friction_force
1148
+ collision_hessian_2 += damping_hessian + bs[2] * bs[2] * friction_hessian
1149
+
1150
+ damping_force, damping_hessian = damp_collision(
1151
+ displacement_3,
1152
+ collision_normal * collision_normal_normal_sign[3],
1153
+ collision_hessian_3,
1154
+ collision_damping,
1155
+ dt,
1156
+ )
1157
+ collision_force_3 += damping_force + bs[3] * friction_force
1158
+ collision_hessian_3 += damping_hessian + bs[3] * bs[3] * friction_hessian
1159
+ return (
1160
+ True,
1161
+ collision_force_0,
1162
+ collision_force_1,
1163
+ collision_force_2,
1164
+ collision_force_3,
1165
+ collision_hessian_0,
1166
+ collision_hessian_1,
1167
+ collision_hessian_2,
1168
+ collision_hessian_3,
1169
+ )
1170
+ else:
1171
+ collision_force = wp.vec3(0.0, 0.0, 0.0)
1172
+ collision_hessian = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1173
+
1174
+ return (
1175
+ False,
1176
+ collision_force,
1177
+ collision_force,
1178
+ collision_force,
1179
+ collision_force,
1180
+ collision_hessian,
1181
+ collision_hessian,
1182
+ collision_hessian,
1183
+ collision_hessian,
1184
+ )
1185
+
1186
+
843
1187
  @wp.func
844
1188
  def compute_friction(mu: float, normal_contact_force: float, T: mat32, u: wp.vec2, eps_u: float):
845
1189
  """
@@ -1022,7 +1366,6 @@ def VBD_solve_trimesh_no_self_contact(
1022
1366
  particle_ids_in_color: wp.array(dtype=wp.int32),
1023
1367
  prev_pos: wp.array(dtype=wp.vec3),
1024
1368
  pos: wp.array(dtype=wp.vec3),
1025
- pos_new: wp.array(dtype=wp.vec3),
1026
1369
  vel: wp.array(dtype=wp.vec3),
1027
1370
  mass: wp.array(dtype=float),
1028
1371
  inertia: wp.array(dtype=wp.vec3),
@@ -1036,37 +1379,29 @@ def VBD_solve_trimesh_no_self_contact(
1036
1379
  edge_rest_length: wp.array(dtype=float),
1037
1380
  edge_bending_properties: wp.array(dtype=float, ndim=2),
1038
1381
  adjacency: ForceElementAdjacencyInfo,
1382
+ particle_forces: wp.array(dtype=wp.vec3),
1383
+ particle_hessians: wp.array(dtype=wp.mat33),
1039
1384
  # contact info
1040
- # self contact
1041
1385
  soft_contact_ke: float,
1386
+ soft_contact_kd: float,
1042
1387
  friction_mu: float,
1043
1388
  friction_epsilon: float,
1044
- # body-particle contact
1045
- particle_radius: wp.array(dtype=float),
1046
- body_particle_contact_buffer_pre_alloc: int,
1047
- body_particle_contact_buffer: wp.array(dtype=int),
1048
- body_particle_contact_count: wp.array(dtype=int),
1049
- shape_materials: ModelShapeMaterials,
1050
- shape_body: wp.array(dtype=int),
1051
- body_q: wp.array(dtype=wp.transform),
1052
- body_qd: wp.array(dtype=wp.spatial_vector),
1053
- body_com: wp.array(dtype=wp.vec3),
1054
- contact_shape: wp.array(dtype=int),
1055
- contact_body_pos: wp.array(dtype=wp.vec3),
1056
- contact_body_vel: wp.array(dtype=wp.vec3),
1057
- contact_normal: wp.array(dtype=wp.vec3),
1058
1389
  # ground-particle contact
1059
1390
  has_ground: bool,
1060
1391
  ground: wp.array(dtype=float),
1392
+ particle_radius: wp.array(dtype=float),
1393
+ # output
1394
+ pos_new: wp.array(dtype=wp.vec3),
1061
1395
  ):
1062
1396
  tid = wp.tid()
1063
1397
 
1064
1398
  particle_index = particle_ids_in_color[tid]
1399
+ particle_pos = pos[particle_index]
1065
1400
 
1066
1401
  if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
1402
+ pos_new[particle_index] = particle_pos
1067
1403
  return
1068
1404
 
1069
- particle_pos = pos[particle_index]
1070
1405
  particle_prev_pos = pos[particle_index]
1071
1406
 
1072
1407
  dt_sqr_reciprocal = 1.0 / (dt * dt)
@@ -1144,38 +1479,6 @@ def VBD_solve_trimesh_no_self_contact(
1144
1479
  f = f + f_edge
1145
1480
  h = h + h_edge
1146
1481
 
1147
- # body-particle contact
1148
- particle_contact_count = min(body_particle_contact_count[particle_index], body_particle_contact_buffer_pre_alloc)
1149
-
1150
- offset = body_particle_contact_buffer_pre_alloc * particle_index
1151
- for contact_counter in range(particle_contact_count):
1152
- # the index to access body-particle data, which is size-variable and only contains active contact
1153
- contact_index = body_particle_contact_buffer[offset + contact_counter]
1154
-
1155
- body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
1156
- particle_index,
1157
- particle_pos,
1158
- particle_prev_pos,
1159
- contact_index,
1160
- soft_contact_ke,
1161
- friction_mu,
1162
- friction_epsilon,
1163
- particle_radius,
1164
- shape_materials,
1165
- shape_body,
1166
- body_q,
1167
- body_qd,
1168
- body_com,
1169
- contact_shape,
1170
- contact_body_pos,
1171
- contact_body_vel,
1172
- contact_normal,
1173
- dt,
1174
- )
1175
-
1176
- f = f + body_contact_force
1177
- h = h + body_contact_hessian
1178
-
1179
1482
  if has_ground:
1180
1483
  ground_normal = wp.vec3(ground[0], ground[1], ground[2])
1181
1484
  ground_level = ground[3]
@@ -1186,14 +1489,17 @@ def VBD_solve_trimesh_no_self_contact(
1186
1489
  ground_normal,
1187
1490
  ground_level,
1188
1491
  soft_contact_ke,
1492
+ soft_contact_kd,
1189
1493
  friction_mu,
1190
1494
  friction_epsilon,
1191
1495
  dt,
1192
1496
  )
1193
1497
 
1194
- f = f + ground_contact_force
1195
- h = h + ground_contact_hessian
1498
+ f += ground_contact_force
1499
+ h += ground_contact_hessian
1196
1500
 
1501
+ f += particle_forces[particle_index]
1502
+ h += particle_hessians[particle_index]
1197
1503
  if abs(wp.determinant(h)) > 1e-5:
1198
1504
  hInv = wp.inverse(h)
1199
1505
  pos_new[particle_index] = particle_pos + hInv * f
@@ -1244,40 +1550,187 @@ def convert_body_particle_contact_data_kernel(
1244
1550
 
1245
1551
 
1246
1552
  @wp.kernel
1247
- def VBD_solve_trimesh_with_self_contact_penetration_free(
1553
+ def VBD_accumulate_contact_force_and_hessian(
1554
+ # inputs
1248
1555
  dt: float,
1249
- particle_ids_in_color: wp.array(dtype=wp.int32),
1556
+ current_color: int,
1250
1557
  pos_prev: wp.array(dtype=wp.vec3),
1251
1558
  pos: wp.array(dtype=wp.vec3),
1252
- pos_new: wp.array(dtype=wp.vec3),
1253
- vel: wp.array(dtype=wp.vec3),
1254
- mass: wp.array(dtype=float),
1255
- inertia: wp.array(dtype=wp.vec3),
1256
- particle_flags: wp.array(dtype=wp.uint32),
1559
+ particle_colors: wp.array(dtype=int),
1257
1560
  tri_indices: wp.array(dtype=wp.int32, ndim=2),
1258
- tri_poses: wp.array(dtype=wp.mat22),
1259
- tri_materials: wp.array(dtype=float, ndim=2),
1260
- tri_areas: wp.array(dtype=float),
1261
1561
  edge_indices: wp.array(dtype=wp.int32, ndim=2),
1262
- edge_rest_angles: wp.array(dtype=float),
1263
- edge_rest_length: wp.array(dtype=float),
1264
- edge_bending_properties: wp.array(dtype=float, ndim=2),
1265
- adjacency: ForceElementAdjacencyInfo,
1266
- # contact info
1267
- # self contact
1268
- collision_info: TriMeshCollisionInfo,
1562
+ # self contact
1563
+ collision_info_array: wp.array(dtype=TriMeshCollisionInfo),
1269
1564
  collision_radius: float,
1270
1565
  soft_contact_ke: float,
1566
+ soft_contact_kd: float,
1271
1567
  friction_mu: float,
1272
1568
  friction_epsilon: float,
1273
- pos_prev_collision_detection: wp.array(dtype=wp.vec3),
1274
- particle_conservative_bounds: wp.array(dtype=float),
1275
1569
  edge_edge_parallel_epsilon: float,
1276
- # body-particle contact
1570
+ # body-particle contact
1277
1571
  particle_radius: wp.array(dtype=float),
1278
- body_particle_contact_buffer_pre_alloc: int,
1279
- body_particle_contact_buffer: wp.array(dtype=int),
1280
- body_particle_contact_count: wp.array(dtype=int),
1572
+ soft_contact_particle: wp.array(dtype=int),
1573
+ contact_count: wp.array(dtype=int),
1574
+ contact_max: int,
1575
+ shape_materials: ModelShapeMaterials,
1576
+ shape_body: wp.array(dtype=int),
1577
+ body_q: wp.array(dtype=wp.transform),
1578
+ body_qd: wp.array(dtype=wp.spatial_vector),
1579
+ body_com: wp.array(dtype=wp.vec3),
1580
+ contact_shape: wp.array(dtype=int),
1581
+ contact_body_pos: wp.array(dtype=wp.vec3),
1582
+ contact_body_vel: wp.array(dtype=wp.vec3),
1583
+ contact_normal: wp.array(dtype=wp.vec3),
1584
+ # outputs: particle force and hessian
1585
+ particle_forces: wp.array(dtype=wp.vec3),
1586
+ particle_hessians: wp.array(dtype=wp.mat33),
1587
+ ):
1588
+ t_id = wp.tid()
1589
+ collision_info = collision_info_array[0]
1590
+
1591
+ # process edge-edge collisions
1592
+ if t_id * 2 < collision_info.edge_colliding_edges.shape[0]:
1593
+ e1_idx = collision_info.edge_colliding_edges[2 * t_id]
1594
+ e2_idx = collision_info.edge_colliding_edges[2 * t_id + 1]
1595
+
1596
+ if e1_idx != -1 and e2_idx != -1:
1597
+ e1_v1 = edge_indices[e1_idx, 2]
1598
+ e1_v2 = edge_indices[e1_idx, 3]
1599
+ if particle_colors[e1_v1] == current_color or particle_colors[e1_v2] == current_color:
1600
+ has_contact, collision_force_0, collision_force_1, collision_hessian_0, collision_hessian_1 = (
1601
+ evaluate_edge_edge_contact_2_vertices(
1602
+ e1_idx,
1603
+ e2_idx,
1604
+ pos,
1605
+ pos_prev,
1606
+ edge_indices,
1607
+ collision_radius,
1608
+ soft_contact_ke,
1609
+ soft_contact_kd,
1610
+ friction_mu,
1611
+ friction_epsilon,
1612
+ dt,
1613
+ edge_edge_parallel_epsilon,
1614
+ )
1615
+ )
1616
+
1617
+ if has_contact:
1618
+ # here we only handle the e1 side, because e2 will also detection this contact and add force and hessian on its own
1619
+ if particle_colors[e1_v1] == current_color:
1620
+ wp.atomic_add(particle_forces, e1_v1, collision_force_0)
1621
+ wp.atomic_add(particle_hessians, e1_v1, collision_hessian_0)
1622
+ if particle_colors[e1_v2] == current_color:
1623
+ wp.atomic_add(particle_forces, e1_v2, collision_force_1)
1624
+ wp.atomic_add(particle_hessians, e1_v2, collision_hessian_1)
1625
+
1626
+ # process vertex-triangle collisions
1627
+ if t_id * 2 < collision_info.vertex_colliding_triangles.shape[0]:
1628
+ particle_idx = collision_info.vertex_colliding_triangles[2 * t_id]
1629
+ tri_idx = collision_info.vertex_colliding_triangles[2 * t_id + 1]
1630
+
1631
+ if particle_idx != -1 and tri_idx != -1:
1632
+ tri_a = tri_indices[tri_idx, 0]
1633
+ tri_b = tri_indices[tri_idx, 1]
1634
+ tri_c = tri_indices[tri_idx, 2]
1635
+ if (
1636
+ particle_colors[particle_idx] == current_color
1637
+ or particle_colors[tri_a] == current_color
1638
+ or particle_colors[tri_b] == current_color
1639
+ or particle_colors[tri_c] == current_color
1640
+ ):
1641
+ (
1642
+ has_contact,
1643
+ collision_force_0,
1644
+ collision_force_1,
1645
+ collision_force_2,
1646
+ collision_force_3,
1647
+ collision_hessian_0,
1648
+ collision_hessian_1,
1649
+ collision_hessian_2,
1650
+ collision_hessian_3,
1651
+ ) = evaluate_vertex_triangle_collision_force_hessian_4_vertices(
1652
+ particle_idx,
1653
+ tri_idx,
1654
+ pos,
1655
+ pos_prev,
1656
+ tri_indices,
1657
+ collision_radius,
1658
+ soft_contact_ke,
1659
+ soft_contact_kd,
1660
+ friction_mu,
1661
+ friction_epsilon,
1662
+ dt,
1663
+ )
1664
+
1665
+ if has_contact:
1666
+ # particle
1667
+ if particle_colors[particle_idx] == current_color:
1668
+ wp.atomic_add(particle_forces, particle_idx, collision_force_3)
1669
+ wp.atomic_add(particle_hessians, particle_idx, collision_hessian_3)
1670
+
1671
+ # tri_a
1672
+ if particle_colors[tri_a] == current_color:
1673
+ wp.atomic_add(particle_forces, tri_a, collision_force_0)
1674
+ wp.atomic_add(particle_hessians, tri_a, collision_hessian_0)
1675
+
1676
+ # tri_b
1677
+ if particle_colors[tri_b] == current_color:
1678
+ wp.atomic_add(particle_forces, tri_b, collision_force_1)
1679
+ wp.atomic_add(particle_hessians, tri_b, collision_hessian_1)
1680
+
1681
+ # tri_c
1682
+ if particle_colors[tri_c] == current_color:
1683
+ wp.atomic_add(particle_forces, tri_c, collision_force_2)
1684
+ wp.atomic_add(particle_hessians, tri_c, collision_hessian_2)
1685
+
1686
+ particle_body_contact_count = min(contact_max, contact_count[0])
1687
+
1688
+ if t_id < particle_body_contact_count:
1689
+ particle_idx = soft_contact_particle[t_id]
1690
+
1691
+ if particle_colors[particle_idx] == current_color:
1692
+ body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
1693
+ particle_idx,
1694
+ pos[particle_idx],
1695
+ pos_prev[particle_idx],
1696
+ t_id,
1697
+ soft_contact_ke,
1698
+ soft_contact_kd,
1699
+ friction_mu,
1700
+ friction_epsilon,
1701
+ particle_radius,
1702
+ shape_materials,
1703
+ shape_body,
1704
+ body_q,
1705
+ body_qd,
1706
+ body_com,
1707
+ contact_shape,
1708
+ contact_body_pos,
1709
+ contact_body_vel,
1710
+ contact_normal,
1711
+ dt,
1712
+ )
1713
+ wp.atomic_add(particle_forces, particle_idx, body_contact_force)
1714
+ wp.atomic_add(particle_hessians, particle_idx, body_contact_hessian)
1715
+
1716
+
1717
+ @wp.kernel
1718
+ def VBD_accumulate_contact_force_and_hessian_no_self_contact(
1719
+ # inputs
1720
+ dt: float,
1721
+ current_color: int,
1722
+ pos_prev: wp.array(dtype=wp.vec3),
1723
+ pos: wp.array(dtype=wp.vec3),
1724
+ particle_colors: wp.array(dtype=int),
1725
+ # body-particle contact
1726
+ soft_contact_ke: float,
1727
+ soft_contact_kd: float,
1728
+ friction_mu: float,
1729
+ friction_epsilon: float,
1730
+ particle_radius: wp.array(dtype=float),
1731
+ soft_contact_particle: wp.array(dtype=int),
1732
+ contact_count: wp.array(dtype=int),
1733
+ contact_max: int,
1281
1734
  shape_materials: ModelShapeMaterials,
1282
1735
  shape_body: wp.array(dtype=int),
1283
1736
  body_q: wp.array(dtype=wp.transform),
@@ -1287,9 +1740,76 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1287
1740
  contact_body_pos: wp.array(dtype=wp.vec3),
1288
1741
  contact_body_vel: wp.array(dtype=wp.vec3),
1289
1742
  contact_normal: wp.array(dtype=wp.vec3),
1743
+ # outputs: particle force and hessian
1744
+ particle_forces: wp.array(dtype=wp.vec3),
1745
+ particle_hessians: wp.array(dtype=wp.mat33),
1746
+ ):
1747
+ t_id = wp.tid()
1748
+
1749
+ particle_body_contact_count = min(contact_max, contact_count[0])
1750
+
1751
+ if t_id < particle_body_contact_count:
1752
+ particle_idx = soft_contact_particle[t_id]
1753
+
1754
+ if particle_colors[particle_idx] == current_color:
1755
+ body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
1756
+ particle_idx,
1757
+ pos[particle_idx],
1758
+ pos_prev[particle_idx],
1759
+ t_id,
1760
+ soft_contact_ke,
1761
+ soft_contact_kd,
1762
+ friction_mu,
1763
+ friction_epsilon,
1764
+ particle_radius,
1765
+ shape_materials,
1766
+ shape_body,
1767
+ body_q,
1768
+ body_qd,
1769
+ body_com,
1770
+ contact_shape,
1771
+ contact_body_pos,
1772
+ contact_body_vel,
1773
+ contact_normal,
1774
+ dt,
1775
+ )
1776
+ wp.atomic_add(particle_forces, particle_idx, body_contact_force)
1777
+ wp.atomic_add(particle_hessians, particle_idx, body_contact_hessian)
1778
+
1779
+
1780
+ @wp.kernel
1781
+ def VBD_solve_trimesh_with_self_contact_penetration_free(
1782
+ dt: float,
1783
+ particle_ids_in_color: wp.array(dtype=wp.int32),
1784
+ pos_prev: wp.array(dtype=wp.vec3),
1785
+ pos: wp.array(dtype=wp.vec3),
1786
+ vel: wp.array(dtype=wp.vec3),
1787
+ mass: wp.array(dtype=float),
1788
+ inertia: wp.array(dtype=wp.vec3),
1789
+ particle_flags: wp.array(dtype=wp.uint32),
1790
+ tri_indices: wp.array(dtype=wp.int32, ndim=2),
1791
+ tri_poses: wp.array(dtype=wp.mat22),
1792
+ tri_materials: wp.array(dtype=float, ndim=2),
1793
+ tri_areas: wp.array(dtype=float),
1794
+ edge_indices: wp.array(dtype=wp.int32, ndim=2),
1795
+ edge_rest_angles: wp.array(dtype=float),
1796
+ edge_rest_length: wp.array(dtype=float),
1797
+ edge_bending_properties: wp.array(dtype=float, ndim=2),
1798
+ adjacency: ForceElementAdjacencyInfo,
1799
+ particle_forces: wp.array(dtype=wp.vec3),
1800
+ particle_hessians: wp.array(dtype=wp.mat33),
1801
+ pos_prev_collision_detection: wp.array(dtype=wp.vec3),
1802
+ particle_conservative_bounds: wp.array(dtype=float),
1290
1803
  # ground-particle contact
1291
1804
  has_ground: bool,
1292
1805
  ground: wp.array(dtype=float),
1806
+ soft_contact_ke: float,
1807
+ soft_contact_kd: float,
1808
+ friction_mu: float,
1809
+ friction_epsilon: float,
1810
+ particle_radius: wp.array(dtype=float),
1811
+ # output
1812
+ pos_new: wp.array(dtype=wp.vec3),
1293
1813
  ):
1294
1814
  t_id = wp.tid()
1295
1815
 
@@ -1298,13 +1818,14 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1298
1818
  particle_prev_pos = pos_prev[particle_index]
1299
1819
 
1300
1820
  if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
1821
+ pos_new[particle_index] = particle_pos
1301
1822
  return
1302
1823
 
1303
1824
  dt_sqr_reciprocal = 1.0 / (dt * dt)
1304
1825
 
1305
1826
  # inertia force and hessian
1306
1827
  f = mass[particle_index] * (inertia[particle_index] - pos[particle_index]) * (dt_sqr_reciprocal)
1307
- h = mass[particle_index] * dt_sqr_reciprocal * wp.identity(n=3, dtype=float)
1828
+ h = particle_hessians[particle_index] + mass[particle_index] * dt_sqr_reciprocal * wp.identity(n=3, dtype=float)
1308
1829
 
1309
1830
  # fmt: off
1310
1831
  if wp.static("inertia_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
@@ -1314,48 +1835,6 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1314
1835
  f[0], f[1], f[2], h[0, 0], h[0, 1], h[0, 2], h[1, 0], h[1, 1], h[1, 2], h[2, 0], h[2, 1], h[2, 2],
1315
1836
  )
1316
1837
 
1317
- # v-side of the v-f collision force
1318
- if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
1319
- wp.printf("Has %d colliding triangles\n", get_vertex_colliding_triangles_count(collision_info, particle_index))
1320
- for i_v_collision in range(get_vertex_colliding_triangles_count(collision_info, particle_index)):
1321
- colliding_t = get_vertex_colliding_triangles(collision_info, particle_index, i_v_collision)
1322
- if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
1323
- wp.printf(
1324
- "vertex %d is colliding with triangle: %d-(%d, %d, %d)",
1325
- particle_index,
1326
- colliding_t,
1327
- tri_indices[colliding_t, 0],
1328
- tri_indices[colliding_t, 1],
1329
- tri_indices[colliding_t, 2],
1330
- )
1331
- # fmt: on
1332
-
1333
- collision_force, collision_hessian = evaluate_vertex_triangle_collision_force_hessian(
1334
- particle_index,
1335
- 3,
1336
- colliding_t,
1337
- pos,
1338
- pos_prev,
1339
- tri_indices,
1340
- collision_radius,
1341
- soft_contact_ke,
1342
- friction_mu,
1343
- friction_epsilon,
1344
- dt,
1345
- )
1346
- f = f + collision_force
1347
- h = h + collision_hessian
1348
-
1349
- # fmt: off
1350
- if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
1351
- wp.printf(
1352
- "vertex: %d collision %d:\nforce:\n %f %f %f, \nhessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
1353
- particle_index,
1354
- i_v_collision,
1355
- collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
1356
- )
1357
- # fmt: on
1358
-
1359
1838
  # elastic force and hessian
1360
1839
  for i_adj_tri in range(get_vertex_num_adjacent_faces(adjacency, particle_index)):
1361
1840
  tri_index, vertex_order = get_vertex_adjacent_face_id_order(adjacency, particle_index, i_adj_tri)
@@ -1391,41 +1870,12 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1391
1870
  k_d = tri_materials[tri_index, 2]
1392
1871
  h_d = h_tri * (k_d / dt)
1393
1872
 
1394
- f_d = h_d * (pos_prev[particle_index] - pos[particle_index])
1873
+ f_d = h_d * (particle_prev_pos - particle_pos)
1395
1874
 
1396
1875
  f = f + f_tri + f_d
1397
1876
  h = h + h_tri + h_d
1398
1877
 
1399
- # t-side of vt-collision from the neighbor triangles
1400
- # fmt: off
1401
- if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
1402
- wp.printf(
1403
- "Nei triangle %d has %d colliding vertice\n",
1404
- tri_index,
1405
- get_triangle_colliding_vertices_count(collision_info, tri_index),
1406
- )
1407
- # fmt: on
1408
- for i_t_collision in range(get_triangle_colliding_vertices_count(collision_info, tri_index)):
1409
- colliding_v = get_triangle_colliding_vertices(collision_info, tri_index, i_t_collision)
1410
-
1411
- collision_force, collision_hessian = evaluate_vertex_triangle_collision_force_hessian(
1412
- colliding_v,
1413
- vertex_order,
1414
- tri_index,
1415
- pos,
1416
- pos_prev,
1417
- tri_indices,
1418
- collision_radius,
1419
- soft_contact_ke,
1420
- friction_mu,
1421
- friction_epsilon,
1422
- dt,
1423
- )
1424
-
1425
- f = f + collision_force
1426
- h = h + collision_hessian
1427
1878
 
1428
- # edge-edge collision force and hessian
1429
1879
  for i_adj_edge in range(get_vertex_num_adjacent_edges(adjacency, particle_index)):
1430
1880
  nei_edge_index, vertex_order_on_edge = get_vertex_adjacent_edge_id_order(adjacency, particle_index, i_adj_edge)
1431
1881
  # vertex is on the edge; otherwise it only effects the bending energy n
@@ -1438,78 +1888,6 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1438
1888
  f = f + f_edge
1439
1889
  h = h + h_edge
1440
1890
 
1441
- if vertex_order_on_edge == 2 or vertex_order_on_edge == 3:
1442
- # collisions of neighbor triangles
1443
- if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
1444
- wp.printf(
1445
- "Nei edge %d has %d colliding edge\n",
1446
- nei_edge_index,
1447
- get_edge_colliding_edges_count(collision_info, nei_edge_index),
1448
- )
1449
- for i_e_collision in range(get_edge_colliding_edges_count(collision_info, nei_edge_index)):
1450
- colliding_e = get_edge_colliding_edges(collision_info, nei_edge_index, i_e_collision)
1451
-
1452
- collision_force, collision_hessian = evaluate_edge_edge_contact(
1453
- particle_index,
1454
- vertex_order_on_edge - 2,
1455
- nei_edge_index,
1456
- colliding_e,
1457
- pos,
1458
- pos_prev,
1459
- edge_indices,
1460
- collision_radius,
1461
- soft_contact_ke,
1462
- friction_mu,
1463
- friction_epsilon,
1464
- dt,
1465
- edge_edge_parallel_epsilon,
1466
- )
1467
- f = f + collision_force
1468
- h = h + collision_hessian
1469
-
1470
- # fmt: off
1471
- if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
1472
- wp.printf(
1473
- "vertex: %d edge %d collision %d:\nforce:\n %f %f %f, \nhessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
1474
- particle_index,
1475
- nei_edge_index,
1476
- i_e_collision,
1477
- collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
1478
- )
1479
- # fmt: on
1480
-
1481
- # body-particle contact
1482
- particle_contact_count = min(body_particle_contact_count[particle_index], body_particle_contact_buffer_pre_alloc)
1483
-
1484
- offset = body_particle_contact_buffer_pre_alloc * particle_index
1485
- for contact_counter in range(particle_contact_count):
1486
- # the index to access body-particle data, which is size-variable and only contains active contact
1487
- contact_index = body_particle_contact_buffer[offset + contact_counter]
1488
-
1489
- body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
1490
- particle_index,
1491
- particle_pos,
1492
- particle_prev_pos,
1493
- contact_index,
1494
- soft_contact_ke,
1495
- friction_mu,
1496
- friction_epsilon,
1497
- particle_radius,
1498
- shape_materials,
1499
- shape_body,
1500
- body_q,
1501
- body_qd,
1502
- body_com,
1503
- contact_shape,
1504
- contact_body_pos,
1505
- contact_body_vel,
1506
- contact_normal,
1507
- dt,
1508
- )
1509
-
1510
- f = f + body_contact_force
1511
- h = h + body_contact_hessian
1512
-
1513
1891
  if has_ground:
1514
1892
  ground_normal = wp.vec3(ground[0], ground[1], ground[2])
1515
1893
  ground_level = ground[3]
@@ -1520,6 +1898,7 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1520
1898
  ground_normal,
1521
1899
  ground_level,
1522
1900
  soft_contact_ke,
1901
+ soft_contact_kd,
1523
1902
  friction_mu,
1524
1903
  friction_epsilon,
1525
1904
  dt,
@@ -1535,9 +1914,12 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1535
1914
  particle_index,
1536
1915
  f[0], f[1], f[2], h[0, 0], h[0, 1], h[0, 2], h[1, 0], h[1, 1], h[1, 2], h[2, 0], h[2, 1], h[2, 2],
1537
1916
  )
1538
- # fmt: on
1539
1917
 
1918
+ # # fmt: on
1919
+ h = h + particle_hessians[particle_index]
1920
+ f = f + particle_forces[particle_index]
1540
1921
  if abs(wp.determinant(h)) > 1e-5:
1922
+
1541
1923
  h_inv = wp.inverse(h)
1542
1924
  particle_pos_new = pos[particle_index] + h_inv * f
1543
1925
 
@@ -1554,7 +1936,7 @@ class VBDIntegrator(Integrator):
1554
1936
 
1555
1937
  Note that VBDIntegrator's constructor requires a :class:`Model` object as input, so that it can do some precomputation and preallocate the space.
1556
1938
  After construction, you must provide the same :class:`Model` object that you used that was used during construction.
1557
- Currently, you must manually provide particle coloring and assign it to `model.particle_coloring` to make VBD work.
1939
+ Currently, you must manually provide particle coloring and assign it to `model.particle_color_groups` to make VBD work.
1558
1940
 
1559
1941
  VBDIntegrator.simulate accepts three arguments: class:`Model`, :class:`State`, and :class:`Control` (optional) objects, this time-integrator
1560
1942
  may be used to advance the simulation state forward in time.
@@ -1564,7 +1946,7 @@ class VBDIntegrator(Integrator):
1564
1946
 
1565
1947
  .. code-block:: python
1566
1948
 
1567
- model.particle_coloring = # load or generate particle coloring
1949
+ model.particle_color_groups = # load or generate particle coloring
1568
1950
  integrator = wp.VBDIntegrator(model)
1569
1951
 
1570
1952
  # simulation loop
@@ -1596,13 +1978,6 @@ class VBDIntegrator(Integrator):
1596
1978
 
1597
1979
  self.adjacency = self.compute_force_element_adjacency(model).to(self.device)
1598
1980
 
1599
- # data for body-particle collision
1600
- self.body_particle_contact_buffer_pre_alloc = body_particle_contact_buffer_pre_alloc
1601
- self.body_particle_contact_buffer = wp.zeros(
1602
- (self.body_particle_contact_buffer_pre_alloc * model.particle_count,),
1603
- dtype=wp.int32,
1604
- device=self.device,
1605
- )
1606
1981
  self.body_particle_contact_count = wp.zeros((model.particle_count,), dtype=wp.int32, device=self.device)
1607
1982
 
1608
1983
  self.handle_self_contact = handle_self_contact
@@ -1626,11 +2001,27 @@ class VBDIntegrator(Integrator):
1626
2001
  edge_edge_parallel_epsilon=edge_edge_parallel_epsilon,
1627
2002
  )
1628
2003
 
2004
+ self.trimesh_collision_info = wp.array(
2005
+ [self.trimesh_collision_detector.collision_info], dtype=TriMeshCollisionInfo, device=self.device
2006
+ )
2007
+
2008
+ self.collision_evaluation_kernel_launch_size = max(
2009
+ self.trimesh_collision_detector.vertex_colliding_triangles.shape[0] // 2,
2010
+ self.trimesh_collision_detector.edge_colliding_edges.shape[0] // 2,
2011
+ self.model.soft_contact_max,
2012
+ )
2013
+ else:
2014
+ self.collision_evaluation_kernel_launch_size = self.model.soft_contact_max
2015
+
2016
+ # spaces for particle force and hessian
2017
+ self.particle_forces = wp.zeros(self.model.particle_count, dtype=wp.vec3, device=self.device)
2018
+ self.particle_hessians = wp.zeros(self.model.particle_count, dtype=wp.mat33, device=self.device)
2019
+
1629
2020
  self.friction_epsilon = friction_epsilon
1630
2021
 
1631
- if len(self.model.particle_coloring) == 0:
2022
+ if len(self.model.particle_color_groups) == 0:
1632
2023
  raise ValueError(
1633
- "model.particle_coloring is empty! When using the VBDIntegrator you must call ModelBuilder.color() "
2024
+ "model.particle_color_groups is empty! When using the VBDIntegrator you must call ModelBuilder.color() "
1634
2025
  "or ModelBuilder.set_coloring() before calling ModelBuilder.finalize()."
1635
2026
  )
1636
2027
 
@@ -1733,8 +2124,6 @@ class VBDIntegrator(Integrator):
1733
2124
  def simulate_one_step_no_self_contact(
1734
2125
  self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None
1735
2126
  ):
1736
- self.convert_body_particle_contact_data()
1737
-
1738
2127
  wp.launch(
1739
2128
  kernel=forward_step,
1740
2129
  inputs=[
@@ -1753,15 +2142,48 @@ class VBDIntegrator(Integrator):
1753
2142
  )
1754
2143
 
1755
2144
  for _iter in range(self.iterations):
1756
- for color_counter in range(len(self.model.particle_coloring)):
2145
+ self.particle_forces.zero_()
2146
+ self.particle_hessians.zero_()
2147
+ for color in range(len(self.model.particle_color_groups)):
2148
+ wp.launch(
2149
+ kernel=VBD_accumulate_contact_force_and_hessian_no_self_contact,
2150
+ dim=self.collision_evaluation_kernel_launch_size,
2151
+ inputs=[
2152
+ dt,
2153
+ color,
2154
+ self.particle_q_prev,
2155
+ state_in.particle_q,
2156
+ self.model.particle_colors,
2157
+ # body-particle contact
2158
+ self.model.soft_contact_ke,
2159
+ self.model.soft_contact_kd,
2160
+ self.model.soft_contact_mu,
2161
+ self.friction_epsilon,
2162
+ self.model.particle_radius,
2163
+ self.model.soft_contact_particle,
2164
+ self.model.soft_contact_count,
2165
+ self.model.soft_contact_max,
2166
+ self.model.shape_materials,
2167
+ self.model.shape_body,
2168
+ self.model.body_q,
2169
+ self.model.body_qd,
2170
+ self.model.body_com,
2171
+ self.model.soft_contact_shape,
2172
+ self.model.soft_contact_body_pos,
2173
+ self.model.soft_contact_body_vel,
2174
+ self.model.soft_contact_normal,
2175
+ ],
2176
+ outputs=[self.particle_forces, self.particle_hessians],
2177
+ device=self.device,
2178
+ )
2179
+
1757
2180
  wp.launch(
1758
2181
  kernel=VBD_solve_trimesh_no_self_contact,
1759
2182
  inputs=[
1760
2183
  dt,
1761
- self.model.particle_coloring[color_counter],
2184
+ self.model.particle_color_groups[color],
1762
2185
  self.particle_q_prev,
1763
2186
  state_in.particle_q,
1764
- state_out.particle_q,
1765
2187
  state_in.particle_qd,
1766
2188
  self.model.particle_mass,
1767
2189
  self.inertia,
@@ -1775,34 +2197,28 @@ class VBDIntegrator(Integrator):
1775
2197
  self.model.edge_rest_length,
1776
2198
  self.model.edge_bending_properties,
1777
2199
  self.adjacency,
2200
+ self.particle_forces,
2201
+ self.particle_hessians,
1778
2202
  self.model.soft_contact_ke,
2203
+ self.model.soft_contact_kd,
1779
2204
  self.model.soft_contact_mu,
1780
2205
  self.friction_epsilon,
1781
- # body-particle contact
1782
- self.model.particle_radius,
1783
- self.body_particle_contact_buffer_pre_alloc,
1784
- self.body_particle_contact_buffer,
1785
- self.body_particle_contact_count,
1786
- self.model.shape_materials,
1787
- self.model.shape_body,
1788
- self.model.body_q,
1789
- self.model.body_qd,
1790
- self.model.body_com,
1791
- self.model.soft_contact_shape,
1792
- self.model.soft_contact_body_pos,
1793
- self.model.soft_contact_body_vel,
1794
- self.model.soft_contact_normal,
2206
+ # ground-particle contact
1795
2207
  self.model.ground,
1796
2208
  self.model.ground_plane,
2209
+ self.model.particle_radius,
2210
+ ],
2211
+ outputs=[
2212
+ state_out.particle_q,
1797
2213
  ],
1798
- dim=self.model.particle_coloring[color_counter].size,
2214
+ dim=self.model.particle_color_groups[color].size,
1799
2215
  device=self.device,
1800
2216
  )
1801
2217
 
1802
2218
  wp.launch(
1803
2219
  kernel=VBD_copy_particle_positions_back,
1804
- inputs=[self.model.particle_coloring[color_counter], state_in.particle_q, state_out.particle_q],
1805
- dim=self.model.particle_coloring[color_counter].size,
2220
+ inputs=[self.model.particle_color_groups[color], state_in.particle_q, state_out.particle_q],
2221
+ dim=self.model.particle_color_groups[color].size,
1806
2222
  device=self.device,
1807
2223
  )
1808
2224
 
@@ -1816,7 +2232,6 @@ class VBDIntegrator(Integrator):
1816
2232
  def simulate_one_step_with_collisions_penetration_free(
1817
2233
  self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None
1818
2234
  ):
1819
- self.convert_body_particle_contact_data()
1820
2235
  # collision detection before initialization to compute conservative bounds for initialization
1821
2236
  self.collision_detection_penetration_free(state_in, dt)
1822
2237
 
@@ -1843,42 +2258,34 @@ class VBDIntegrator(Integrator):
1843
2258
  self.collision_detection_penetration_free(state_in, dt)
1844
2259
 
1845
2260
  for _iter in range(self.iterations):
1846
- for i_color in range(len(self.model.particle_coloring)):
2261
+ self.particle_forces.zero_()
2262
+ self.particle_hessians.zero_()
2263
+
2264
+ for color in range(len(self.model.particle_color_groups)):
1847
2265
  wp.launch(
1848
- kernel=VBD_solve_trimesh_with_self_contact_penetration_free,
2266
+ kernel=VBD_accumulate_contact_force_and_hessian,
2267
+ dim=self.collision_evaluation_kernel_launch_size,
1849
2268
  inputs=[
1850
2269
  dt,
1851
- self.model.particle_coloring[i_color],
2270
+ color,
1852
2271
  self.particle_q_prev,
1853
2272
  state_in.particle_q,
1854
- state_out.particle_q,
1855
- state_in.particle_qd,
1856
- self.model.particle_mass,
1857
- self.inertia,
1858
- self.model.particle_flags,
2273
+ self.model.particle_colors,
1859
2274
  self.model.tri_indices,
1860
- self.model.tri_poses,
1861
- self.model.tri_materials,
1862
- self.model.tri_areas,
1863
2275
  self.model.edge_indices,
1864
- self.model.edge_rest_angle,
1865
- self.model.edge_rest_length,
1866
- self.model.edge_bending_properties,
1867
- self.adjacency,
1868
- # self-contact
1869
- self.trimesh_collision_detector.collision_info,
2276
+ # self-contact
2277
+ self.trimesh_collision_info,
1870
2278
  self.model.soft_contact_radius,
1871
2279
  self.model.soft_contact_ke,
2280
+ self.model.soft_contact_kd,
1872
2281
  self.model.soft_contact_mu,
1873
2282
  self.friction_epsilon,
1874
- self.pos_prev_collision_detection,
1875
- self.particle_conservative_bounds,
1876
2283
  self.trimesh_collision_detector.edge_edge_parallel_epsilon,
1877
- # body-particle contact
2284
+ # body-particle contact
1878
2285
  self.model.particle_radius,
1879
- self.body_particle_contact_buffer_pre_alloc,
1880
- self.body_particle_contact_buffer,
1881
- self.body_particle_contact_count,
2286
+ self.model.soft_contact_particle,
2287
+ self.model.soft_contact_count,
2288
+ self.model.soft_contact_max,
1882
2289
  self.model.shape_materials,
1883
2290
  self.model.shape_body,
1884
2291
  self.model.body_q,
@@ -1888,17 +2295,54 @@ class VBDIntegrator(Integrator):
1888
2295
  self.model.soft_contact_body_pos,
1889
2296
  self.model.soft_contact_body_vel,
1890
2297
  self.model.soft_contact_normal,
2298
+ ],
2299
+ outputs=[self.particle_forces, self.particle_hessians],
2300
+ device=self.device,
2301
+ )
2302
+
2303
+ wp.launch(
2304
+ kernel=VBD_solve_trimesh_with_self_contact_penetration_free,
2305
+ dim=self.model.particle_color_groups[color].shape[0],
2306
+ inputs=[
2307
+ dt,
2308
+ self.model.particle_color_groups[color],
2309
+ self.particle_q_prev,
2310
+ state_in.particle_q,
2311
+ state_in.particle_qd,
2312
+ self.model.particle_mass,
2313
+ self.inertia,
2314
+ self.model.particle_flags,
2315
+ self.model.tri_indices,
2316
+ self.model.tri_poses,
2317
+ self.model.tri_materials,
2318
+ self.model.tri_areas,
2319
+ self.model.edge_indices,
2320
+ self.model.edge_rest_angle,
2321
+ self.model.edge_rest_length,
2322
+ self.model.edge_bending_properties,
2323
+ self.adjacency,
2324
+ self.particle_forces,
2325
+ self.particle_hessians,
2326
+ self.pos_prev_collision_detection,
2327
+ self.particle_conservative_bounds,
1891
2328
  self.model.ground,
1892
2329
  self.model.ground_plane,
2330
+ self.model.soft_contact_ke,
2331
+ self.model.soft_contact_kd,
2332
+ self.model.soft_contact_mu,
2333
+ self.friction_epsilon,
2334
+ self.model.particle_radius,
2335
+ ],
2336
+ outputs=[
2337
+ state_out.particle_q,
1893
2338
  ],
1894
- dim=self.model.particle_coloring[i_color].shape[0],
1895
2339
  device=self.device,
1896
2340
  )
1897
2341
 
1898
2342
  wp.launch(
1899
2343
  kernel=VBD_copy_particle_positions_back,
1900
- inputs=[self.model.particle_coloring[i_color], state_in.particle_q, state_out.particle_q],
1901
- dim=self.model.particle_coloring[i_color].size,
2344
+ inputs=[self.model.particle_color_groups[color], state_in.particle_q, state_out.particle_q],
2345
+ dim=self.model.particle_color_groups[color].size,
1902
2346
  device=self.device,
1903
2347
  )
1904
2348
 
@@ -1930,21 +2374,16 @@ class VBDIntegrator(Integrator):
1930
2374
  device=self.device,
1931
2375
  )
1932
2376
 
1933
- def convert_body_particle_contact_data(self):
1934
- self.body_particle_contact_count.zero_()
2377
+ def rebuild_bvh(self, state: State):
2378
+ """This function will rebuild the BVHs used for detecting self-contacts using the input `state`.
1935
2379
 
1936
- wp.launch(
1937
- kernel=convert_body_particle_contact_data_kernel,
1938
- inputs=[
1939
- self.body_particle_contact_buffer_pre_alloc,
1940
- self.model.soft_contact_particle,
1941
- self.model.soft_contact_count,
1942
- self.model.soft_contact_max,
1943
- ],
1944
- outputs=[self.body_particle_contact_buffer, self.body_particle_contact_count],
1945
- dim=self.model.soft_contact_max,
1946
- device=self.device,
1947
- )
2380
+ When the simulated object deforms significantly, simply refitting the BVH can lead to deterioration of the BVH's
2381
+ quality. In these cases, rebuilding the entire tree is necessary to achieve better querying efficiency.
2382
+
2383
+ Args:
2384
+ state (wp.sim.State): The state whose particle positions (:attr:`State.particle_q`) will be used for rebuilding the BVHs.
2385
+ """
2386
+ self.trimesh_collision_detector.rebuild(state.particle_q)
1948
2387
 
1949
2388
  @wp.kernel
1950
2389
  def count_num_adjacent_edges(