warp-lang 1.7.2__py3-none-macosx_10_13_universal2.whl → 1.8.0__py3-none-macosx_10_13_universal2.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/libwarp-clang.dylib +0 -0
  5. warp/bin/libwarp.dylib +0 -0
  6. warp/build.py +241 -252
  7. warp/build_dll.py +125 -26
  8. warp/builtins.py +1907 -384
  9. warp/codegen.py +257 -101
  10. warp/config.py +12 -1
  11. warp/constants.py +1 -1
  12. warp/context.py +657 -223
  13. warp/dlpack.py +1 -1
  14. warp/examples/benchmarks/benchmark_cloth.py +2 -2
  15. warp/examples/benchmarks/benchmark_tile_sort.py +155 -0
  16. warp/examples/core/example_sample_mesh.py +1 -1
  17. warp/examples/core/example_spin_lock.py +93 -0
  18. warp/examples/core/example_work_queue.py +118 -0
  19. warp/examples/fem/example_adaptive_grid.py +5 -5
  20. warp/examples/fem/example_apic_fluid.py +1 -1
  21. warp/examples/fem/example_burgers.py +1 -1
  22. warp/examples/fem/example_convection_diffusion.py +9 -6
  23. warp/examples/fem/example_darcy_ls_optimization.py +489 -0
  24. warp/examples/fem/example_deformed_geometry.py +1 -1
  25. warp/examples/fem/example_diffusion.py +2 -2
  26. warp/examples/fem/example_diffusion_3d.py +1 -1
  27. warp/examples/fem/example_distortion_energy.py +1 -1
  28. warp/examples/fem/example_elastic_shape_optimization.py +387 -0
  29. warp/examples/fem/example_magnetostatics.py +5 -3
  30. warp/examples/fem/example_mixed_elasticity.py +5 -3
  31. warp/examples/fem/example_navier_stokes.py +11 -9
  32. warp/examples/fem/example_nonconforming_contact.py +5 -3
  33. warp/examples/fem/example_streamlines.py +8 -3
  34. warp/examples/fem/utils.py +9 -8
  35. warp/examples/interop/example_jax_ffi_callback.py +2 -2
  36. warp/examples/optim/example_drone.py +1 -1
  37. warp/examples/sim/example_cloth.py +1 -1
  38. warp/examples/sim/example_cloth_self_contact.py +48 -54
  39. warp/examples/tile/example_tile_block_cholesky.py +502 -0
  40. warp/examples/tile/example_tile_cholesky.py +2 -1
  41. warp/examples/tile/example_tile_convolution.py +1 -1
  42. warp/examples/tile/example_tile_filtering.py +1 -1
  43. warp/examples/tile/example_tile_matmul.py +1 -1
  44. warp/examples/tile/example_tile_mlp.py +2 -0
  45. warp/fabric.py +7 -7
  46. warp/fem/__init__.py +5 -0
  47. warp/fem/adaptivity.py +1 -1
  48. warp/fem/cache.py +152 -63
  49. warp/fem/dirichlet.py +2 -2
  50. warp/fem/domain.py +136 -6
  51. warp/fem/field/field.py +141 -99
  52. warp/fem/field/nodal_field.py +85 -39
  53. warp/fem/field/virtual.py +97 -52
  54. warp/fem/geometry/adaptive_nanogrid.py +91 -86
  55. warp/fem/geometry/closest_point.py +13 -0
  56. warp/fem/geometry/deformed_geometry.py +102 -40
  57. warp/fem/geometry/element.py +56 -2
  58. warp/fem/geometry/geometry.py +323 -22
  59. warp/fem/geometry/grid_2d.py +157 -62
  60. warp/fem/geometry/grid_3d.py +116 -20
  61. warp/fem/geometry/hexmesh.py +86 -20
  62. warp/fem/geometry/nanogrid.py +166 -86
  63. warp/fem/geometry/partition.py +59 -25
  64. warp/fem/geometry/quadmesh.py +86 -135
  65. warp/fem/geometry/tetmesh.py +47 -119
  66. warp/fem/geometry/trimesh.py +77 -270
  67. warp/fem/integrate.py +107 -52
  68. warp/fem/linalg.py +25 -58
  69. warp/fem/operator.py +124 -27
  70. warp/fem/quadrature/pic_quadrature.py +36 -14
  71. warp/fem/quadrature/quadrature.py +40 -16
  72. warp/fem/space/__init__.py +1 -1
  73. warp/fem/space/basis_function_space.py +66 -46
  74. warp/fem/space/basis_space.py +17 -4
  75. warp/fem/space/dof_mapper.py +1 -1
  76. warp/fem/space/function_space.py +2 -2
  77. warp/fem/space/grid_2d_function_space.py +4 -1
  78. warp/fem/space/hexmesh_function_space.py +4 -2
  79. warp/fem/space/nanogrid_function_space.py +3 -1
  80. warp/fem/space/partition.py +11 -2
  81. warp/fem/space/quadmesh_function_space.py +4 -1
  82. warp/fem/space/restriction.py +5 -2
  83. warp/fem/space/shape/__init__.py +10 -8
  84. warp/fem/space/tetmesh_function_space.py +4 -1
  85. warp/fem/space/topology.py +52 -21
  86. warp/fem/space/trimesh_function_space.py +4 -1
  87. warp/fem/utils.py +53 -8
  88. warp/jax.py +1 -2
  89. warp/jax_experimental/ffi.py +12 -17
  90. warp/jax_experimental/xla_ffi.py +37 -24
  91. warp/math.py +171 -1
  92. warp/native/array.h +99 -0
  93. warp/native/builtin.h +174 -31
  94. warp/native/coloring.cpp +1 -1
  95. warp/native/exports.h +118 -63
  96. warp/native/intersect.h +3 -3
  97. warp/native/mat.h +5 -10
  98. warp/native/mathdx.cpp +11 -5
  99. warp/native/matnn.h +1 -123
  100. warp/native/quat.h +28 -4
  101. warp/native/sparse.cpp +121 -258
  102. warp/native/sparse.cu +181 -274
  103. warp/native/spatial.h +305 -17
  104. warp/native/tile.h +583 -72
  105. warp/native/tile_radix_sort.h +1108 -0
  106. warp/native/tile_reduce.h +237 -2
  107. warp/native/tile_scan.h +240 -0
  108. warp/native/tuple.h +189 -0
  109. warp/native/vec.h +6 -16
  110. warp/native/warp.cpp +36 -4
  111. warp/native/warp.cu +574 -51
  112. warp/native/warp.h +47 -74
  113. warp/optim/linear.py +5 -1
  114. warp/paddle.py +7 -8
  115. warp/py.typed +0 -0
  116. warp/render/render_opengl.py +58 -29
  117. warp/render/render_usd.py +124 -61
  118. warp/sim/__init__.py +9 -0
  119. warp/sim/collide.py +252 -78
  120. warp/sim/graph_coloring.py +8 -1
  121. warp/sim/import_mjcf.py +4 -3
  122. warp/sim/import_usd.py +11 -7
  123. warp/sim/integrator.py +5 -2
  124. warp/sim/integrator_euler.py +1 -1
  125. warp/sim/integrator_featherstone.py +1 -1
  126. warp/sim/integrator_vbd.py +751 -320
  127. warp/sim/integrator_xpbd.py +1 -1
  128. warp/sim/model.py +265 -260
  129. warp/sim/utils.py +10 -7
  130. warp/sparse.py +303 -166
  131. warp/tape.py +52 -51
  132. warp/tests/cuda/test_conditional_captures.py +1046 -0
  133. warp/tests/cuda/test_streams.py +1 -1
  134. warp/tests/geometry/test_volume.py +2 -2
  135. warp/tests/interop/test_dlpack.py +9 -9
  136. warp/tests/interop/test_jax.py +0 -1
  137. warp/tests/run_coverage_serial.py +1 -1
  138. warp/tests/sim/disabled_kinematics.py +2 -2
  139. warp/tests/sim/{test_vbd.py → test_cloth.py} +296 -113
  140. warp/tests/sim/test_collision.py +159 -51
  141. warp/tests/sim/test_coloring.py +15 -1
  142. warp/tests/test_array.py +254 -2
  143. warp/tests/test_array_reduce.py +2 -2
  144. warp/tests/test_atomic_cas.py +299 -0
  145. warp/tests/test_codegen.py +142 -19
  146. warp/tests/test_conditional.py +47 -1
  147. warp/tests/test_ctypes.py +0 -20
  148. warp/tests/test_devices.py +8 -0
  149. warp/tests/test_fabricarray.py +4 -2
  150. warp/tests/test_fem.py +58 -25
  151. warp/tests/test_func.py +42 -1
  152. warp/tests/test_grad.py +1 -1
  153. warp/tests/test_lerp.py +1 -3
  154. warp/tests/test_map.py +481 -0
  155. warp/tests/test_mat.py +1 -24
  156. warp/tests/test_quat.py +6 -15
  157. warp/tests/test_rounding.py +10 -38
  158. warp/tests/test_runlength_encode.py +7 -7
  159. warp/tests/test_smoothstep.py +1 -1
  160. warp/tests/test_sparse.py +51 -2
  161. warp/tests/test_spatial.py +507 -1
  162. warp/tests/test_struct.py +2 -2
  163. warp/tests/test_tuple.py +265 -0
  164. warp/tests/test_types.py +2 -2
  165. warp/tests/test_utils.py +24 -18
  166. warp/tests/tile/test_tile.py +420 -1
  167. warp/tests/tile/test_tile_mathdx.py +518 -14
  168. warp/tests/tile/test_tile_reduce.py +213 -0
  169. warp/tests/tile/test_tile_shared_memory.py +130 -1
  170. warp/tests/tile/test_tile_sort.py +117 -0
  171. warp/tests/unittest_suites.py +4 -6
  172. warp/types.py +462 -308
  173. warp/utils.py +647 -86
  174. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/METADATA +20 -6
  175. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/RECORD +178 -166
  176. warp/stubs.py +0 -3381
  177. warp/tests/sim/test_xpbd.py +0 -399
  178. warp/tests/test_mlp.py +0 -282
  179. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/WHEEL +0 -0
  180. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/licenses/LICENSE.md +0 -0
  181. {warp_lang-1.7.2.dist-info → warp_lang-1.8.0.dist-info}/top_level.txt +0 -0
@@ -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),
@@ -1037,36 +1380,26 @@ def VBD_solve_trimesh_no_self_contact(
1037
1380
  edge_bending_properties: wp.array(dtype=float, ndim=2),
1038
1381
  adjacency: ForceElementAdjacencyInfo,
1039
1382
  # contact info
1040
- # self contact
1041
1383
  soft_contact_ke: float,
1384
+ soft_contact_kd: float,
1042
1385
  friction_mu: float,
1043
1386
  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
1387
  # ground-particle contact
1059
1388
  has_ground: bool,
1060
1389
  ground: wp.array(dtype=float),
1390
+ particle_radius: wp.array(dtype=float),
1391
+ # output
1392
+ pos_new: wp.array(dtype=wp.vec3),
1061
1393
  ):
1062
1394
  tid = wp.tid()
1063
1395
 
1064
1396
  particle_index = particle_ids_in_color[tid]
1397
+ particle_pos = pos[particle_index]
1065
1398
 
1066
1399
  if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
1400
+ pos_new[particle_index] = particle_pos
1067
1401
  return
1068
1402
 
1069
- particle_pos = pos[particle_index]
1070
1403
  particle_prev_pos = pos[particle_index]
1071
1404
 
1072
1405
  dt_sqr_reciprocal = 1.0 / (dt * dt)
@@ -1144,38 +1477,6 @@ def VBD_solve_trimesh_no_self_contact(
1144
1477
  f = f + f_edge
1145
1478
  h = h + h_edge
1146
1479
 
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
1480
  if has_ground:
1180
1481
  ground_normal = wp.vec3(ground[0], ground[1], ground[2])
1181
1482
  ground_level = ground[3]
@@ -1186,6 +1487,7 @@ def VBD_solve_trimesh_no_self_contact(
1186
1487
  ground_normal,
1187
1488
  ground_level,
1188
1489
  soft_contact_ke,
1490
+ soft_contact_kd,
1189
1491
  friction_mu,
1190
1492
  friction_epsilon,
1191
1493
  dt,
@@ -1244,40 +1546,28 @@ def convert_body_particle_contact_data_kernel(
1244
1546
 
1245
1547
 
1246
1548
  @wp.kernel
1247
- def VBD_solve_trimesh_with_self_contact_penetration_free(
1549
+ def VBD_accumulate_contact_force_and_hessian(
1550
+ # inputs
1248
1551
  dt: float,
1249
- particle_ids_in_color: wp.array(dtype=wp.int32),
1552
+ current_color: int,
1250
1553
  pos_prev: wp.array(dtype=wp.vec3),
1251
1554
  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),
1555
+ particle_colors: wp.array(dtype=int),
1257
1556
  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
1557
  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,
1558
+ # self contact
1559
+ collision_info_array: wp.array(dtype=TriMeshCollisionInfo),
1269
1560
  collision_radius: float,
1270
1561
  soft_contact_ke: float,
1562
+ soft_contact_kd: float,
1271
1563
  friction_mu: float,
1272
1564
  friction_epsilon: float,
1273
- pos_prev_collision_detection: wp.array(dtype=wp.vec3),
1274
- particle_conservative_bounds: wp.array(dtype=float),
1275
1565
  edge_edge_parallel_epsilon: float,
1276
- # body-particle contact
1566
+ # body-particle contact
1277
1567
  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),
1568
+ soft_contact_particle: wp.array(dtype=int),
1569
+ contact_count: wp.array(dtype=int),
1570
+ contact_max: int,
1281
1571
  shape_materials: ModelShapeMaterials,
1282
1572
  shape_body: wp.array(dtype=int),
1283
1573
  body_q: wp.array(dtype=wp.transform),
@@ -1287,9 +1577,235 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1287
1577
  contact_body_pos: wp.array(dtype=wp.vec3),
1288
1578
  contact_body_vel: wp.array(dtype=wp.vec3),
1289
1579
  contact_normal: wp.array(dtype=wp.vec3),
1580
+ # outputs: particle force and hessian
1581
+ particle_forces: wp.array(dtype=wp.vec3),
1582
+ particle_hessians: wp.array(dtype=wp.mat33),
1583
+ ):
1584
+ t_id = wp.tid()
1585
+ collision_info = collision_info_array[0]
1586
+
1587
+ # process edge-edge collisions
1588
+ if t_id * 2 < collision_info.edge_colliding_edges.shape[0]:
1589
+ e1_idx = collision_info.edge_colliding_edges[2 * t_id]
1590
+ e2_idx = collision_info.edge_colliding_edges[2 * t_id + 1]
1591
+
1592
+ if e1_idx != -1 and e2_idx != -1:
1593
+ e1_v1 = edge_indices[e1_idx, 2]
1594
+ e1_v2 = edge_indices[e1_idx, 3]
1595
+ if particle_colors[e1_v1] == current_color or particle_colors[e1_v2] == current_color:
1596
+ has_contact, collision_force_0, collision_force_1, collision_hessian_0, collision_hessian_1 = (
1597
+ evaluate_edge_edge_contact_2_vertices(
1598
+ e1_idx,
1599
+ e2_idx,
1600
+ pos,
1601
+ pos_prev,
1602
+ edge_indices,
1603
+ collision_radius,
1604
+ soft_contact_ke,
1605
+ soft_contact_kd,
1606
+ friction_mu,
1607
+ friction_epsilon,
1608
+ dt,
1609
+ edge_edge_parallel_epsilon,
1610
+ )
1611
+ )
1612
+
1613
+ if has_contact:
1614
+ # here we only handle the e1 side, because e2 will also detection this contact and add force and hessian on its own
1615
+ if particle_colors[e1_v1] == current_color:
1616
+ wp.atomic_add(particle_forces, e1_v1, collision_force_0)
1617
+ wp.atomic_add(particle_hessians, e1_v1, collision_hessian_0)
1618
+ if particle_colors[e1_v2] == current_color:
1619
+ wp.atomic_add(particle_forces, e1_v2, collision_force_1)
1620
+ wp.atomic_add(particle_hessians, e1_v2, collision_hessian_1)
1621
+
1622
+ # process vertex-triangle collisions
1623
+ if t_id * 2 < collision_info.vertex_colliding_triangles.shape[0]:
1624
+ particle_idx = collision_info.vertex_colliding_triangles[2 * t_id]
1625
+ tri_idx = collision_info.vertex_colliding_triangles[2 * t_id + 1]
1626
+
1627
+ if particle_idx != -1 and tri_idx != -1:
1628
+ tri_a = tri_indices[tri_idx, 0]
1629
+ tri_b = tri_indices[tri_idx, 1]
1630
+ tri_c = tri_indices[tri_idx, 2]
1631
+ if (
1632
+ particle_colors[particle_idx] == current_color
1633
+ or particle_colors[tri_a] == current_color
1634
+ or particle_colors[tri_b] == current_color
1635
+ or particle_colors[tri_c] == current_color
1636
+ ):
1637
+ (
1638
+ has_contact,
1639
+ collision_force_0,
1640
+ collision_force_1,
1641
+ collision_force_2,
1642
+ collision_force_3,
1643
+ collision_hessian_0,
1644
+ collision_hessian_1,
1645
+ collision_hessian_2,
1646
+ collision_hessian_3,
1647
+ ) = evaluate_vertex_triangle_collision_force_hessian_4_vertices(
1648
+ particle_idx,
1649
+ tri_idx,
1650
+ pos,
1651
+ pos_prev,
1652
+ tri_indices,
1653
+ collision_radius,
1654
+ soft_contact_ke,
1655
+ soft_contact_kd,
1656
+ friction_mu,
1657
+ friction_epsilon,
1658
+ dt,
1659
+ )
1660
+
1661
+ if has_contact:
1662
+ # particle
1663
+ if particle_colors[particle_idx] == current_color:
1664
+ wp.atomic_add(particle_forces, particle_idx, collision_force_3)
1665
+ wp.atomic_add(particle_hessians, particle_idx, collision_hessian_3)
1666
+
1667
+ # tri_a
1668
+ if particle_colors[tri_a] == current_color:
1669
+ wp.atomic_add(particle_forces, tri_a, collision_force_0)
1670
+ wp.atomic_add(particle_hessians, tri_a, collision_hessian_0)
1671
+
1672
+ # tri_b
1673
+ if particle_colors[tri_b] == current_color:
1674
+ wp.atomic_add(particle_forces, tri_b, collision_force_1)
1675
+ wp.atomic_add(particle_hessians, tri_b, collision_hessian_1)
1676
+
1677
+ # tri_c
1678
+ if particle_colors[tri_c] == current_color:
1679
+ wp.atomic_add(particle_forces, tri_c, collision_force_2)
1680
+ wp.atomic_add(particle_hessians, tri_c, collision_hessian_2)
1681
+
1682
+ particle_body_contact_count = min(contact_max, contact_count[0])
1683
+
1684
+ if t_id < particle_body_contact_count:
1685
+ particle_idx = soft_contact_particle[t_id]
1686
+
1687
+ if particle_colors[particle_idx] == current_color:
1688
+ body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
1689
+ particle_idx,
1690
+ pos[particle_idx],
1691
+ pos_prev[particle_idx],
1692
+ t_id,
1693
+ soft_contact_ke,
1694
+ soft_contact_kd,
1695
+ friction_mu,
1696
+ friction_epsilon,
1697
+ particle_radius,
1698
+ shape_materials,
1699
+ shape_body,
1700
+ body_q,
1701
+ body_qd,
1702
+ body_com,
1703
+ contact_shape,
1704
+ contact_body_pos,
1705
+ contact_body_vel,
1706
+ contact_normal,
1707
+ dt,
1708
+ )
1709
+ wp.atomic_add(particle_forces, particle_idx, body_contact_force)
1710
+ wp.atomic_add(particle_hessians, particle_idx, body_contact_hessian)
1711
+
1712
+
1713
+ @wp.kernel
1714
+ def VBD_accumulate_contact_force_and_hessian_no_self_contact(
1715
+ # inputs
1716
+ dt: float,
1717
+ current_color: int,
1718
+ pos_prev: wp.array(dtype=wp.vec3),
1719
+ pos: wp.array(dtype=wp.vec3),
1720
+ particle_colors: wp.array(dtype=int),
1721
+ # body-particle contact
1722
+ soft_contact_ke: float,
1723
+ soft_contact_kd: float,
1724
+ friction_mu: float,
1725
+ friction_epsilon: float,
1726
+ particle_radius: wp.array(dtype=float),
1727
+ soft_contact_particle: wp.array(dtype=int),
1728
+ contact_count: wp.array(dtype=int),
1729
+ contact_max: int,
1730
+ shape_materials: ModelShapeMaterials,
1731
+ shape_body: wp.array(dtype=int),
1732
+ body_q: wp.array(dtype=wp.transform),
1733
+ body_qd: wp.array(dtype=wp.spatial_vector),
1734
+ body_com: wp.array(dtype=wp.vec3),
1735
+ contact_shape: wp.array(dtype=int),
1736
+ contact_body_pos: wp.array(dtype=wp.vec3),
1737
+ contact_body_vel: wp.array(dtype=wp.vec3),
1738
+ contact_normal: wp.array(dtype=wp.vec3),
1739
+ # outputs: particle force and hessian
1740
+ particle_forces: wp.array(dtype=wp.vec3),
1741
+ particle_hessians: wp.array(dtype=wp.mat33),
1742
+ ):
1743
+ t_id = wp.tid()
1744
+
1745
+ particle_body_contact_count = min(contact_max, contact_count[0])
1746
+
1747
+ if t_id < particle_body_contact_count:
1748
+ particle_idx = soft_contact_particle[t_id]
1749
+
1750
+ if particle_colors[particle_idx] == current_color:
1751
+ body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
1752
+ particle_idx,
1753
+ pos[particle_idx],
1754
+ pos_prev[particle_idx],
1755
+ t_id,
1756
+ soft_contact_ke,
1757
+ soft_contact_kd,
1758
+ friction_mu,
1759
+ friction_epsilon,
1760
+ particle_radius,
1761
+ shape_materials,
1762
+ shape_body,
1763
+ body_q,
1764
+ body_qd,
1765
+ body_com,
1766
+ contact_shape,
1767
+ contact_body_pos,
1768
+ contact_body_vel,
1769
+ contact_normal,
1770
+ dt,
1771
+ )
1772
+ wp.atomic_add(particle_forces, particle_idx, body_contact_force)
1773
+ wp.atomic_add(particle_hessians, particle_idx, body_contact_hessian)
1774
+
1775
+
1776
+ @wp.kernel
1777
+ def VBD_solve_trimesh_with_self_contact_penetration_free(
1778
+ dt: float,
1779
+ particle_ids_in_color: wp.array(dtype=wp.int32),
1780
+ pos_prev: wp.array(dtype=wp.vec3),
1781
+ pos: wp.array(dtype=wp.vec3),
1782
+ vel: wp.array(dtype=wp.vec3),
1783
+ mass: wp.array(dtype=float),
1784
+ inertia: wp.array(dtype=wp.vec3),
1785
+ particle_flags: wp.array(dtype=wp.uint32),
1786
+ tri_indices: wp.array(dtype=wp.int32, ndim=2),
1787
+ tri_poses: wp.array(dtype=wp.mat22),
1788
+ tri_materials: wp.array(dtype=float, ndim=2),
1789
+ tri_areas: wp.array(dtype=float),
1790
+ edge_indices: wp.array(dtype=wp.int32, ndim=2),
1791
+ edge_rest_angles: wp.array(dtype=float),
1792
+ edge_rest_length: wp.array(dtype=float),
1793
+ edge_bending_properties: wp.array(dtype=float, ndim=2),
1794
+ adjacency: ForceElementAdjacencyInfo,
1795
+ particle_forces: wp.array(dtype=wp.vec3),
1796
+ particle_hessians: wp.array(dtype=wp.mat33),
1797
+ pos_prev_collision_detection: wp.array(dtype=wp.vec3),
1798
+ particle_conservative_bounds: wp.array(dtype=float),
1290
1799
  # ground-particle contact
1291
1800
  has_ground: bool,
1292
1801
  ground: wp.array(dtype=float),
1802
+ soft_contact_ke: float,
1803
+ soft_contact_kd: float,
1804
+ friction_mu: float,
1805
+ friction_epsilon: float,
1806
+ particle_radius: wp.array(dtype=float),
1807
+ # output
1808
+ pos_new: wp.array(dtype=wp.vec3),
1293
1809
  ):
1294
1810
  t_id = wp.tid()
1295
1811
 
@@ -1298,13 +1814,14 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1298
1814
  particle_prev_pos = pos_prev[particle_index]
1299
1815
 
1300
1816
  if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
1817
+ pos_new[particle_index] = particle_pos
1301
1818
  return
1302
1819
 
1303
1820
  dt_sqr_reciprocal = 1.0 / (dt * dt)
1304
1821
 
1305
1822
  # inertia force and hessian
1306
1823
  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)
1824
+ h = particle_hessians[particle_index] + mass[particle_index] * dt_sqr_reciprocal * wp.identity(n=3, dtype=float)
1308
1825
 
1309
1826
  # fmt: off
1310
1827
  if wp.static("inertia_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
@@ -1314,48 +1831,6 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1314
1831
  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
1832
  )
1316
1833
 
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
1834
  # elastic force and hessian
1360
1835
  for i_adj_tri in range(get_vertex_num_adjacent_faces(adjacency, particle_index)):
1361
1836
  tri_index, vertex_order = get_vertex_adjacent_face_id_order(adjacency, particle_index, i_adj_tri)
@@ -1391,41 +1866,12 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1391
1866
  k_d = tri_materials[tri_index, 2]
1392
1867
  h_d = h_tri * (k_d / dt)
1393
1868
 
1394
- f_d = h_d * (pos_prev[particle_index] - pos[particle_index])
1869
+ f_d = h_d * (particle_prev_pos - particle_pos)
1395
1870
 
1396
1871
  f = f + f_tri + f_d
1397
1872
  h = h + h_tri + h_d
1398
1873
 
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
1874
 
1428
- # edge-edge collision force and hessian
1429
1875
  for i_adj_edge in range(get_vertex_num_adjacent_edges(adjacency, particle_index)):
1430
1876
  nei_edge_index, vertex_order_on_edge = get_vertex_adjacent_edge_id_order(adjacency, particle_index, i_adj_edge)
1431
1877
  # vertex is on the edge; otherwise it only effects the bending energy n
@@ -1438,78 +1884,6 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1438
1884
  f = f + f_edge
1439
1885
  h = h + h_edge
1440
1886
 
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
1887
  if has_ground:
1514
1888
  ground_normal = wp.vec3(ground[0], ground[1], ground[2])
1515
1889
  ground_level = ground[3]
@@ -1520,6 +1894,7 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1520
1894
  ground_normal,
1521
1895
  ground_level,
1522
1896
  soft_contact_ke,
1897
+ soft_contact_kd,
1523
1898
  friction_mu,
1524
1899
  friction_epsilon,
1525
1900
  dt,
@@ -1535,9 +1910,12 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
1535
1910
  particle_index,
1536
1911
  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
1912
  )
1538
- # fmt: on
1539
1913
 
1914
+ # # fmt: on
1915
+ h = h + particle_hessians[particle_index]
1916
+ f = f + particle_forces[particle_index]
1540
1917
  if abs(wp.determinant(h)) > 1e-5:
1918
+
1541
1919
  h_inv = wp.inverse(h)
1542
1920
  particle_pos_new = pos[particle_index] + h_inv * f
1543
1921
 
@@ -1554,7 +1932,7 @@ class VBDIntegrator(Integrator):
1554
1932
 
1555
1933
  Note that VBDIntegrator's constructor requires a :class:`Model` object as input, so that it can do some precomputation and preallocate the space.
1556
1934
  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.
1935
+ Currently, you must manually provide particle coloring and assign it to `model.particle_color_groups` to make VBD work.
1558
1936
 
1559
1937
  VBDIntegrator.simulate accepts three arguments: class:`Model`, :class:`State`, and :class:`Control` (optional) objects, this time-integrator
1560
1938
  may be used to advance the simulation state forward in time.
@@ -1564,7 +1942,7 @@ class VBDIntegrator(Integrator):
1564
1942
 
1565
1943
  .. code-block:: python
1566
1944
 
1567
- model.particle_coloring = # load or generate particle coloring
1945
+ model.particle_color_groups = # load or generate particle coloring
1568
1946
  integrator = wp.VBDIntegrator(model)
1569
1947
 
1570
1948
  # simulation loop
@@ -1596,13 +1974,6 @@ class VBDIntegrator(Integrator):
1596
1974
 
1597
1975
  self.adjacency = self.compute_force_element_adjacency(model).to(self.device)
1598
1976
 
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
1977
  self.body_particle_contact_count = wp.zeros((model.particle_count,), dtype=wp.int32, device=self.device)
1607
1978
 
1608
1979
  self.handle_self_contact = handle_self_contact
@@ -1626,11 +1997,27 @@ class VBDIntegrator(Integrator):
1626
1997
  edge_edge_parallel_epsilon=edge_edge_parallel_epsilon,
1627
1998
  )
1628
1999
 
2000
+ self.trimesh_collision_info = wp.array(
2001
+ [self.trimesh_collision_detector.collision_info], dtype=TriMeshCollisionInfo, device=self.device
2002
+ )
2003
+
2004
+ self.collision_evaluation_kernel_launch_size = max(
2005
+ self.trimesh_collision_detector.vertex_colliding_triangles.shape[0] // 2,
2006
+ self.trimesh_collision_detector.edge_colliding_edges.shape[0] // 2,
2007
+ self.model.soft_contact_max,
2008
+ )
2009
+ else:
2010
+ self.collision_evaluation_kernel_launch_size = self.model.soft_contact_max
2011
+
2012
+ # spaces for particle force and hessian
2013
+ self.particle_forces = wp.zeros(self.model.particle_count, dtype=wp.vec3, device=self.device)
2014
+ self.particle_hessians = wp.zeros(self.model.particle_count, dtype=wp.mat33, device=self.device)
2015
+
1629
2016
  self.friction_epsilon = friction_epsilon
1630
2017
 
1631
- if len(self.model.particle_coloring) == 0:
2018
+ if len(self.model.particle_color_groups) == 0:
1632
2019
  raise ValueError(
1633
- "model.particle_coloring is empty! When using the VBDIntegrator you must call ModelBuilder.color() "
2020
+ "model.particle_color_groups is empty! When using the VBDIntegrator you must call ModelBuilder.color() "
1634
2021
  "or ModelBuilder.set_coloring() before calling ModelBuilder.finalize()."
1635
2022
  )
1636
2023
 
@@ -1733,8 +2120,6 @@ class VBDIntegrator(Integrator):
1733
2120
  def simulate_one_step_no_self_contact(
1734
2121
  self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None
1735
2122
  ):
1736
- self.convert_body_particle_contact_data()
1737
-
1738
2123
  wp.launch(
1739
2124
  kernel=forward_step,
1740
2125
  inputs=[
@@ -1753,15 +2138,46 @@ class VBDIntegrator(Integrator):
1753
2138
  )
1754
2139
 
1755
2140
  for _iter in range(self.iterations):
1756
- for color_counter in range(len(self.model.particle_coloring)):
2141
+ for color in range(len(self.model.particle_color_groups)):
2142
+ wp.launch(
2143
+ kernel=VBD_accumulate_contact_force_and_hessian_no_self_contact,
2144
+ dim=self.collision_evaluation_kernel_launch_size,
2145
+ inputs=[
2146
+ dt,
2147
+ color,
2148
+ self.particle_q_prev,
2149
+ state_in.particle_q,
2150
+ self.model.particle_colors,
2151
+ # body-particle contact
2152
+ self.model.soft_contact_ke,
2153
+ self.model.soft_contact_kd,
2154
+ self.model.soft_contact_mu,
2155
+ self.friction_epsilon,
2156
+ self.model.particle_radius,
2157
+ self.model.soft_contact_particle,
2158
+ self.model.soft_contact_count,
2159
+ self.model.soft_contact_max,
2160
+ self.model.shape_materials,
2161
+ self.model.shape_body,
2162
+ self.model.body_q,
2163
+ self.model.body_qd,
2164
+ self.model.body_com,
2165
+ self.model.soft_contact_shape,
2166
+ self.model.soft_contact_body_pos,
2167
+ self.model.soft_contact_body_vel,
2168
+ self.model.soft_contact_normal,
2169
+ ],
2170
+ outputs=[self.particle_forces, self.particle_hessians],
2171
+ device=self.device,
2172
+ )
2173
+
1757
2174
  wp.launch(
1758
2175
  kernel=VBD_solve_trimesh_no_self_contact,
1759
2176
  inputs=[
1760
2177
  dt,
1761
- self.model.particle_coloring[color_counter],
2178
+ self.model.particle_color_groups[color],
1762
2179
  self.particle_q_prev,
1763
2180
  state_in.particle_q,
1764
- state_out.particle_q,
1765
2181
  state_in.particle_qd,
1766
2182
  self.model.particle_mass,
1767
2183
  self.inertia,
@@ -1776,33 +2192,25 @@ class VBDIntegrator(Integrator):
1776
2192
  self.model.edge_bending_properties,
1777
2193
  self.adjacency,
1778
2194
  self.model.soft_contact_ke,
2195
+ self.model.soft_contact_kd,
1779
2196
  self.model.soft_contact_mu,
1780
2197
  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,
2198
+ # ground-particle contact
1795
2199
  self.model.ground,
1796
2200
  self.model.ground_plane,
2201
+ self.model.particle_radius,
2202
+ ],
2203
+ outputs=[
2204
+ state_out.particle_q,
1797
2205
  ],
1798
- dim=self.model.particle_coloring[color_counter].size,
2206
+ dim=self.model.particle_color_groups[color].size,
1799
2207
  device=self.device,
1800
2208
  )
1801
2209
 
1802
2210
  wp.launch(
1803
2211
  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,
2212
+ inputs=[self.model.particle_color_groups[color], state_in.particle_q, state_out.particle_q],
2213
+ dim=self.model.particle_color_groups[color].size,
1806
2214
  device=self.device,
1807
2215
  )
1808
2216
 
@@ -1816,7 +2224,6 @@ class VBDIntegrator(Integrator):
1816
2224
  def simulate_one_step_with_collisions_penetration_free(
1817
2225
  self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None
1818
2226
  ):
1819
- self.convert_body_particle_contact_data()
1820
2227
  # collision detection before initialization to compute conservative bounds for initialization
1821
2228
  self.collision_detection_penetration_free(state_in, dt)
1822
2229
 
@@ -1843,42 +2250,34 @@ class VBDIntegrator(Integrator):
1843
2250
  self.collision_detection_penetration_free(state_in, dt)
1844
2251
 
1845
2252
  for _iter in range(self.iterations):
1846
- for i_color in range(len(self.model.particle_coloring)):
2253
+ self.particle_forces.zero_()
2254
+ self.particle_hessians.zero_()
2255
+
2256
+ for color in range(len(self.model.particle_color_groups)):
1847
2257
  wp.launch(
1848
- kernel=VBD_solve_trimesh_with_self_contact_penetration_free,
2258
+ kernel=VBD_accumulate_contact_force_and_hessian,
2259
+ dim=self.collision_evaluation_kernel_launch_size,
1849
2260
  inputs=[
1850
2261
  dt,
1851
- self.model.particle_coloring[i_color],
2262
+ color,
1852
2263
  self.particle_q_prev,
1853
2264
  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,
2265
+ self.model.particle_colors,
1859
2266
  self.model.tri_indices,
1860
- self.model.tri_poses,
1861
- self.model.tri_materials,
1862
- self.model.tri_areas,
1863
2267
  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,
2268
+ # self-contact
2269
+ self.trimesh_collision_info,
1870
2270
  self.model.soft_contact_radius,
1871
2271
  self.model.soft_contact_ke,
2272
+ self.model.soft_contact_kd,
1872
2273
  self.model.soft_contact_mu,
1873
2274
  self.friction_epsilon,
1874
- self.pos_prev_collision_detection,
1875
- self.particle_conservative_bounds,
1876
2275
  self.trimesh_collision_detector.edge_edge_parallel_epsilon,
1877
- # body-particle contact
2276
+ # body-particle contact
1878
2277
  self.model.particle_radius,
1879
- self.body_particle_contact_buffer_pre_alloc,
1880
- self.body_particle_contact_buffer,
1881
- self.body_particle_contact_count,
2278
+ self.model.soft_contact_particle,
2279
+ self.model.soft_contact_count,
2280
+ self.model.soft_contact_max,
1882
2281
  self.model.shape_materials,
1883
2282
  self.model.shape_body,
1884
2283
  self.model.body_q,
@@ -1888,17 +2287,54 @@ class VBDIntegrator(Integrator):
1888
2287
  self.model.soft_contact_body_pos,
1889
2288
  self.model.soft_contact_body_vel,
1890
2289
  self.model.soft_contact_normal,
2290
+ ],
2291
+ outputs=[self.particle_forces, self.particle_hessians],
2292
+ device=self.device,
2293
+ )
2294
+
2295
+ wp.launch(
2296
+ kernel=VBD_solve_trimesh_with_self_contact_penetration_free,
2297
+ dim=self.model.particle_color_groups[color].shape[0],
2298
+ inputs=[
2299
+ dt,
2300
+ self.model.particle_color_groups[color],
2301
+ self.particle_q_prev,
2302
+ state_in.particle_q,
2303
+ state_in.particle_qd,
2304
+ self.model.particle_mass,
2305
+ self.inertia,
2306
+ self.model.particle_flags,
2307
+ self.model.tri_indices,
2308
+ self.model.tri_poses,
2309
+ self.model.tri_materials,
2310
+ self.model.tri_areas,
2311
+ self.model.edge_indices,
2312
+ self.model.edge_rest_angle,
2313
+ self.model.edge_rest_length,
2314
+ self.model.edge_bending_properties,
2315
+ self.adjacency,
2316
+ self.particle_forces,
2317
+ self.particle_hessians,
2318
+ self.pos_prev_collision_detection,
2319
+ self.particle_conservative_bounds,
1891
2320
  self.model.ground,
1892
2321
  self.model.ground_plane,
2322
+ self.model.soft_contact_ke,
2323
+ self.model.soft_contact_kd,
2324
+ self.model.soft_contact_mu,
2325
+ self.friction_epsilon,
2326
+ self.model.particle_radius,
2327
+ ],
2328
+ outputs=[
2329
+ state_out.particle_q,
1893
2330
  ],
1894
- dim=self.model.particle_coloring[i_color].shape[0],
1895
2331
  device=self.device,
1896
2332
  )
1897
2333
 
1898
2334
  wp.launch(
1899
2335
  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,
2336
+ inputs=[self.model.particle_color_groups[color], state_in.particle_q, state_out.particle_q],
2337
+ dim=self.model.particle_color_groups[color].size,
1902
2338
  device=self.device,
1903
2339
  )
1904
2340
 
@@ -1930,21 +2366,16 @@ class VBDIntegrator(Integrator):
1930
2366
  device=self.device,
1931
2367
  )
1932
2368
 
1933
- def convert_body_particle_contact_data(self):
1934
- self.body_particle_contact_count.zero_()
2369
+ def rebuild_bvh(self, state: State):
2370
+ """This function will rebuild the BVHs used for detecting self-contacts using the input `state`.
1935
2371
 
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
- )
2372
+ When the simulated object deforms significantly, simply refitting the BVH can lead to deterioration of the BVH's
2373
+ quality. In these cases, rebuilding the entire tree is necessary to achieve better querying efficiency.
2374
+
2375
+ Args:
2376
+ state (wp.sim.State): The state whose particle positions (:attr:`State.particle_q`) will be used for rebuilding the BVHs.
2377
+ """
2378
+ self.trimesh_collision_detector.rebuild(state.particle_q)
1948
2379
 
1949
2380
  @wp.kernel
1950
2381
  def count_num_adjacent_edges(