warp-lang 1.9.0__py3-none-win_amd64.whl → 1.10.0rc2__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 (350) hide show
  1. warp/__init__.py +301 -287
  2. warp/__init__.pyi +2220 -313
  3. warp/_src/__init__.py +14 -0
  4. warp/_src/autograd.py +1075 -0
  5. warp/_src/build.py +618 -0
  6. warp/_src/build_dll.py +640 -0
  7. warp/{builtins.py → _src/builtins.py} +1497 -226
  8. warp/_src/codegen.py +4359 -0
  9. warp/{config.py → _src/config.py} +178 -169
  10. warp/_src/constants.py +57 -0
  11. warp/_src/context.py +8294 -0
  12. warp/_src/dlpack.py +462 -0
  13. warp/_src/fabric.py +355 -0
  14. warp/_src/fem/__init__.py +14 -0
  15. warp/_src/fem/adaptivity.py +508 -0
  16. warp/_src/fem/cache.py +687 -0
  17. warp/_src/fem/dirichlet.py +188 -0
  18. warp/{fem → _src/fem}/domain.py +40 -30
  19. warp/_src/fem/field/__init__.py +131 -0
  20. warp/_src/fem/field/field.py +701 -0
  21. warp/{fem → _src/fem}/field/nodal_field.py +30 -15
  22. warp/{fem → _src/fem}/field/restriction.py +1 -1
  23. warp/{fem → _src/fem}/field/virtual.py +53 -27
  24. warp/_src/fem/geometry/__init__.py +32 -0
  25. warp/{fem → _src/fem}/geometry/adaptive_nanogrid.py +77 -163
  26. warp/_src/fem/geometry/closest_point.py +97 -0
  27. warp/{fem → _src/fem}/geometry/deformed_geometry.py +14 -22
  28. warp/{fem → _src/fem}/geometry/element.py +32 -10
  29. warp/{fem → _src/fem}/geometry/geometry.py +48 -20
  30. warp/{fem → _src/fem}/geometry/grid_2d.py +12 -23
  31. warp/{fem → _src/fem}/geometry/grid_3d.py +12 -23
  32. warp/{fem → _src/fem}/geometry/hexmesh.py +40 -63
  33. warp/{fem → _src/fem}/geometry/nanogrid.py +255 -248
  34. warp/{fem → _src/fem}/geometry/partition.py +121 -63
  35. warp/{fem → _src/fem}/geometry/quadmesh.py +26 -45
  36. warp/{fem → _src/fem}/geometry/tetmesh.py +40 -63
  37. warp/{fem → _src/fem}/geometry/trimesh.py +26 -45
  38. warp/{fem → _src/fem}/integrate.py +164 -158
  39. warp/_src/fem/linalg.py +383 -0
  40. warp/_src/fem/operator.py +396 -0
  41. warp/_src/fem/polynomial.py +229 -0
  42. warp/{fem → _src/fem}/quadrature/pic_quadrature.py +15 -20
  43. warp/{fem → _src/fem}/quadrature/quadrature.py +95 -47
  44. warp/_src/fem/space/__init__.py +248 -0
  45. warp/{fem → _src/fem}/space/basis_function_space.py +20 -11
  46. warp/_src/fem/space/basis_space.py +679 -0
  47. warp/{fem → _src/fem}/space/dof_mapper.py +3 -3
  48. warp/{fem → _src/fem}/space/function_space.py +14 -13
  49. warp/{fem → _src/fem}/space/grid_2d_function_space.py +4 -7
  50. warp/{fem → _src/fem}/space/grid_3d_function_space.py +4 -4
  51. warp/{fem → _src/fem}/space/hexmesh_function_space.py +4 -10
  52. warp/{fem → _src/fem}/space/nanogrid_function_space.py +3 -9
  53. warp/{fem → _src/fem}/space/partition.py +117 -60
  54. warp/{fem → _src/fem}/space/quadmesh_function_space.py +4 -10
  55. warp/{fem → _src/fem}/space/restriction.py +66 -33
  56. warp/_src/fem/space/shape/__init__.py +152 -0
  57. warp/{fem → _src/fem}/space/shape/cube_shape_function.py +9 -9
  58. warp/{fem → _src/fem}/space/shape/shape_function.py +8 -9
  59. warp/{fem → _src/fem}/space/shape/square_shape_function.py +6 -6
  60. warp/{fem → _src/fem}/space/shape/tet_shape_function.py +3 -3
  61. warp/{fem → _src/fem}/space/shape/triangle_shape_function.py +3 -3
  62. warp/{fem → _src/fem}/space/tetmesh_function_space.py +3 -9
  63. warp/_src/fem/space/topology.py +459 -0
  64. warp/{fem → _src/fem}/space/trimesh_function_space.py +3 -9
  65. warp/_src/fem/types.py +112 -0
  66. warp/_src/fem/utils.py +486 -0
  67. warp/_src/jax.py +186 -0
  68. warp/_src/jax_experimental/__init__.py +14 -0
  69. warp/_src/jax_experimental/custom_call.py +387 -0
  70. warp/_src/jax_experimental/ffi.py +1284 -0
  71. warp/_src/jax_experimental/xla_ffi.py +656 -0
  72. warp/_src/marching_cubes.py +708 -0
  73. warp/_src/math.py +414 -0
  74. warp/_src/optim/__init__.py +14 -0
  75. warp/_src/optim/adam.py +163 -0
  76. warp/_src/optim/linear.py +1606 -0
  77. warp/_src/optim/sgd.py +112 -0
  78. warp/_src/paddle.py +406 -0
  79. warp/_src/render/__init__.py +14 -0
  80. warp/_src/render/imgui_manager.py +289 -0
  81. warp/_src/render/render_opengl.py +3636 -0
  82. warp/_src/render/render_usd.py +937 -0
  83. warp/_src/render/utils.py +160 -0
  84. warp/_src/sparse.py +2716 -0
  85. warp/_src/tape.py +1206 -0
  86. warp/{thirdparty → _src/thirdparty}/unittest_parallel.py +9 -2
  87. warp/_src/torch.py +391 -0
  88. warp/_src/types.py +5870 -0
  89. warp/_src/utils.py +1693 -0
  90. warp/autograd.py +12 -1054
  91. warp/bin/warp-clang.dll +0 -0
  92. warp/bin/warp.dll +0 -0
  93. warp/build.py +8 -588
  94. warp/build_dll.py +6 -471
  95. warp/codegen.py +6 -4246
  96. warp/constants.py +6 -39
  97. warp/context.py +12 -7851
  98. warp/dlpack.py +6 -444
  99. warp/examples/distributed/example_jacobi_mpi.py +4 -5
  100. warp/examples/fem/example_adaptive_grid.py +1 -1
  101. warp/examples/fem/example_apic_fluid.py +1 -1
  102. warp/examples/fem/example_burgers.py +8 -8
  103. warp/examples/fem/example_diffusion.py +1 -1
  104. warp/examples/fem/example_distortion_energy.py +1 -1
  105. warp/examples/fem/example_mixed_elasticity.py +2 -2
  106. warp/examples/fem/example_navier_stokes.py +1 -1
  107. warp/examples/fem/example_nonconforming_contact.py +7 -7
  108. warp/examples/fem/example_stokes.py +1 -1
  109. warp/examples/fem/example_stokes_transfer.py +1 -1
  110. warp/examples/fem/utils.py +2 -2
  111. warp/examples/interop/example_jax_callable.py +1 -1
  112. warp/examples/interop/example_jax_ffi_callback.py +1 -1
  113. warp/examples/interop/example_jax_kernel.py +3 -2
  114. warp/examples/tile/example_tile_mcgp.py +191 -0
  115. warp/fabric.py +6 -337
  116. warp/fem/__init__.py +159 -97
  117. warp/fem/adaptivity.py +7 -489
  118. warp/fem/cache.py +9 -648
  119. warp/fem/dirichlet.py +6 -184
  120. warp/fem/field/__init__.py +8 -109
  121. warp/fem/field/field.py +7 -652
  122. warp/fem/geometry/__init__.py +7 -18
  123. warp/fem/geometry/closest_point.py +11 -77
  124. warp/fem/linalg.py +18 -366
  125. warp/fem/operator.py +11 -369
  126. warp/fem/polynomial.py +9 -209
  127. warp/fem/space/__init__.py +5 -211
  128. warp/fem/space/basis_space.py +6 -662
  129. warp/fem/space/shape/__init__.py +41 -118
  130. warp/fem/space/topology.py +6 -437
  131. warp/fem/types.py +6 -81
  132. warp/fem/utils.py +11 -444
  133. warp/jax.py +8 -165
  134. warp/jax_experimental/__init__.py +14 -1
  135. warp/jax_experimental/custom_call.py +8 -342
  136. warp/jax_experimental/ffi.py +17 -853
  137. warp/jax_experimental/xla_ffi.py +5 -596
  138. warp/marching_cubes.py +5 -689
  139. warp/math.py +16 -393
  140. warp/native/array.h +385 -37
  141. warp/native/builtin.h +316 -39
  142. warp/native/bvh.cpp +43 -9
  143. warp/native/bvh.cu +62 -27
  144. warp/native/bvh.h +310 -309
  145. warp/native/clang/clang.cpp +102 -97
  146. warp/native/coloring.cpp +0 -1
  147. warp/native/crt.h +208 -0
  148. warp/native/exports.h +156 -0
  149. warp/native/hashgrid.cu +2 -0
  150. warp/native/intersect.h +24 -1
  151. warp/native/intersect_tri.h +44 -35
  152. warp/native/mat.h +1456 -276
  153. warp/native/mesh.cpp +4 -4
  154. warp/native/mesh.cu +4 -2
  155. warp/native/mesh.h +176 -61
  156. warp/native/quat.h +0 -52
  157. warp/native/scan.cu +2 -0
  158. warp/native/sort.cu +22 -13
  159. warp/native/sort.h +2 -0
  160. warp/native/sparse.cu +7 -3
  161. warp/native/spatial.h +12 -0
  162. warp/native/tile.h +837 -70
  163. warp/native/tile_radix_sort.h +1 -1
  164. warp/native/tile_reduce.h +394 -46
  165. warp/native/tile_scan.h +4 -4
  166. warp/native/vec.h +469 -53
  167. warp/native/version.h +23 -0
  168. warp/native/volume.cpp +1 -1
  169. warp/native/volume.cu +1 -0
  170. warp/native/volume.h +1 -1
  171. warp/native/volume_builder.cu +2 -0
  172. warp/native/warp.cpp +60 -32
  173. warp/native/warp.cu +313 -201
  174. warp/native/warp.h +14 -11
  175. warp/optim/__init__.py +6 -3
  176. warp/optim/adam.py +6 -145
  177. warp/optim/linear.py +14 -1585
  178. warp/optim/sgd.py +6 -94
  179. warp/paddle.py +6 -388
  180. warp/render/__init__.py +8 -4
  181. warp/render/imgui_manager.py +7 -267
  182. warp/render/render_opengl.py +6 -3616
  183. warp/render/render_usd.py +6 -918
  184. warp/render/utils.py +6 -142
  185. warp/sparse.py +37 -2563
  186. warp/tape.py +6 -1188
  187. warp/tests/__main__.py +1 -1
  188. warp/tests/cuda/test_async.py +4 -4
  189. warp/tests/cuda/test_conditional_captures.py +1 -1
  190. warp/tests/cuda/test_multigpu.py +1 -1
  191. warp/tests/cuda/test_streams.py +58 -1
  192. warp/tests/geometry/test_bvh.py +157 -22
  193. warp/tests/geometry/test_hash_grid.py +38 -0
  194. warp/tests/geometry/test_marching_cubes.py +0 -1
  195. warp/tests/geometry/test_mesh.py +5 -3
  196. warp/tests/geometry/test_mesh_query_aabb.py +5 -12
  197. warp/tests/geometry/test_mesh_query_point.py +5 -2
  198. warp/tests/geometry/test_mesh_query_ray.py +15 -3
  199. warp/tests/geometry/test_volume_write.py +5 -5
  200. warp/tests/interop/test_dlpack.py +14 -14
  201. warp/tests/interop/test_jax.py +1382 -79
  202. warp/tests/interop/test_paddle.py +1 -1
  203. warp/tests/test_adam.py +0 -1
  204. warp/tests/test_arithmetic.py +9 -9
  205. warp/tests/test_array.py +529 -100
  206. warp/tests/test_array_reduce.py +3 -3
  207. warp/tests/test_atomic.py +12 -8
  208. warp/tests/test_atomic_bitwise.py +209 -0
  209. warp/tests/test_atomic_cas.py +4 -4
  210. warp/tests/test_bool.py +2 -2
  211. warp/tests/test_builtins_resolution.py +5 -571
  212. warp/tests/test_codegen.py +34 -15
  213. warp/tests/test_conditional.py +1 -1
  214. warp/tests/test_context.py +6 -6
  215. warp/tests/test_copy.py +242 -161
  216. warp/tests/test_ctypes.py +3 -3
  217. warp/tests/test_devices.py +24 -2
  218. warp/tests/test_examples.py +16 -84
  219. warp/tests/test_fabricarray.py +35 -35
  220. warp/tests/test_fast_math.py +0 -2
  221. warp/tests/test_fem.py +60 -14
  222. warp/tests/test_fixedarray.py +3 -3
  223. warp/tests/test_func.py +8 -5
  224. warp/tests/test_generics.py +1 -1
  225. warp/tests/test_indexedarray.py +24 -24
  226. warp/tests/test_intersect.py +39 -9
  227. warp/tests/test_large.py +1 -1
  228. warp/tests/test_lerp.py +3 -1
  229. warp/tests/test_linear_solvers.py +1 -1
  230. warp/tests/test_map.py +49 -4
  231. warp/tests/test_mat.py +52 -62
  232. warp/tests/test_mat_constructors.py +4 -5
  233. warp/tests/test_mat_lite.py +1 -1
  234. warp/tests/test_mat_scalar_ops.py +121 -121
  235. warp/tests/test_math.py +34 -0
  236. warp/tests/test_module_aot.py +4 -4
  237. warp/tests/test_modules_lite.py +28 -2
  238. warp/tests/test_print.py +11 -11
  239. warp/tests/test_quat.py +93 -58
  240. warp/tests/test_runlength_encode.py +1 -1
  241. warp/tests/test_scalar_ops.py +38 -10
  242. warp/tests/test_smoothstep.py +1 -1
  243. warp/tests/test_sparse.py +126 -15
  244. warp/tests/test_spatial.py +105 -87
  245. warp/tests/test_special_values.py +6 -6
  246. warp/tests/test_static.py +7 -7
  247. warp/tests/test_struct.py +13 -2
  248. warp/tests/test_triangle_closest_point.py +48 -1
  249. warp/tests/test_tuple.py +96 -0
  250. warp/tests/test_types.py +82 -9
  251. warp/tests/test_utils.py +52 -52
  252. warp/tests/test_vec.py +29 -29
  253. warp/tests/test_vec_constructors.py +5 -5
  254. warp/tests/test_vec_scalar_ops.py +97 -97
  255. warp/tests/test_version.py +75 -0
  256. warp/tests/tile/test_tile.py +239 -0
  257. warp/tests/tile/test_tile_atomic_bitwise.py +403 -0
  258. warp/tests/tile/test_tile_cholesky.py +7 -4
  259. warp/tests/tile/test_tile_load.py +26 -2
  260. warp/tests/tile/test_tile_mathdx.py +3 -3
  261. warp/tests/tile/test_tile_matmul.py +1 -1
  262. warp/tests/tile/test_tile_mlp.py +2 -4
  263. warp/tests/tile/test_tile_reduce.py +214 -13
  264. warp/tests/unittest_suites.py +6 -14
  265. warp/tests/unittest_utils.py +10 -9
  266. warp/tests/walkthrough_debug.py +3 -1
  267. warp/torch.py +6 -373
  268. warp/types.py +29 -5750
  269. warp/utils.py +10 -1659
  270. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/METADATA +47 -103
  271. warp_lang-1.10.0rc2.dist-info/RECORD +468 -0
  272. warp_lang-1.10.0rc2.dist-info/licenses/licenses/Gaia-LICENSE.txt +6 -0
  273. warp_lang-1.10.0rc2.dist-info/licenses/licenses/appdirs-LICENSE.txt +22 -0
  274. warp_lang-1.10.0rc2.dist-info/licenses/licenses/asset_pixel_jpg-LICENSE.txt +3 -0
  275. warp_lang-1.10.0rc2.dist-info/licenses/licenses/cuda-LICENSE.txt +1582 -0
  276. warp_lang-1.10.0rc2.dist-info/licenses/licenses/dlpack-LICENSE.txt +201 -0
  277. warp_lang-1.10.0rc2.dist-info/licenses/licenses/fp16-LICENSE.txt +28 -0
  278. warp_lang-1.10.0rc2.dist-info/licenses/licenses/libmathdx-LICENSE.txt +220 -0
  279. warp_lang-1.10.0rc2.dist-info/licenses/licenses/llvm-LICENSE.txt +279 -0
  280. warp_lang-1.10.0rc2.dist-info/licenses/licenses/moller-LICENSE.txt +16 -0
  281. warp_lang-1.10.0rc2.dist-info/licenses/licenses/nanovdb-LICENSE.txt +2 -0
  282. warp_lang-1.10.0rc2.dist-info/licenses/licenses/nvrtc-LICENSE.txt +1592 -0
  283. warp_lang-1.10.0rc2.dist-info/licenses/licenses/svd-LICENSE.txt +23 -0
  284. warp_lang-1.10.0rc2.dist-info/licenses/licenses/unittest_parallel-LICENSE.txt +21 -0
  285. warp_lang-1.10.0rc2.dist-info/licenses/licenses/usd-LICENSE.txt +213 -0
  286. warp_lang-1.10.0rc2.dist-info/licenses/licenses/windingnumber-LICENSE.txt +21 -0
  287. warp/examples/assets/cartpole.urdf +0 -110
  288. warp/examples/assets/crazyflie.usd +0 -0
  289. warp/examples/assets/nv_ant.xml +0 -92
  290. warp/examples/assets/nv_humanoid.xml +0 -183
  291. warp/examples/assets/quadruped.urdf +0 -268
  292. warp/examples/optim/example_bounce.py +0 -266
  293. warp/examples/optim/example_cloth_throw.py +0 -228
  294. warp/examples/optim/example_drone.py +0 -870
  295. warp/examples/optim/example_inverse_kinematics.py +0 -182
  296. warp/examples/optim/example_inverse_kinematics_torch.py +0 -191
  297. warp/examples/optim/example_softbody_properties.py +0 -400
  298. warp/examples/optim/example_spring_cage.py +0 -245
  299. warp/examples/optim/example_trajectory.py +0 -227
  300. warp/examples/sim/example_cartpole.py +0 -143
  301. warp/examples/sim/example_cloth.py +0 -225
  302. warp/examples/sim/example_cloth_self_contact.py +0 -316
  303. warp/examples/sim/example_granular.py +0 -130
  304. warp/examples/sim/example_granular_collision_sdf.py +0 -202
  305. warp/examples/sim/example_jacobian_ik.py +0 -244
  306. warp/examples/sim/example_particle_chain.py +0 -124
  307. warp/examples/sim/example_quadruped.py +0 -203
  308. warp/examples/sim/example_rigid_chain.py +0 -203
  309. warp/examples/sim/example_rigid_contact.py +0 -195
  310. warp/examples/sim/example_rigid_force.py +0 -133
  311. warp/examples/sim/example_rigid_gyroscopic.py +0 -115
  312. warp/examples/sim/example_rigid_soft_contact.py +0 -140
  313. warp/examples/sim/example_soft_body.py +0 -196
  314. warp/examples/tile/example_tile_walker.py +0 -327
  315. warp/sim/__init__.py +0 -74
  316. warp/sim/articulation.py +0 -793
  317. warp/sim/collide.py +0 -2570
  318. warp/sim/graph_coloring.py +0 -307
  319. warp/sim/import_mjcf.py +0 -791
  320. warp/sim/import_snu.py +0 -227
  321. warp/sim/import_urdf.py +0 -579
  322. warp/sim/import_usd.py +0 -898
  323. warp/sim/inertia.py +0 -357
  324. warp/sim/integrator.py +0 -245
  325. warp/sim/integrator_euler.py +0 -2000
  326. warp/sim/integrator_featherstone.py +0 -2101
  327. warp/sim/integrator_vbd.py +0 -2487
  328. warp/sim/integrator_xpbd.py +0 -3295
  329. warp/sim/model.py +0 -4821
  330. warp/sim/particles.py +0 -121
  331. warp/sim/render.py +0 -431
  332. warp/sim/utils.py +0 -431
  333. warp/tests/sim/disabled_kinematics.py +0 -244
  334. warp/tests/sim/test_cloth.py +0 -863
  335. warp/tests/sim/test_collision.py +0 -743
  336. warp/tests/sim/test_coloring.py +0 -347
  337. warp/tests/sim/test_inertia.py +0 -161
  338. warp/tests/sim/test_model.py +0 -226
  339. warp/tests/sim/test_sim_grad.py +0 -287
  340. warp/tests/sim/test_sim_grad_bounce_linear.py +0 -212
  341. warp/tests/sim/test_sim_kinematics.py +0 -98
  342. warp/thirdparty/__init__.py +0 -0
  343. warp_lang-1.9.0.dist-info/RECORD +0 -456
  344. /warp/{fem → _src/fem}/quadrature/__init__.py +0 -0
  345. /warp/{tests/sim → _src/thirdparty}/__init__.py +0 -0
  346. /warp/{thirdparty → _src/thirdparty}/appdirs.py +0 -0
  347. /warp/{thirdparty → _src/thirdparty}/dlpack.py +0 -0
  348. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/WHEEL +0 -0
  349. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/licenses/LICENSE.md +0 -0
  350. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/top_level.txt +0 -0
@@ -1,2000 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
- # SPDX-License-Identifier: Apache-2.0
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- """This module contains time-integration objects for simulating
17
- models + state forward in time.
18
-
19
- """
20
-
21
- import warp as wp
22
-
23
- from .collide import triangle_closest_point_barycentric
24
- from .integrator import Integrator
25
- from .model import PARTICLE_FLAG_ACTIVE, Control, Model, ModelShapeGeometry, ModelShapeMaterials, State
26
- from .particles import eval_particle_forces
27
- from .utils import quat_decompose, quat_twist
28
-
29
-
30
- @wp.kernel
31
- def eval_springs(
32
- x: wp.array(dtype=wp.vec3),
33
- v: wp.array(dtype=wp.vec3),
34
- spring_indices: wp.array(dtype=int),
35
- spring_rest_lengths: wp.array(dtype=float),
36
- spring_stiffness: wp.array(dtype=float),
37
- spring_damping: wp.array(dtype=float),
38
- f: wp.array(dtype=wp.vec3),
39
- ):
40
- tid = wp.tid()
41
-
42
- i = spring_indices[tid * 2 + 0]
43
- j = spring_indices[tid * 2 + 1]
44
-
45
- if i == -1 or j == -1:
46
- return
47
-
48
- ke = spring_stiffness[tid]
49
- kd = spring_damping[tid]
50
- rest = spring_rest_lengths[tid]
51
-
52
- xi = x[i]
53
- xj = x[j]
54
-
55
- vi = v[i]
56
- vj = v[j]
57
-
58
- xij = xi - xj
59
- vij = vi - vj
60
-
61
- l = wp.length(xij)
62
- l_inv = 1.0 / l
63
-
64
- # normalized spring direction
65
- dir = xij * l_inv
66
-
67
- c = l - rest
68
- dcdt = wp.dot(dir, vij)
69
-
70
- # damping based on relative velocity
71
- fs = dir * (ke * c + kd * dcdt)
72
-
73
- wp.atomic_sub(f, i, fs)
74
- wp.atomic_add(f, j, fs)
75
-
76
-
77
- @wp.kernel
78
- def eval_triangles(
79
- x: wp.array(dtype=wp.vec3),
80
- v: wp.array(dtype=wp.vec3),
81
- indices: wp.array2d(dtype=int),
82
- pose: wp.array(dtype=wp.mat22),
83
- activation: wp.array(dtype=float),
84
- materials: wp.array2d(dtype=float),
85
- f: wp.array(dtype=wp.vec3),
86
- ):
87
- tid = wp.tid()
88
-
89
- k_mu = materials[tid, 0]
90
- k_lambda = materials[tid, 1]
91
- k_damp = materials[tid, 2]
92
- k_drag = materials[tid, 3]
93
- k_lift = materials[tid, 4]
94
-
95
- i = indices[tid, 0]
96
- j = indices[tid, 1]
97
- k = indices[tid, 2]
98
-
99
- x0 = x[i] # point zero
100
- x1 = x[j] # point one
101
- x2 = x[k] # point two
102
-
103
- v0 = v[i] # vel zero
104
- v1 = v[j] # vel one
105
- v2 = v[k] # vel two
106
-
107
- x10 = x1 - x0 # barycentric coordinates (centered at p)
108
- x20 = x2 - x0
109
-
110
- v10 = v1 - v0
111
- v20 = v2 - v0
112
-
113
- Dm = pose[tid]
114
-
115
- inv_rest_area = wp.determinant(Dm) * 2.0 # 1 / det(A) = det(A^-1)
116
- rest_area = 1.0 / inv_rest_area
117
-
118
- # scale stiffness coefficients to account for area
119
- k_mu = k_mu * rest_area
120
- k_lambda = k_lambda * rest_area
121
- k_damp = k_damp * rest_area
122
-
123
- # F = Xs*Xm^-1
124
- F1 = x10 * Dm[0, 0] + x20 * Dm[1, 0]
125
- F2 = x10 * Dm[0, 1] + x20 * Dm[1, 1]
126
-
127
- # dFdt = Vs*Xm^-1
128
- dFdt1 = v10 * Dm[0, 0] + v20 * Dm[1, 0]
129
- dFdt2 = v10 * Dm[0, 1] + v20 * Dm[1, 1]
130
-
131
- # deviatoric PK1 + damping term
132
- P1 = F1 * k_mu + dFdt1 * k_damp
133
- P2 = F2 * k_mu + dFdt2 * k_damp
134
-
135
- # -----------------------------
136
- # St. Venant-Kirchoff
137
-
138
- # # Green strain, F'*F-I
139
- # e00 = dot(f1, f1) - 1.0
140
- # e10 = dot(f2, f1)
141
- # e01 = dot(f1, f2)
142
- # e11 = dot(f2, f2) - 1.0
143
-
144
- # E = wp.mat22(e00, e01,
145
- # e10, e11)
146
-
147
- # # local forces (deviatoric part)
148
- # T = wp.mul(E, wp.transpose(Dm))
149
-
150
- # # spatial forces, F*T
151
- # fq = (f1*T[0,0] + f2*T[1,0])*k_mu*2.0
152
- # fr = (f1*T[0,1] + f2*T[1,1])*k_mu*2.0
153
- # alpha = 1.0
154
-
155
- # -----------------------------
156
- # Baraff & Witkin, note this model is not isotropic
157
-
158
- # c1 = length(f1) - 1.0
159
- # c2 = length(f2) - 1.0
160
- # f1 = normalize(f1)*c1*k1
161
- # f2 = normalize(f2)*c2*k1
162
-
163
- # fq = f1*Dm[0,0] + f2*Dm[0,1]
164
- # fr = f1*Dm[1,0] + f2*Dm[1,1]
165
-
166
- # -----------------------------
167
- # Neo-Hookean (with rest stability)
168
-
169
- # force = P*Dm'
170
- f1 = P1 * Dm[0, 0] + P2 * Dm[0, 1]
171
- f2 = P1 * Dm[1, 0] + P2 * Dm[1, 1]
172
- alpha = 1.0 + k_mu / k_lambda
173
-
174
- # -----------------------------
175
- # Area Preservation
176
-
177
- n = wp.cross(x10, x20)
178
- area = wp.length(n) * 0.5
179
-
180
- # actuation
181
- act = activation[tid]
182
-
183
- # J-alpha
184
- c = area * inv_rest_area - alpha + act
185
-
186
- # dJdx
187
- n = wp.normalize(n)
188
- dcdq = wp.cross(x20, n) * inv_rest_area * 0.5
189
- dcdr = wp.cross(n, x10) * inv_rest_area * 0.5
190
-
191
- f_area = k_lambda * c
192
-
193
- # -----------------------------
194
- # Area Damping
195
-
196
- dcdt = wp.dot(dcdq, v1) + wp.dot(dcdr, v2) - wp.dot(dcdq + dcdr, v0)
197
- f_damp = k_damp * dcdt
198
-
199
- f1 = f1 + dcdq * (f_area + f_damp)
200
- f2 = f2 + dcdr * (f_area + f_damp)
201
- f0 = f1 + f2
202
-
203
- # -----------------------------
204
- # Lift + Drag
205
-
206
- vmid = (v0 + v1 + v2) * 0.3333
207
- vdir = wp.normalize(vmid)
208
-
209
- f_drag = vmid * (k_drag * area * wp.abs(wp.dot(n, vmid)))
210
- f_lift = n * (k_lift * area * (wp.HALF_PI - wp.acos(wp.dot(n, vdir)))) * wp.dot(vmid, vmid)
211
-
212
- f0 = f0 - f_drag - f_lift
213
- f1 = f1 + f_drag + f_lift
214
- f2 = f2 + f_drag + f_lift
215
-
216
- # apply forces
217
- wp.atomic_add(f, i, f0)
218
- wp.atomic_sub(f, j, f1)
219
- wp.atomic_sub(f, k, f2)
220
-
221
-
222
- # @wp.func
223
- # def triangle_closest_point(a: wp.vec3, b: wp.vec3, c: wp.vec3, p: wp.vec3):
224
- # ab = b - a
225
- # ac = c - a
226
- # ap = p - a
227
-
228
- # d1 = wp.dot(ab, ap)
229
- # d2 = wp.dot(ac, ap)
230
-
231
- # if (d1 <= 0.0 and d2 <= 0.0):
232
- # return a
233
-
234
- # bp = p - b
235
- # d3 = wp.dot(ab, bp)
236
- # d4 = wp.dot(ac, bp)
237
-
238
- # if (d3 >= 0.0 and d4 <= d3):
239
- # return b
240
-
241
- # vc = d1 * d4 - d3 * d2
242
- # v = d1 / (d1 - d3)
243
- # if (vc <= 0.0 and d1 >= 0.0 and d3 <= 0.0):
244
- # return a + ab * v
245
-
246
- # cp = p - c
247
- # d5 = dot(ab, cp)
248
- # d6 = dot(ac, cp)
249
-
250
- # if (d6 >= 0.0 and d5 <= d6):
251
- # return c
252
-
253
- # vb = d5 * d2 - d1 * d6
254
- # w = d2 / (d2 - d6)
255
- # if (vb <= 0.0 and d2 >= 0.0 and d6 <= 0.0):
256
- # return a + ac * w
257
-
258
- # va = d3 * d6 - d5 * d4
259
- # w = (d4 - d3) / ((d4 - d3) + (d5 - d6))
260
- # if (va <= 0.0 and (d4 - d3) >= 0.0 and (d5 - d6) >= 0.0):
261
- # return b + (c - b) * w
262
-
263
- # denom = 1.0 / (va + vb + vc)
264
- # v = vb * denom
265
- # w = vc * denom
266
-
267
- # return a + ab * v + ac * w
268
-
269
-
270
- @wp.kernel
271
- def eval_triangles_contact(
272
- # idx : wp.array(dtype=int), # list of indices for colliding particles
273
- num_particles: int, # size of particles
274
- x: wp.array(dtype=wp.vec3),
275
- v: wp.array(dtype=wp.vec3),
276
- indices: wp.array2d(dtype=int),
277
- materials: wp.array2d(dtype=float),
278
- particle_radius: wp.array(dtype=float),
279
- f: wp.array(dtype=wp.vec3),
280
- ):
281
- tid = wp.tid()
282
- face_no = tid // num_particles # which face
283
- particle_no = tid % num_particles # which particle
284
-
285
- # k_mu = materials[face_no, 0]
286
- # k_lambda = materials[face_no, 1]
287
- # k_damp = materials[face_no, 2]
288
- # k_drag = materials[face_no, 3]
289
- # k_lift = materials[face_no, 4]
290
-
291
- # at the moment, just one particle
292
- pos = x[particle_no]
293
-
294
- i = indices[face_no, 0]
295
- j = indices[face_no, 1]
296
- k = indices[face_no, 2]
297
-
298
- if i == particle_no or j == particle_no or k == particle_no:
299
- return
300
-
301
- p = x[i] # point zero
302
- q = x[j] # point one
303
- r = x[k] # point two
304
-
305
- # vp = v[i] # vel zero
306
- # vq = v[j] # vel one
307
- # vr = v[k] # vel two
308
-
309
- # qp = q-p # barycentric coordinates (centered at p)
310
- # rp = r-p
311
-
312
- bary = triangle_closest_point_barycentric(p, q, r, pos)
313
- closest = p * bary[0] + q * bary[1] + r * bary[2]
314
-
315
- diff = pos - closest
316
- dist = wp.dot(diff, diff)
317
- n = wp.normalize(diff)
318
- c = wp.min(dist - particle_radius[particle_no], 0.0) # 0 unless within particle's contact radius
319
- # c = wp.leaky_min(dot(n, x0)-0.01, 0.0, 0.0)
320
- fn = n * c * 1e5
321
-
322
- wp.atomic_sub(f, particle_no, fn)
323
-
324
- # # apply forces (could do - f / 3 here)
325
- wp.atomic_add(f, i, fn * bary[0])
326
- wp.atomic_add(f, j, fn * bary[1])
327
- wp.atomic_add(f, k, fn * bary[2])
328
-
329
-
330
- @wp.kernel
331
- def eval_triangles_body_contacts(
332
- num_particles: int, # number of particles (size of contact_point)
333
- x: wp.array(dtype=wp.vec3), # position of particles
334
- v: wp.array(dtype=wp.vec3),
335
- indices: wp.array(dtype=int), # triangle indices
336
- body_x: wp.array(dtype=wp.vec3), # body body positions
337
- body_r: wp.array(dtype=wp.quat),
338
- body_v: wp.array(dtype=wp.vec3),
339
- body_w: wp.array(dtype=wp.vec3),
340
- contact_body: wp.array(dtype=int),
341
- contact_point: wp.array(dtype=wp.vec3), # position of contact points relative to body
342
- contact_dist: wp.array(dtype=float),
343
- contact_mat: wp.array(dtype=int),
344
- materials: wp.array(dtype=float),
345
- # body_f : wp.array(dtype=wp.vec3),
346
- # body_t : wp.array(dtype=wp.vec3),
347
- tri_f: wp.array(dtype=wp.vec3),
348
- ):
349
- tid = wp.tid()
350
-
351
- face_no = tid // num_particles # which face
352
- particle_no = tid % num_particles # which particle
353
-
354
- # -----------------------
355
- # load body body point
356
- c_body = contact_body[particle_no]
357
- c_point = contact_point[particle_no]
358
- c_dist = contact_dist[particle_no]
359
- c_mat = contact_mat[particle_no]
360
-
361
- # hard coded surface parameter tensor layout (ke, kd, kf, mu)
362
- ke = materials[c_mat * 4 + 0] # restitution coefficient
363
- kd = materials[c_mat * 4 + 1] # damping coefficient
364
- kf = materials[c_mat * 4 + 2] # friction coefficient
365
- mu = materials[c_mat * 4 + 3] # coulomb friction
366
-
367
- x0 = body_x[c_body] # position of colliding body
368
- r0 = body_r[c_body] # orientation of colliding body
369
-
370
- v0 = body_v[c_body]
371
- w0 = body_w[c_body]
372
-
373
- # transform point to world space
374
- pos = x0 + wp.quat_rotate(r0, c_point)
375
- # use x0 as center, everything is offset from center of mass
376
-
377
- # moment arm
378
- r = pos - x0 # basically just c_point in the new coordinates
379
- rhat = wp.normalize(r)
380
- pos = pos + rhat * c_dist # add on 'thickness' of shape, e.g.: radius of sphere/capsule
381
-
382
- # contact point velocity
383
- dpdt = v0 + wp.cross(w0, r) # this is body velocity cross offset, so it's the velocity of the contact point.
384
-
385
- # -----------------------
386
- # load triangle
387
- i = indices[face_no * 3 + 0]
388
- j = indices[face_no * 3 + 1]
389
- k = indices[face_no * 3 + 2]
390
-
391
- p = x[i] # point zero
392
- q = x[j] # point one
393
- r = x[k] # point two
394
-
395
- vp = v[i] # vel zero
396
- vq = v[j] # vel one
397
- vr = v[k] # vel two
398
-
399
- bary = triangle_closest_point_barycentric(p, q, r, pos)
400
- closest = p * bary[0] + q * bary[1] + r * bary[2]
401
-
402
- diff = pos - closest # vector from tri to point
403
- dist = wp.dot(diff, diff) # squared distance
404
- n = wp.normalize(diff) # points into the object
405
- c = wp.min(dist - 0.05, 0.0) # 0 unless within 0.05 of surface
406
- # c = wp.leaky_min(wp.dot(n, x0)-0.01, 0.0, 0.0)
407
- # fn = n * c * 1e6 # points towards cloth (both n and c are negative)
408
-
409
- # wp.atomic_sub(tri_f, particle_no, fn)
410
-
411
- fn = c * ke # normal force (restitution coefficient * how far inside for ground) (negative)
412
-
413
- vtri = vp * bary[0] + vq * bary[1] + vr * bary[2] # bad approximation for centroid velocity
414
- vrel = vtri - dpdt
415
-
416
- vn = wp.dot(n, vrel) # velocity component of body in negative normal direction
417
- vt = vrel - n * vn # velocity component not in normal direction
418
-
419
- # contact damping
420
- fd = -wp.max(vn, 0.0) * kd * wp.step(c) # again, negative, into the ground
421
-
422
- # # viscous friction
423
- # ft = vt*kf
424
-
425
- # Coulomb friction (box)
426
- lower = mu * (fn + fd)
427
- upper = -lower
428
-
429
- nx = wp.cross(n, wp.vec3(0.0, 0.0, 1.0)) # basis vectors for tangent
430
- nz = wp.cross(n, wp.vec3(1.0, 0.0, 0.0))
431
-
432
- vx = wp.clamp(wp.dot(nx * kf, vt), lower, upper)
433
- vz = wp.clamp(wp.dot(nz * kf, vt), lower, upper)
434
-
435
- ft = (nx * vx + nz * vz) * (-wp.step(c)) # wp.vec3(vx, 0.0, vz)*wp.step(c)
436
-
437
- # # Coulomb friction (smooth, but gradients are numerically unstable around |vt| = 0)
438
- # #ft = wp.normalize(vt)*wp.min(kf*wp.length(vt), -mu*c*ke)
439
-
440
- f_total = n * (fn + fd) + ft
441
-
442
- wp.atomic_add(tri_f, i, f_total * bary[0])
443
- wp.atomic_add(tri_f, j, f_total * bary[1])
444
- wp.atomic_add(tri_f, k, f_total * bary[2])
445
-
446
-
447
- @wp.kernel
448
- def eval_bending(
449
- x: wp.array(dtype=wp.vec3),
450
- v: wp.array(dtype=wp.vec3),
451
- indices: wp.array2d(dtype=int),
452
- rest: wp.array(dtype=float),
453
- bending_properties: wp.array2d(dtype=float),
454
- f: wp.array(dtype=wp.vec3),
455
- ):
456
- tid = wp.tid()
457
- ke = bending_properties[tid, 0]
458
- kd = bending_properties[tid, 1]
459
-
460
- i = indices[tid, 0]
461
- j = indices[tid, 1]
462
- k = indices[tid, 2]
463
- l = indices[tid, 3]
464
-
465
- if i == -1 or j == -1 or k == -1 or l == -1:
466
- return
467
-
468
- rest_angle = rest[tid]
469
-
470
- x1 = x[i]
471
- x2 = x[j]
472
- x3 = x[k]
473
- x4 = x[l]
474
-
475
- v1 = v[i]
476
- v2 = v[j]
477
- v3 = v[k]
478
- v4 = v[l]
479
-
480
- n1 = wp.cross(x3 - x1, x4 - x1) # normal to face 1
481
- n2 = wp.cross(x4 - x2, x3 - x2) # normal to face 2
482
-
483
- n1_length = wp.length(n1)
484
- n2_length = wp.length(n2)
485
-
486
- if n1_length < 1.0e-6 or n2_length < 1.0e-6:
487
- return
488
-
489
- rcp_n1 = 1.0 / n1_length
490
- rcp_n2 = 1.0 / n2_length
491
-
492
- cos_theta = wp.dot(n1, n2) * rcp_n1 * rcp_n2
493
-
494
- n1 = n1 * rcp_n1 * rcp_n1
495
- n2 = n2 * rcp_n2 * rcp_n2
496
-
497
- e = x4 - x3
498
- e_hat = wp.normalize(e)
499
- e_length = wp.length(e)
500
-
501
- s = wp.sign(wp.dot(wp.cross(n2, n1), e_hat))
502
- angle = wp.acos(cos_theta) * s
503
-
504
- d1 = n1 * e_length
505
- d2 = n2 * e_length
506
- d3 = n1 * wp.dot(x1 - x4, e_hat) + n2 * wp.dot(x2 - x4, e_hat)
507
- d4 = n1 * wp.dot(x3 - x1, e_hat) + n2 * wp.dot(x3 - x2, e_hat)
508
-
509
- # elastic
510
- f_elastic = ke * (angle - rest_angle)
511
-
512
- # damping
513
- f_damp = kd * (wp.dot(d1, v1) + wp.dot(d2, v2) + wp.dot(d3, v3) + wp.dot(d4, v4))
514
-
515
- # total force, proportional to edge length
516
- f_total = -e_length * (f_elastic + f_damp)
517
-
518
- wp.atomic_add(f, i, d1 * f_total)
519
- wp.atomic_add(f, j, d2 * f_total)
520
- wp.atomic_add(f, k, d3 * f_total)
521
- wp.atomic_add(f, l, d4 * f_total)
522
-
523
-
524
- @wp.kernel
525
- def eval_tetrahedra(
526
- x: wp.array(dtype=wp.vec3),
527
- v: wp.array(dtype=wp.vec3),
528
- indices: wp.array2d(dtype=int),
529
- pose: wp.array(dtype=wp.mat33),
530
- activation: wp.array(dtype=float),
531
- materials: wp.array2d(dtype=float),
532
- f: wp.array(dtype=wp.vec3),
533
- ):
534
- tid = wp.tid()
535
-
536
- i = indices[tid, 0]
537
- j = indices[tid, 1]
538
- k = indices[tid, 2]
539
- l = indices[tid, 3]
540
-
541
- act = activation[tid]
542
-
543
- k_mu = materials[tid, 0]
544
- k_lambda = materials[tid, 1]
545
- k_damp = materials[tid, 2]
546
-
547
- x0 = x[i]
548
- x1 = x[j]
549
- x2 = x[k]
550
- x3 = x[l]
551
-
552
- v0 = v[i]
553
- v1 = v[j]
554
- v2 = v[k]
555
- v3 = v[l]
556
-
557
- x10 = x1 - x0
558
- x20 = x2 - x0
559
- x30 = x3 - x0
560
-
561
- v10 = v1 - v0
562
- v20 = v2 - v0
563
- v30 = v3 - v0
564
-
565
- Ds = wp.matrix_from_cols(x10, x20, x30)
566
- Dm = pose[tid]
567
-
568
- inv_rest_volume = wp.determinant(Dm) * 6.0
569
- rest_volume = 1.0 / inv_rest_volume
570
-
571
- alpha = 1.0 + k_mu / k_lambda - k_mu / (4.0 * k_lambda)
572
-
573
- # scale stiffness coefficients to account for area
574
- k_mu = k_mu * rest_volume
575
- k_lambda = k_lambda * rest_volume
576
- k_damp = k_damp * rest_volume
577
-
578
- # F = Xs*Xm^-1
579
- F = Ds * Dm
580
- dFdt = wp.matrix_from_cols(v10, v20, v30) * Dm
581
-
582
- col1 = wp.vec3(F[0, 0], F[1, 0], F[2, 0])
583
- col2 = wp.vec3(F[0, 1], F[1, 1], F[2, 1])
584
- col3 = wp.vec3(F[0, 2], F[1, 2], F[2, 2])
585
-
586
- # -----------------------------
587
- # Neo-Hookean (with rest stability [Smith et al 2018])
588
-
589
- Ic = wp.dot(col1, col1) + wp.dot(col2, col2) + wp.dot(col3, col3)
590
-
591
- # deviatoric part
592
- P = F * k_mu * (1.0 - 1.0 / (Ic + 1.0)) + dFdt * k_damp
593
- H = P * wp.transpose(Dm)
594
-
595
- f1 = wp.vec3(H[0, 0], H[1, 0], H[2, 0])
596
- f2 = wp.vec3(H[0, 1], H[1, 1], H[2, 1])
597
- f3 = wp.vec3(H[0, 2], H[1, 2], H[2, 2])
598
-
599
- # -----------------------------
600
- # C_sqrt
601
-
602
- # alpha = 1.0
603
-
604
- # r_s = wp.sqrt(wp.abs(dot(col1, col1) + dot(col2, col2) + dot(col3, col3) - 3.0))
605
-
606
- # f1 = wp.vec3()
607
- # f2 = wp.vec3()
608
- # f3 = wp.vec3()
609
-
610
- # if (r_s > 0.0):
611
- # r_s_inv = 1.0/r_s
612
-
613
- # C = r_s
614
- # dCdx = F*wp.transpose(Dm)*r_s_inv*wp.sign(r_s)
615
-
616
- # grad1 = vec3(dCdx[0,0], dCdx[1,0], dCdx[2,0])
617
- # grad2 = vec3(dCdx[0,1], dCdx[1,1], dCdx[2,1])
618
- # grad3 = vec3(dCdx[0,2], dCdx[1,2], dCdx[2,2])
619
-
620
- # f1 = grad1*C*k_mu
621
- # f2 = grad2*C*k_mu
622
- # f3 = grad3*C*k_mu
623
-
624
- # -----------------------------
625
- # C_spherical
626
-
627
- # alpha = 1.0
628
-
629
- # r_s = wp.sqrt(dot(col1, col1) + dot(col2, col2) + dot(col3, col3))
630
- # r_s_inv = 1.0/r_s
631
-
632
- # C = r_s - wp.sqrt(3.0)
633
- # dCdx = F*wp.transpose(Dm)*r_s_inv
634
-
635
- # grad1 = vec3(dCdx[0,0], dCdx[1,0], dCdx[2,0])
636
- # grad2 = vec3(dCdx[0,1], dCdx[1,1], dCdx[2,1])
637
- # grad3 = vec3(dCdx[0,2], dCdx[1,2], dCdx[2,2])
638
-
639
- # f1 = grad1*C*k_mu
640
- # f2 = grad2*C*k_mu
641
- # f3 = grad3*C*k_mu
642
-
643
- # ----------------------------
644
- # C_D
645
-
646
- # alpha = 1.0
647
-
648
- # r_s = wp.sqrt(dot(col1, col1) + dot(col2, col2) + dot(col3, col3))
649
-
650
- # C = r_s*r_s - 3.0
651
- # dCdx = F*wp.transpose(Dm)*2.0
652
-
653
- # grad1 = vec3(dCdx[0,0], dCdx[1,0], dCdx[2,0])
654
- # grad2 = vec3(dCdx[0,1], dCdx[1,1], dCdx[2,1])
655
- # grad3 = vec3(dCdx[0,2], dCdx[1,2], dCdx[2,2])
656
-
657
- # f1 = grad1*C*k_mu
658
- # f2 = grad2*C*k_mu
659
- # f3 = grad3*C*k_mu
660
-
661
- # ----------------------------
662
- # Hookean
663
-
664
- # alpha = 1.0
665
-
666
- # I = wp.matrix_from_cols(wp.vec3(1.0, 0.0, 0.0),
667
- # wp.vec3(0.0, 1.0, 0.0),
668
- # wp.vec3(0.0, 0.0, 1.0))
669
-
670
- # P = (F + wp.transpose(F) + I*(0.0-2.0))*k_mu
671
- # H = P * wp.transpose(Dm)
672
-
673
- # f1 = wp.vec3(H[0, 0], H[1, 0], H[2, 0])
674
- # f2 = wp.vec3(H[0, 1], H[1, 1], H[2, 1])
675
- # f3 = wp.vec3(H[0, 2], H[1, 2], H[2, 2])
676
-
677
- # hydrostatic part
678
- J = wp.determinant(F)
679
-
680
- # print(J)
681
- s = inv_rest_volume / 6.0
682
- dJdx1 = wp.cross(x20, x30) * s
683
- dJdx2 = wp.cross(x30, x10) * s
684
- dJdx3 = wp.cross(x10, x20) * s
685
-
686
- f_volume = (J - alpha + act) * k_lambda
687
- f_damp = (wp.dot(dJdx1, v1) + wp.dot(dJdx2, v2) + wp.dot(dJdx3, v3)) * k_damp
688
-
689
- f_total = f_volume + f_damp
690
-
691
- f1 = f1 + dJdx1 * f_total
692
- f2 = f2 + dJdx2 * f_total
693
- f3 = f3 + dJdx3 * f_total
694
- f0 = -(f1 + f2 + f3)
695
-
696
- # apply forces
697
- wp.atomic_sub(f, i, f0)
698
- wp.atomic_sub(f, j, f1)
699
- wp.atomic_sub(f, k, f2)
700
- wp.atomic_sub(f, l, f3)
701
-
702
-
703
- @wp.kernel
704
- def eval_particle_ground_contacts(
705
- particle_x: wp.array(dtype=wp.vec3),
706
- particle_v: wp.array(dtype=wp.vec3),
707
- particle_radius: wp.array(dtype=float),
708
- particle_flags: wp.array(dtype=wp.uint32),
709
- ke: float,
710
- kd: float,
711
- kf: float,
712
- mu: float,
713
- ground: wp.array(dtype=float),
714
- # outputs
715
- f: wp.array(dtype=wp.vec3),
716
- ):
717
- tid = wp.tid()
718
- if (particle_flags[tid] & PARTICLE_FLAG_ACTIVE) == 0:
719
- return
720
-
721
- x = particle_x[tid]
722
- v = particle_v[tid]
723
- radius = particle_radius[tid]
724
-
725
- n = wp.vec3(ground[0], ground[1], ground[2])
726
- c = wp.min(wp.dot(n, x) + ground[3] - radius, 0.0)
727
-
728
- vn = wp.dot(n, v)
729
- jn = c * ke
730
-
731
- if c >= 0.0:
732
- return
733
-
734
- jd = min(vn, 0.0) * kd
735
-
736
- # contact force
737
- fn = jn + jd
738
-
739
- # friction force
740
- vt = v - n * vn
741
- vs = wp.length(vt)
742
-
743
- if vs > 0.0:
744
- vt = vt / vs
745
-
746
- # Coulomb condition
747
- ft = wp.min(vs * kf, mu * wp.abs(fn))
748
-
749
- # total force
750
- f[tid] = f[tid] - n * fn - vt * ft
751
-
752
-
753
- @wp.kernel
754
- def eval_particle_contacts(
755
- particle_x: wp.array(dtype=wp.vec3),
756
- particle_v: wp.array(dtype=wp.vec3),
757
- body_q: wp.array(dtype=wp.transform),
758
- body_qd: wp.array(dtype=wp.spatial_vector),
759
- particle_radius: wp.array(dtype=float),
760
- particle_flags: wp.array(dtype=wp.uint32),
761
- body_com: wp.array(dtype=wp.vec3),
762
- shape_body: wp.array(dtype=int),
763
- shape_materials: ModelShapeMaterials,
764
- particle_ke: float,
765
- particle_kd: float,
766
- particle_kf: float,
767
- particle_mu: float,
768
- particle_ka: float,
769
- contact_count: wp.array(dtype=int),
770
- contact_particle: wp.array(dtype=int),
771
- contact_shape: wp.array(dtype=int),
772
- contact_body_pos: wp.array(dtype=wp.vec3),
773
- contact_body_vel: wp.array(dtype=wp.vec3),
774
- contact_normal: wp.array(dtype=wp.vec3),
775
- contact_max: int,
776
- body_f_in_world_frame: bool,
777
- # outputs
778
- particle_f: wp.array(dtype=wp.vec3),
779
- body_f: wp.array(dtype=wp.spatial_vector),
780
- ):
781
- tid = wp.tid()
782
-
783
- count = min(contact_max, contact_count[0])
784
- if tid >= count:
785
- return
786
-
787
- shape_index = contact_shape[tid]
788
- body_index = shape_body[shape_index]
789
- particle_index = contact_particle[tid]
790
- if (particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE) == 0:
791
- return
792
-
793
- px = particle_x[particle_index]
794
- pv = particle_v[particle_index]
795
-
796
- X_wb = wp.transform_identity()
797
- X_com = wp.vec3()
798
- body_v_s = wp.spatial_vector()
799
-
800
- if body_index >= 0:
801
- X_wb = body_q[body_index]
802
- X_com = body_com[body_index]
803
- body_v_s = body_qd[body_index]
804
-
805
- # body position in world space
806
- bx = wp.transform_point(X_wb, contact_body_pos[tid])
807
- r = bx - wp.transform_point(X_wb, X_com)
808
-
809
- n = contact_normal[tid]
810
- c = wp.dot(n, px - bx) - particle_radius[particle_index]
811
-
812
- if c > particle_ka:
813
- return
814
-
815
- # take average material properties of shape and particle parameters
816
- ke = 0.5 * (particle_ke + shape_materials.ke[shape_index])
817
- kd = 0.5 * (particle_kd + shape_materials.kd[shape_index])
818
- kf = 0.5 * (particle_kf + shape_materials.kf[shape_index])
819
- mu = 0.5 * (particle_mu + shape_materials.mu[shape_index])
820
-
821
- body_w = wp.spatial_top(body_v_s)
822
- body_v = wp.spatial_bottom(body_v_s)
823
-
824
- # compute the body velocity at the particle position
825
- bv = body_v + wp.transform_vector(X_wb, contact_body_vel[tid])
826
- if body_f_in_world_frame:
827
- bv += wp.cross(body_w, bx)
828
- else:
829
- bv += wp.cross(body_w, r)
830
-
831
- # relative velocity
832
- v = pv - bv
833
-
834
- # decompose relative velocity
835
- vn = wp.dot(n, v)
836
- vt = v - n * vn
837
-
838
- # contact elastic
839
- fn = n * c * ke
840
-
841
- # contact damping
842
- fd = n * wp.min(vn, 0.0) * kd
843
-
844
- # viscous friction
845
- # ft = vt*kf
846
-
847
- # Coulomb friction (box)
848
- # lower = mu * c * ke
849
- # upper = -lower
850
-
851
- # vx = wp.clamp(wp.dot(wp.vec3(kf, 0.0, 0.0), vt), lower, upper)
852
- # vz = wp.clamp(wp.dot(wp.vec3(0.0, 0.0, kf), vt), lower, upper)
853
-
854
- # ft = wp.vec3(vx, 0.0, vz)
855
-
856
- # Coulomb friction (smooth, but gradients are numerically unstable around |vt| = 0)
857
- ft = wp.normalize(vt) * wp.min(kf * wp.length(vt), abs(mu * c * ke))
858
-
859
- f_total = fn + (fd + ft)
860
-
861
- wp.atomic_sub(particle_f, particle_index, f_total)
862
-
863
- if body_index >= 0:
864
- if body_f_in_world_frame:
865
- wp.atomic_sub(body_f, body_index, wp.spatial_vector(wp.cross(bx, f_total), f_total))
866
- else:
867
- wp.atomic_add(body_f, body_index, wp.spatial_vector(wp.cross(r, f_total), f_total))
868
-
869
-
870
- @wp.kernel
871
- def eval_rigid_contacts(
872
- body_q: wp.array(dtype=wp.transform),
873
- body_qd: wp.array(dtype=wp.spatial_vector),
874
- body_com: wp.array(dtype=wp.vec3),
875
- shape_materials: ModelShapeMaterials,
876
- geo: ModelShapeGeometry,
877
- shape_body: wp.array(dtype=int),
878
- contact_count: wp.array(dtype=int),
879
- contact_point0: wp.array(dtype=wp.vec3),
880
- contact_point1: wp.array(dtype=wp.vec3),
881
- contact_normal: wp.array(dtype=wp.vec3),
882
- contact_shape0: wp.array(dtype=int),
883
- contact_shape1: wp.array(dtype=int),
884
- force_in_world_frame: bool,
885
- friction_smoothing: float,
886
- # outputs
887
- body_f: wp.array(dtype=wp.spatial_vector),
888
- ):
889
- tid = wp.tid()
890
-
891
- count = contact_count[0]
892
- if tid >= count:
893
- return
894
-
895
- # retrieve contact thickness, compute average contact material properties
896
- ke = 0.0 # contact normal force stiffness
897
- kd = 0.0 # damping coefficient
898
- kf = 0.0 # friction force stiffness
899
- ka = 0.0 # adhesion distance
900
- mu = 0.0 # friction coefficient
901
- mat_nonzero = 0
902
- thickness_a = 0.0
903
- thickness_b = 0.0
904
- shape_a = contact_shape0[tid]
905
- shape_b = contact_shape1[tid]
906
- if shape_a == shape_b:
907
- return
908
- body_a = -1
909
- body_b = -1
910
- if shape_a >= 0:
911
- mat_nonzero += 1
912
- ke += shape_materials.ke[shape_a]
913
- kd += shape_materials.kd[shape_a]
914
- kf += shape_materials.kf[shape_a]
915
- ka += shape_materials.ka[shape_a]
916
- mu += shape_materials.mu[shape_a]
917
- thickness_a = geo.thickness[shape_a]
918
- body_a = shape_body[shape_a]
919
- if shape_b >= 0:
920
- mat_nonzero += 1
921
- ke += shape_materials.ke[shape_b]
922
- kd += shape_materials.kd[shape_b]
923
- kf += shape_materials.kf[shape_b]
924
- ka += shape_materials.ka[shape_b]
925
- mu += shape_materials.mu[shape_b]
926
- thickness_b = geo.thickness[shape_b]
927
- body_b = shape_body[shape_b]
928
- if mat_nonzero > 0:
929
- ke /= float(mat_nonzero)
930
- kd /= float(mat_nonzero)
931
- kf /= float(mat_nonzero)
932
- ka /= float(mat_nonzero)
933
- mu /= float(mat_nonzero)
934
-
935
- # contact normal in world space
936
- n = contact_normal[tid]
937
- bx_a = contact_point0[tid]
938
- bx_b = contact_point1[tid]
939
- r_a = wp.vec3(0.0)
940
- r_b = wp.vec3(0.0)
941
- if body_a >= 0:
942
- X_wb_a = body_q[body_a]
943
- X_com_a = body_com[body_a]
944
- bx_a = wp.transform_point(X_wb_a, bx_a) - thickness_a * n
945
- r_a = bx_a - wp.transform_point(X_wb_a, X_com_a)
946
-
947
- if body_b >= 0:
948
- X_wb_b = body_q[body_b]
949
- X_com_b = body_com[body_b]
950
- bx_b = wp.transform_point(X_wb_b, bx_b) + thickness_b * n
951
- r_b = bx_b - wp.transform_point(X_wb_b, X_com_b)
952
-
953
- d = wp.dot(n, bx_a - bx_b)
954
-
955
- if d >= ka:
956
- return
957
-
958
- # compute contact point velocity
959
- bv_a = wp.vec3(0.0)
960
- bv_b = wp.vec3(0.0)
961
- if body_a >= 0:
962
- body_v_s_a = body_qd[body_a]
963
- body_w_a = wp.spatial_top(body_v_s_a)
964
- body_v_a = wp.spatial_bottom(body_v_s_a)
965
- if force_in_world_frame:
966
- bv_a = body_v_a + wp.cross(body_w_a, bx_a)
967
- else:
968
- bv_a = body_v_a + wp.cross(body_w_a, r_a)
969
-
970
- if body_b >= 0:
971
- body_v_s_b = body_qd[body_b]
972
- body_w_b = wp.spatial_top(body_v_s_b)
973
- body_v_b = wp.spatial_bottom(body_v_s_b)
974
- if force_in_world_frame:
975
- bv_b = body_v_b + wp.cross(body_w_b, bx_b)
976
- else:
977
- bv_b = body_v_b + wp.cross(body_w_b, r_b)
978
-
979
- # relative velocity
980
- v = bv_a - bv_b
981
-
982
- # print(v)
983
-
984
- # decompose relative velocity
985
- vn = wp.dot(n, v)
986
- vt = v - n * vn
987
-
988
- # contact elastic
989
- fn = d * ke
990
-
991
- # contact damping
992
- fd = wp.min(vn, 0.0) * kd * wp.step(d)
993
-
994
- # viscous friction
995
- # ft = vt*kf
996
-
997
- # Coulomb friction (box)
998
- # lower = mu * d * ke
999
- # upper = -lower
1000
-
1001
- # vx = wp.clamp(wp.dot(wp.vec3(kf, 0.0, 0.0), vt), lower, upper)
1002
- # vz = wp.clamp(wp.dot(wp.vec3(0.0, 0.0, kf), vt), lower, upper)
1003
-
1004
- # ft = wp.vec3(vx, 0.0, vz)
1005
-
1006
- # Coulomb friction (smooth, but gradients are numerically unstable around |vt| = 0)
1007
- ft = wp.vec3(0.0)
1008
- if d < 0.0:
1009
- # use a smooth vector norm to avoid gradient instability at/around zero velocity
1010
- vs = wp.norm_huber(vt, delta=friction_smoothing)
1011
- if vs > 0.0:
1012
- fr = vt / vs
1013
- ft = fr * wp.min(kf * vs, -mu * (fn + fd))
1014
-
1015
- f_total = n * (fn + fd) + ft
1016
- # f_total = n * (fn + fd)
1017
- # f_total = n * fn
1018
-
1019
- if body_a >= 0:
1020
- if force_in_world_frame:
1021
- wp.atomic_add(body_f, body_a, wp.spatial_vector(wp.cross(bx_a, f_total), f_total))
1022
- else:
1023
- wp.atomic_sub(body_f, body_a, wp.spatial_vector(wp.cross(r_a, f_total), f_total))
1024
-
1025
- if body_b >= 0:
1026
- if force_in_world_frame:
1027
- wp.atomic_sub(body_f, body_b, wp.spatial_vector(wp.cross(bx_b, f_total), f_total))
1028
- else:
1029
- wp.atomic_add(body_f, body_b, wp.spatial_vector(wp.cross(r_b, f_total), f_total))
1030
-
1031
-
1032
- @wp.func
1033
- def eval_joint_force(
1034
- q: float,
1035
- qd: float,
1036
- act: float,
1037
- target_ke: float,
1038
- target_kd: float,
1039
- limit_lower: float,
1040
- limit_upper: float,
1041
- limit_ke: float,
1042
- limit_kd: float,
1043
- mode: wp.int32,
1044
- ) -> float:
1045
- """Joint force evaluation for a single degree of freedom."""
1046
-
1047
- limit_f = 0.0
1048
- damping_f = 0.0
1049
- target_f = 0.0
1050
-
1051
- if mode == wp.sim.JOINT_MODE_FORCE:
1052
- target_f = act
1053
- elif mode == wp.sim.JOINT_MODE_TARGET_POSITION:
1054
- target_f = target_ke * (act - q) - target_kd * qd
1055
- elif mode == wp.sim.JOINT_MODE_TARGET_VELOCITY:
1056
- target_f = target_ke * (act - qd)
1057
-
1058
- # compute limit forces, damping only active when limit is violated
1059
- if q < limit_lower:
1060
- limit_f = limit_ke * (limit_lower - q)
1061
- damping_f = -limit_kd * qd
1062
- if mode == wp.sim.JOINT_MODE_TARGET_VELOCITY:
1063
- target_f = 0.0 # override target force when limit is violated
1064
- elif q > limit_upper:
1065
- limit_f = limit_ke * (limit_upper - q)
1066
- damping_f = -limit_kd * qd
1067
- if mode == wp.sim.JOINT_MODE_TARGET_VELOCITY:
1068
- target_f = 0.0 # override target force when limit is violated
1069
-
1070
- return limit_f + damping_f + target_f
1071
-
1072
-
1073
- @wp.kernel
1074
- def eval_body_joints(
1075
- body_q: wp.array(dtype=wp.transform),
1076
- body_qd: wp.array(dtype=wp.spatial_vector),
1077
- body_com: wp.array(dtype=wp.vec3),
1078
- joint_qd_start: wp.array(dtype=int),
1079
- joint_type: wp.array(dtype=int),
1080
- joint_enabled: wp.array(dtype=int),
1081
- joint_child: wp.array(dtype=int),
1082
- joint_parent: wp.array(dtype=int),
1083
- joint_X_p: wp.array(dtype=wp.transform),
1084
- joint_X_c: wp.array(dtype=wp.transform),
1085
- joint_axis: wp.array(dtype=wp.vec3),
1086
- joint_axis_start: wp.array(dtype=int),
1087
- joint_axis_dim: wp.array(dtype=int, ndim=2),
1088
- joint_axis_mode: wp.array(dtype=int),
1089
- joint_act: wp.array(dtype=float),
1090
- joint_target_ke: wp.array(dtype=float),
1091
- joint_target_kd: wp.array(dtype=float),
1092
- joint_limit_lower: wp.array(dtype=float),
1093
- joint_limit_upper: wp.array(dtype=float),
1094
- joint_limit_ke: wp.array(dtype=float),
1095
- joint_limit_kd: wp.array(dtype=float),
1096
- joint_attach_ke: float,
1097
- joint_attach_kd: float,
1098
- body_f: wp.array(dtype=wp.spatial_vector),
1099
- ):
1100
- tid = wp.tid()
1101
- type = joint_type[tid]
1102
-
1103
- # early out for free joints
1104
- if joint_enabled[tid] == 0 or type == wp.sim.JOINT_FREE:
1105
- return
1106
-
1107
- c_child = joint_child[tid]
1108
- c_parent = joint_parent[tid]
1109
-
1110
- X_pj = joint_X_p[tid]
1111
- X_cj = joint_X_c[tid]
1112
-
1113
- X_wp = X_pj
1114
- r_p = wp.vec3()
1115
- w_p = wp.vec3()
1116
- v_p = wp.vec3()
1117
-
1118
- # parent transform and moment arm
1119
- if c_parent >= 0:
1120
- X_wp = body_q[c_parent] * X_wp
1121
- r_p = wp.transform_get_translation(X_wp) - wp.transform_point(body_q[c_parent], body_com[c_parent])
1122
-
1123
- twist_p = body_qd[c_parent]
1124
-
1125
- w_p = wp.spatial_top(twist_p)
1126
- v_p = wp.spatial_bottom(twist_p) + wp.cross(w_p, r_p)
1127
-
1128
- # child transform and moment arm
1129
- X_wc = body_q[c_child] * X_cj
1130
- r_c = wp.transform_get_translation(X_wc) - wp.transform_point(body_q[c_child], body_com[c_child])
1131
-
1132
- twist_c = body_qd[c_child]
1133
-
1134
- w_c = wp.spatial_top(twist_c)
1135
- v_c = wp.spatial_bottom(twist_c) + wp.cross(w_c, r_c)
1136
-
1137
- # joint properties (for 1D joints)
1138
- # q_start = joint_q_start[tid]
1139
- # qd_start = joint_qd_start[tid]
1140
- axis_start = joint_axis_start[tid]
1141
-
1142
- lin_axis_count = joint_axis_dim[tid, 0]
1143
- ang_axis_count = joint_axis_dim[tid, 1]
1144
-
1145
- x_p = wp.transform_get_translation(X_wp)
1146
- x_c = wp.transform_get_translation(X_wc)
1147
-
1148
- q_p = wp.transform_get_rotation(X_wp)
1149
- q_c = wp.transform_get_rotation(X_wc)
1150
-
1151
- # translational error
1152
- x_err = x_c - x_p
1153
- r_err = wp.quat_inverse(q_p) * q_c
1154
- v_err = v_c - v_p
1155
- w_err = w_c - w_p
1156
-
1157
- # total force/torque on the parent
1158
- t_total = wp.vec3()
1159
- f_total = wp.vec3()
1160
-
1161
- # reduce angular damping stiffness for stability
1162
- angular_damping_scale = 0.01
1163
-
1164
- if type == wp.sim.JOINT_FIXED:
1165
- ang_err = wp.normalize(wp.vec3(r_err[0], r_err[1], r_err[2])) * wp.acos(r_err[3]) * 2.0
1166
-
1167
- f_total += x_err * joint_attach_ke + v_err * joint_attach_kd
1168
- t_total += (
1169
- wp.transform_vector(X_wp, ang_err) * joint_attach_ke + w_err * joint_attach_kd * angular_damping_scale
1170
- )
1171
-
1172
- if type == wp.sim.JOINT_PRISMATIC:
1173
- axis = joint_axis[axis_start]
1174
-
1175
- # world space joint axis
1176
- axis_p = wp.transform_vector(X_wp, axis)
1177
-
1178
- # evaluate joint coordinates
1179
- q = wp.dot(x_err, axis_p)
1180
- qd = wp.dot(v_err, axis_p)
1181
- act = joint_act[axis_start]
1182
-
1183
- f_total = axis_p * -eval_joint_force(
1184
- q,
1185
- qd,
1186
- act,
1187
- joint_target_ke[axis_start],
1188
- joint_target_kd[axis_start],
1189
- joint_limit_lower[axis_start],
1190
- joint_limit_upper[axis_start],
1191
- joint_limit_ke[axis_start],
1192
- joint_limit_kd[axis_start],
1193
- joint_axis_mode[axis_start],
1194
- )
1195
-
1196
- # attachment dynamics
1197
- ang_err = wp.normalize(wp.vec3(r_err[0], r_err[1], r_err[2])) * wp.acos(r_err[3]) * 2.0
1198
-
1199
- # project off any displacement along the joint axis
1200
- f_total += (x_err - q * axis_p) * joint_attach_ke + (v_err - qd * axis_p) * joint_attach_kd
1201
- t_total += (
1202
- wp.transform_vector(X_wp, ang_err) * joint_attach_ke + w_err * joint_attach_kd * angular_damping_scale
1203
- )
1204
-
1205
- if type == wp.sim.JOINT_REVOLUTE:
1206
- axis = joint_axis[axis_start]
1207
-
1208
- axis_p = wp.transform_vector(X_wp, axis)
1209
- axis_c = wp.transform_vector(X_wc, axis)
1210
-
1211
- # swing twist decomposition
1212
- twist = quat_twist(axis, r_err)
1213
-
1214
- q = wp.acos(twist[3]) * 2.0 * wp.sign(wp.dot(axis, wp.vec3(twist[0], twist[1], twist[2])))
1215
- qd = wp.dot(w_err, axis_p)
1216
- act = joint_act[axis_start]
1217
-
1218
- t_total = axis_p * -eval_joint_force(
1219
- q,
1220
- qd,
1221
- act,
1222
- joint_target_ke[axis_start],
1223
- joint_target_kd[axis_start],
1224
- joint_limit_lower[axis_start],
1225
- joint_limit_upper[axis_start],
1226
- joint_limit_ke[axis_start],
1227
- joint_limit_kd[axis_start],
1228
- joint_axis_mode[axis_start],
1229
- )
1230
-
1231
- # attachment dynamics
1232
- swing_err = wp.cross(axis_p, axis_c)
1233
-
1234
- f_total += x_err * joint_attach_ke + v_err * joint_attach_kd
1235
- t_total += swing_err * joint_attach_ke + (w_err - qd * axis_p) * joint_attach_kd * angular_damping_scale
1236
-
1237
- if type == wp.sim.JOINT_BALL:
1238
- ang_err = wp.normalize(wp.vec3(r_err[0], r_err[1], r_err[2])) * wp.acos(r_err[3]) * 2.0
1239
-
1240
- # TODO joint limits
1241
- # TODO expose target_kd or target_ke for ball joints
1242
- # t_total += target_kd * w_err + target_ke * wp.transform_vector(X_wp, ang_err)
1243
- f_total += x_err * joint_attach_ke + v_err * joint_attach_kd
1244
-
1245
- if type == wp.sim.JOINT_COMPOUND:
1246
- q_pc = wp.quat_inverse(q_p) * q_c
1247
-
1248
- # decompose to a compound rotation each axis
1249
- angles = quat_decompose(q_pc)
1250
-
1251
- # reconstruct rotation axes
1252
- axis_0 = wp.vec3(1.0, 0.0, 0.0)
1253
- q_0 = wp.quat_from_axis_angle(axis_0, angles[0])
1254
-
1255
- axis_1 = wp.quat_rotate(q_0, wp.vec3(0.0, 1.0, 0.0))
1256
- q_1 = wp.quat_from_axis_angle(axis_1, angles[1])
1257
-
1258
- axis_2 = wp.quat_rotate(q_1 * q_0, wp.vec3(0.0, 0.0, 1.0))
1259
- # q_2 = wp.quat_from_axis_angle(axis_2, angles[2])
1260
-
1261
- # q_w = q_p
1262
-
1263
- axis_0 = wp.transform_vector(X_wp, axis_0)
1264
- axis_1 = wp.transform_vector(X_wp, axis_1)
1265
- axis_2 = wp.transform_vector(X_wp, axis_2)
1266
-
1267
- # joint dynamics
1268
- # # TODO remove wp.quat_rotate(q_w, ...)?
1269
- # t_total += eval_joint_force(angles[0], wp.dot(wp.quat_rotate(q_w, axis_0), w_err), joint_target[axis_start+0], joint_target_ke[axis_start+0],joint_target_kd[axis_start+0], joint_act[axis_start+0], joint_limit_lower[axis_start+0], joint_limit_upper[axis_start+0], joint_limit_ke[axis_start+0], joint_limit_kd[axis_start+0], wp.quat_rotate(q_w, axis_0))
1270
- # t_total += eval_joint_force(angles[1], wp.dot(wp.quat_rotate(q_w, axis_1), w_err), joint_target[axis_start+1], joint_target_ke[axis_start+1],joint_target_kd[axis_start+1], joint_act[axis_start+1], joint_limit_lower[axis_start+1], joint_limit_upper[axis_start+1], joint_limit_ke[axis_start+1], joint_limit_kd[axis_start+1], wp.quat_rotate(q_w, axis_1))
1271
- # t_total += eval_joint_force(angles[2], wp.dot(wp.quat_rotate(q_w, axis_2), w_err), joint_target[axis_start+2], joint_target_ke[axis_start+2],joint_target_kd[axis_start+2], joint_act[axis_start+2], joint_limit_lower[axis_start+2], joint_limit_upper[axis_start+2], joint_limit_ke[axis_start+2], joint_limit_kd[axis_start+2], wp.quat_rotate(q_w, axis_2))
1272
-
1273
- t_total += axis_0 * -eval_joint_force(
1274
- angles[0],
1275
- wp.dot(axis_0, w_err),
1276
- joint_act[axis_start + 0],
1277
- joint_target_ke[axis_start + 0],
1278
- joint_target_kd[axis_start + 0],
1279
- joint_limit_lower[axis_start + 0],
1280
- joint_limit_upper[axis_start + 0],
1281
- joint_limit_ke[axis_start + 0],
1282
- joint_limit_kd[axis_start + 0],
1283
- joint_axis_mode[axis_start + 0],
1284
- )
1285
- t_total += axis_1 * -eval_joint_force(
1286
- angles[1],
1287
- wp.dot(axis_1, w_err),
1288
- joint_act[axis_start + 1],
1289
- joint_target_ke[axis_start + 1],
1290
- joint_target_kd[axis_start + 1],
1291
- joint_limit_lower[axis_start + 1],
1292
- joint_limit_upper[axis_start + 1],
1293
- joint_limit_ke[axis_start + 1],
1294
- joint_limit_kd[axis_start + 1],
1295
- joint_axis_mode[axis_start + 1],
1296
- )
1297
- t_total += axis_2 * -eval_joint_force(
1298
- angles[2],
1299
- wp.dot(axis_2, w_err),
1300
- joint_act[axis_start + 2],
1301
- joint_target_ke[axis_start + 2],
1302
- joint_target_kd[axis_start + 2],
1303
- joint_limit_lower[axis_start + 2],
1304
- joint_limit_upper[axis_start + 2],
1305
- joint_limit_ke[axis_start + 2],
1306
- joint_limit_kd[axis_start + 2],
1307
- joint_axis_mode[axis_start + 2],
1308
- )
1309
-
1310
- f_total += x_err * joint_attach_ke + v_err * joint_attach_kd
1311
-
1312
- if type == wp.sim.JOINT_UNIVERSAL:
1313
- q_pc = wp.quat_inverse(q_p) * q_c
1314
-
1315
- # decompose to a compound rotation each axis
1316
- angles = quat_decompose(q_pc)
1317
-
1318
- # reconstruct rotation axes
1319
- axis_0 = wp.vec3(1.0, 0.0, 0.0)
1320
- q_0 = wp.quat_from_axis_angle(axis_0, angles[0])
1321
-
1322
- axis_1 = wp.quat_rotate(q_0, wp.vec3(0.0, 1.0, 0.0))
1323
- q_1 = wp.quat_from_axis_angle(axis_1, angles[1])
1324
-
1325
- axis_2 = wp.quat_rotate(q_1 * q_0, wp.vec3(0.0, 0.0, 1.0))
1326
-
1327
- axis_0 = wp.transform_vector(X_wp, axis_0)
1328
- axis_1 = wp.transform_vector(X_wp, axis_1)
1329
- axis_2 = wp.transform_vector(X_wp, axis_2)
1330
-
1331
- # joint dynamics
1332
-
1333
- t_total += axis_0 * -eval_joint_force(
1334
- angles[0],
1335
- wp.dot(axis_0, w_err),
1336
- joint_act[axis_start + 0],
1337
- joint_target_ke[axis_start + 0],
1338
- joint_target_kd[axis_start + 0],
1339
- joint_limit_lower[axis_start + 0],
1340
- joint_limit_upper[axis_start + 0],
1341
- joint_limit_ke[axis_start + 0],
1342
- joint_limit_kd[axis_start + 0],
1343
- joint_axis_mode[axis_start + 0],
1344
- )
1345
- t_total += axis_1 * -eval_joint_force(
1346
- angles[1],
1347
- wp.dot(axis_1, w_err),
1348
- joint_act[axis_start + 1],
1349
- joint_target_ke[axis_start + 1],
1350
- joint_target_kd[axis_start + 1],
1351
- joint_limit_lower[axis_start + 1],
1352
- joint_limit_upper[axis_start + 1],
1353
- joint_limit_ke[axis_start + 1],
1354
- joint_limit_kd[axis_start + 1],
1355
- joint_axis_mode[axis_start + 1],
1356
- )
1357
-
1358
- # last axis (fixed)
1359
- t_total += axis_2 * -eval_joint_force(
1360
- angles[2],
1361
- wp.dot(axis_2, w_err),
1362
- 0.0,
1363
- joint_attach_ke,
1364
- joint_attach_kd * angular_damping_scale,
1365
- 0.0,
1366
- 0.0,
1367
- 0.0,
1368
- 0.0,
1369
- wp.sim.JOINT_MODE_FORCE,
1370
- )
1371
-
1372
- f_total += x_err * joint_attach_ke + v_err * joint_attach_kd
1373
-
1374
- if type == wp.sim.JOINT_D6:
1375
- pos = wp.vec3(0.0)
1376
- vel = wp.vec3(0.0)
1377
- if lin_axis_count >= 1:
1378
- axis_0 = wp.transform_vector(X_wp, joint_axis[axis_start + 0])
1379
- q0 = wp.dot(x_err, axis_0)
1380
- qd0 = wp.dot(v_err, axis_0)
1381
-
1382
- f_total += axis_0 * -eval_joint_force(
1383
- q0,
1384
- qd0,
1385
- joint_act[axis_start + 0],
1386
- joint_target_ke[axis_start + 0],
1387
- joint_target_kd[axis_start + 0],
1388
- joint_limit_lower[axis_start + 0],
1389
- joint_limit_upper[axis_start + 0],
1390
- joint_limit_ke[axis_start + 0],
1391
- joint_limit_kd[axis_start + 0],
1392
- joint_axis_mode[axis_start + 0],
1393
- )
1394
-
1395
- pos += q0 * axis_0
1396
- vel += qd0 * axis_0
1397
-
1398
- if lin_axis_count >= 2:
1399
- axis_1 = wp.transform_vector(X_wp, joint_axis[axis_start + 1])
1400
- q1 = wp.dot(x_err, axis_1)
1401
- qd1 = wp.dot(v_err, axis_1)
1402
-
1403
- f_total += axis_1 * -eval_joint_force(
1404
- q1,
1405
- qd1,
1406
- joint_act[axis_start + 1],
1407
- joint_target_ke[axis_start + 1],
1408
- joint_target_kd[axis_start + 1],
1409
- joint_limit_lower[axis_start + 1],
1410
- joint_limit_upper[axis_start + 1],
1411
- joint_limit_ke[axis_start + 1],
1412
- joint_limit_kd[axis_start + 1],
1413
- joint_axis_mode[axis_start + 1],
1414
- )
1415
-
1416
- pos += q1 * axis_1
1417
- vel += qd1 * axis_1
1418
-
1419
- if lin_axis_count == 3:
1420
- axis_2 = wp.transform_vector(X_wp, joint_axis[axis_start + 2])
1421
- q2 = wp.dot(x_err, axis_2)
1422
- qd2 = wp.dot(v_err, axis_2)
1423
-
1424
- f_total += axis_2 * -eval_joint_force(
1425
- q2,
1426
- qd2,
1427
- joint_act[axis_start + 2],
1428
- joint_target_ke[axis_start + 2],
1429
- joint_target_kd[axis_start + 2],
1430
- joint_limit_lower[axis_start + 2],
1431
- joint_limit_upper[axis_start + 2],
1432
- joint_limit_ke[axis_start + 2],
1433
- joint_limit_kd[axis_start + 2],
1434
- joint_axis_mode[axis_start + 2],
1435
- )
1436
-
1437
- pos += q2 * axis_2
1438
- vel += qd2 * axis_2
1439
-
1440
- f_total += (x_err - pos) * joint_attach_ke + (v_err - vel) * joint_attach_kd
1441
-
1442
- if ang_axis_count == 0:
1443
- ang_err = wp.normalize(wp.vec3(r_err[0], r_err[1], r_err[2])) * wp.acos(r_err[3]) * 2.0
1444
- t_total += (
1445
- wp.transform_vector(X_wp, ang_err) * joint_attach_ke + w_err * joint_attach_kd * angular_damping_scale
1446
- )
1447
-
1448
- i_0 = lin_axis_count + axis_start + 0
1449
- i_1 = lin_axis_count + axis_start + 1
1450
- i_2 = lin_axis_count + axis_start + 2
1451
-
1452
- if ang_axis_count == 1:
1453
- axis = joint_axis[i_0]
1454
-
1455
- axis_p = wp.transform_vector(X_wp, axis)
1456
- axis_c = wp.transform_vector(X_wc, axis)
1457
-
1458
- # swing twist decomposition
1459
- twist = quat_twist(axis, r_err)
1460
-
1461
- q = wp.acos(twist[3]) * 2.0 * wp.sign(wp.dot(axis, wp.vec3(twist[0], twist[1], twist[2])))
1462
- qd = wp.dot(w_err, axis_p)
1463
-
1464
- t_total = axis_p * -eval_joint_force(
1465
- q,
1466
- qd,
1467
- joint_act[i_0],
1468
- joint_target_ke[i_0],
1469
- joint_target_kd[i_0],
1470
- joint_limit_lower[i_0],
1471
- joint_limit_upper[i_0],
1472
- joint_limit_ke[i_0],
1473
- joint_limit_kd[i_0],
1474
- joint_axis_mode[i_0],
1475
- )
1476
-
1477
- # attachment dynamics
1478
- swing_err = wp.cross(axis_p, axis_c)
1479
-
1480
- t_total += swing_err * joint_attach_ke + (w_err - qd * axis_p) * joint_attach_kd * angular_damping_scale
1481
-
1482
- if ang_axis_count == 2:
1483
- q_pc = wp.quat_inverse(q_p) * q_c
1484
-
1485
- # decompose to a compound rotation each axis
1486
- angles = quat_decompose(q_pc)
1487
-
1488
- orig_axis_0 = joint_axis[i_0]
1489
- orig_axis_1 = joint_axis[i_1]
1490
- orig_axis_2 = wp.cross(orig_axis_0, orig_axis_1)
1491
-
1492
- # reconstruct rotation axes
1493
- axis_0 = orig_axis_0
1494
- q_0 = wp.quat_from_axis_angle(axis_0, angles[0])
1495
-
1496
- axis_1 = wp.quat_rotate(q_0, orig_axis_1)
1497
- q_1 = wp.quat_from_axis_angle(axis_1, angles[1])
1498
-
1499
- axis_2 = wp.quat_rotate(q_1 * q_0, orig_axis_2)
1500
-
1501
- axis_0 = wp.transform_vector(X_wp, axis_0)
1502
- axis_1 = wp.transform_vector(X_wp, axis_1)
1503
- axis_2 = wp.transform_vector(X_wp, axis_2)
1504
-
1505
- # joint dynamics
1506
-
1507
- t_total += axis_0 * -eval_joint_force(
1508
- angles[0],
1509
- wp.dot(axis_0, w_err),
1510
- joint_act[i_0],
1511
- joint_target_ke[i_0],
1512
- joint_target_kd[i_0],
1513
- joint_limit_lower[i_0],
1514
- joint_limit_upper[i_0],
1515
- joint_limit_ke[i_0],
1516
- joint_limit_kd[i_0],
1517
- joint_axis_mode[i_0],
1518
- )
1519
- t_total += axis_1 * -eval_joint_force(
1520
- angles[1],
1521
- wp.dot(axis_1, w_err),
1522
- joint_act[i_1],
1523
- joint_target_ke[i_1],
1524
- joint_target_kd[i_1],
1525
- joint_limit_lower[i_1],
1526
- joint_limit_upper[i_1],
1527
- joint_limit_ke[i_1],
1528
- joint_limit_kd[i_1],
1529
- joint_axis_mode[i_1],
1530
- )
1531
-
1532
- # last axis (fixed)
1533
- t_total += axis_2 * -eval_joint_force(
1534
- angles[2],
1535
- wp.dot(axis_2, w_err),
1536
- 0.0,
1537
- joint_attach_ke,
1538
- joint_attach_kd * angular_damping_scale,
1539
- 0.0,
1540
- 0.0,
1541
- 0.0,
1542
- 0.0,
1543
- wp.sim.JOINT_MODE_FORCE,
1544
- )
1545
-
1546
- if ang_axis_count == 3:
1547
- q_pc = wp.quat_inverse(q_p) * q_c
1548
-
1549
- # decompose to a compound rotation each axis
1550
- angles = quat_decompose(q_pc)
1551
-
1552
- orig_axis_0 = joint_axis[i_0]
1553
- orig_axis_1 = joint_axis[i_1]
1554
- orig_axis_2 = joint_axis[i_2]
1555
-
1556
- # reconstruct rotation axes
1557
- axis_0 = orig_axis_0
1558
- q_0 = wp.quat_from_axis_angle(axis_0, angles[0])
1559
-
1560
- axis_1 = wp.quat_rotate(q_0, orig_axis_1)
1561
- q_1 = wp.quat_from_axis_angle(axis_1, angles[1])
1562
-
1563
- axis_2 = wp.quat_rotate(q_1 * q_0, orig_axis_2)
1564
-
1565
- axis_0 = wp.transform_vector(X_wp, axis_0)
1566
- axis_1 = wp.transform_vector(X_wp, axis_1)
1567
- axis_2 = wp.transform_vector(X_wp, axis_2)
1568
-
1569
- t_total += axis_0 * -eval_joint_force(
1570
- angles[0],
1571
- wp.dot(axis_0, w_err),
1572
- joint_act[i_0],
1573
- joint_target_ke[i_0],
1574
- joint_target_kd[i_0],
1575
- joint_limit_lower[i_0],
1576
- joint_limit_upper[i_0],
1577
- joint_limit_ke[i_0],
1578
- joint_limit_kd[i_0],
1579
- joint_axis_mode[i_0],
1580
- )
1581
- t_total += axis_1 * -eval_joint_force(
1582
- angles[1],
1583
- wp.dot(axis_1, w_err),
1584
- joint_act[i_1],
1585
- joint_target_ke[i_1],
1586
- joint_target_kd[i_1],
1587
- joint_limit_lower[i_1],
1588
- joint_limit_upper[i_1],
1589
- joint_limit_ke[i_1],
1590
- joint_limit_kd[i_1],
1591
- joint_axis_mode[i_1],
1592
- )
1593
- t_total += axis_2 * -eval_joint_force(
1594
- angles[2],
1595
- wp.dot(axis_2, w_err),
1596
- joint_act[i_2],
1597
- joint_target_ke[i_2],
1598
- joint_target_kd[i_2],
1599
- joint_limit_lower[i_2],
1600
- joint_limit_upper[i_2],
1601
- joint_limit_ke[i_2],
1602
- joint_limit_kd[i_2],
1603
- joint_axis_mode[i_2],
1604
- )
1605
-
1606
- # write forces
1607
- if c_parent >= 0:
1608
- wp.atomic_add(body_f, c_parent, wp.spatial_vector(t_total + wp.cross(r_p, f_total), f_total))
1609
-
1610
- wp.atomic_sub(body_f, c_child, wp.spatial_vector(t_total + wp.cross(r_c, f_total), f_total))
1611
-
1612
-
1613
- @wp.func
1614
- def compute_muscle_force(
1615
- i: int,
1616
- body_X_s: wp.array(dtype=wp.transform),
1617
- body_v_s: wp.array(dtype=wp.spatial_vector),
1618
- body_com: wp.array(dtype=wp.vec3),
1619
- muscle_links: wp.array(dtype=int),
1620
- muscle_points: wp.array(dtype=wp.vec3),
1621
- muscle_activation: float,
1622
- body_f_s: wp.array(dtype=wp.spatial_vector),
1623
- ):
1624
- link_0 = muscle_links[i]
1625
- link_1 = muscle_links[i + 1]
1626
-
1627
- if link_0 == link_1:
1628
- return 0
1629
-
1630
- r_0 = muscle_points[i]
1631
- r_1 = muscle_points[i + 1]
1632
-
1633
- xform_0 = body_X_s[link_0]
1634
- xform_1 = body_X_s[link_1]
1635
-
1636
- pos_0 = wp.transform_point(xform_0, r_0 - body_com[link_0])
1637
- pos_1 = wp.transform_point(xform_1, r_1 - body_com[link_1])
1638
-
1639
- n = wp.normalize(pos_1 - pos_0)
1640
-
1641
- # todo: add passive elastic and viscosity terms
1642
- f = n * muscle_activation
1643
-
1644
- wp.atomic_sub(body_f_s, link_0, wp.spatial_vector(f, wp.cross(pos_0, f)))
1645
- wp.atomic_add(body_f_s, link_1, wp.spatial_vector(f, wp.cross(pos_1, f)))
1646
-
1647
-
1648
- @wp.kernel
1649
- def eval_muscles(
1650
- body_X_s: wp.array(dtype=wp.transform),
1651
- body_v_s: wp.array(dtype=wp.spatial_vector),
1652
- body_com: wp.array(dtype=wp.vec3),
1653
- muscle_start: wp.array(dtype=int),
1654
- muscle_params: wp.array(dtype=float),
1655
- muscle_links: wp.array(dtype=int),
1656
- muscle_points: wp.array(dtype=wp.vec3),
1657
- muscle_activation: wp.array(dtype=float),
1658
- # output
1659
- body_f_s: wp.array(dtype=wp.spatial_vector),
1660
- ):
1661
- tid = wp.tid()
1662
-
1663
- m_start = muscle_start[tid]
1664
- m_end = muscle_start[tid + 1] - 1
1665
-
1666
- activation = muscle_activation[tid]
1667
-
1668
- for i in range(m_start, m_end):
1669
- compute_muscle_force(i, body_X_s, body_v_s, body_com, muscle_links, muscle_points, activation, body_f_s)
1670
-
1671
-
1672
- def eval_spring_forces(model: Model, state: State, particle_f: wp.array):
1673
- if model.spring_count:
1674
- wp.launch(
1675
- kernel=eval_springs,
1676
- dim=model.spring_count,
1677
- inputs=[
1678
- state.particle_q,
1679
- state.particle_qd,
1680
- model.spring_indices,
1681
- model.spring_rest_length,
1682
- model.spring_stiffness,
1683
- model.spring_damping,
1684
- ],
1685
- outputs=[particle_f],
1686
- device=model.device,
1687
- )
1688
-
1689
-
1690
- def eval_triangle_forces(model: Model, state: State, control: Control, particle_f: wp.array):
1691
- if model.tri_count:
1692
- wp.launch(
1693
- kernel=eval_triangles,
1694
- dim=model.tri_count,
1695
- inputs=[
1696
- state.particle_q,
1697
- state.particle_qd,
1698
- model.tri_indices,
1699
- model.tri_poses,
1700
- control.tri_activations,
1701
- model.tri_materials,
1702
- ],
1703
- outputs=[particle_f],
1704
- device=model.device,
1705
- )
1706
-
1707
-
1708
- def eval_triangle_contact_forces(model: Model, state: State, particle_f: wp.array):
1709
- if model.enable_tri_collisions:
1710
- wp.launch(
1711
- kernel=eval_triangles_contact,
1712
- dim=model.tri_count * model.particle_count,
1713
- inputs=[
1714
- model.particle_count,
1715
- state.particle_q,
1716
- state.particle_qd,
1717
- model.tri_indices,
1718
- model.tri_materials,
1719
- model.particle_radius,
1720
- ],
1721
- outputs=[particle_f],
1722
- device=model.device,
1723
- )
1724
-
1725
-
1726
- def eval_bending_forces(model: Model, state: State, particle_f: wp.array):
1727
- if model.edge_count:
1728
- wp.launch(
1729
- kernel=eval_bending,
1730
- dim=model.edge_count,
1731
- inputs=[
1732
- state.particle_q,
1733
- state.particle_qd,
1734
- model.edge_indices,
1735
- model.edge_rest_angle,
1736
- model.edge_bending_properties,
1737
- ],
1738
- outputs=[particle_f],
1739
- device=model.device,
1740
- )
1741
-
1742
-
1743
- def eval_particle_ground_contact_forces(model: Model, state: State, particle_f: wp.array):
1744
- if model.ground and model.particle_count:
1745
- wp.launch(
1746
- kernel=eval_particle_ground_contacts,
1747
- dim=model.particle_count,
1748
- inputs=[
1749
- state.particle_q,
1750
- state.particle_qd,
1751
- model.particle_radius,
1752
- model.particle_flags,
1753
- model.soft_contact_ke,
1754
- model.soft_contact_kd,
1755
- model.soft_contact_kf,
1756
- model.soft_contact_mu,
1757
- model.ground_plane,
1758
- ],
1759
- outputs=[particle_f],
1760
- device=model.device,
1761
- )
1762
-
1763
-
1764
- def eval_tetrahedral_forces(model: Model, state: State, control: Control, particle_f: wp.array):
1765
- if model.tet_count:
1766
- wp.launch(
1767
- kernel=eval_tetrahedra,
1768
- dim=model.tet_count,
1769
- inputs=[
1770
- state.particle_q,
1771
- state.particle_qd,
1772
- model.tet_indices,
1773
- model.tet_poses,
1774
- control.tet_activations,
1775
- model.tet_materials,
1776
- ],
1777
- outputs=[particle_f],
1778
- device=model.device,
1779
- )
1780
-
1781
-
1782
- def eval_body_contact_forces(model: Model, state: State, particle_f: wp.array, friction_smoothing: float = 1.0):
1783
- if model.rigid_contact_max and (
1784
- (model.ground and model.shape_ground_contact_pair_count) or model.shape_contact_pair_count
1785
- ):
1786
- wp.launch(
1787
- kernel=eval_rigid_contacts,
1788
- dim=model.rigid_contact_max,
1789
- inputs=[
1790
- state.body_q,
1791
- state.body_qd,
1792
- model.body_com,
1793
- model.shape_materials,
1794
- model.shape_geo,
1795
- model.shape_body,
1796
- model.rigid_contact_count,
1797
- model.rigid_contact_point0,
1798
- model.rigid_contact_point1,
1799
- model.rigid_contact_normal,
1800
- model.rigid_contact_shape0,
1801
- model.rigid_contact_shape1,
1802
- False,
1803
- friction_smoothing,
1804
- ],
1805
- outputs=[state.body_f],
1806
- device=model.device,
1807
- )
1808
-
1809
-
1810
- def eval_body_joint_forces(model: Model, state: State, control: Control, body_f: wp.array):
1811
- if model.joint_count:
1812
- wp.launch(
1813
- kernel=eval_body_joints,
1814
- dim=model.joint_count,
1815
- inputs=[
1816
- state.body_q,
1817
- state.body_qd,
1818
- model.body_com,
1819
- model.joint_qd_start,
1820
- model.joint_type,
1821
- model.joint_enabled,
1822
- model.joint_child,
1823
- model.joint_parent,
1824
- model.joint_X_p,
1825
- model.joint_X_c,
1826
- model.joint_axis,
1827
- model.joint_axis_start,
1828
- model.joint_axis_dim,
1829
- model.joint_axis_mode,
1830
- control.joint_act,
1831
- model.joint_target_ke,
1832
- model.joint_target_kd,
1833
- model.joint_limit_lower,
1834
- model.joint_limit_upper,
1835
- model.joint_limit_ke,
1836
- model.joint_limit_kd,
1837
- model.joint_attach_ke,
1838
- model.joint_attach_kd,
1839
- ],
1840
- outputs=[body_f],
1841
- device=model.device,
1842
- )
1843
-
1844
-
1845
- def eval_particle_body_contact_forces(
1846
- model: Model, state: State, particle_f: wp.array, body_f: wp.array, body_f_in_world_frame: bool = False
1847
- ):
1848
- if model.particle_count and model.shape_count > 1:
1849
- wp.launch(
1850
- kernel=eval_particle_contacts,
1851
- dim=model.soft_contact_max,
1852
- inputs=[
1853
- state.particle_q,
1854
- state.particle_qd,
1855
- state.body_q,
1856
- state.body_qd,
1857
- model.particle_radius,
1858
- model.particle_flags,
1859
- model.body_com,
1860
- model.shape_body,
1861
- model.shape_materials,
1862
- model.soft_contact_ke,
1863
- model.soft_contact_kd,
1864
- model.soft_contact_kf,
1865
- model.soft_contact_mu,
1866
- model.particle_adhesion,
1867
- model.soft_contact_count,
1868
- model.soft_contact_particle,
1869
- model.soft_contact_shape,
1870
- model.soft_contact_body_pos,
1871
- model.soft_contact_body_vel,
1872
- model.soft_contact_normal,
1873
- model.soft_contact_max,
1874
- body_f_in_world_frame,
1875
- ],
1876
- # outputs
1877
- outputs=[particle_f, body_f],
1878
- device=model.device,
1879
- )
1880
-
1881
-
1882
- def eval_muscle_forces(model: Model, state: State, control: Control, body_f: wp.array):
1883
- if model.muscle_count:
1884
- wp.launch(
1885
- kernel=eval_muscles,
1886
- dim=model.muscle_count,
1887
- inputs=[
1888
- state.body_q,
1889
- state.body_qd,
1890
- model.body_com,
1891
- model.muscle_start,
1892
- model.muscle_params,
1893
- model.muscle_bodies,
1894
- model.muscle_points,
1895
- control.muscle_activations,
1896
- ],
1897
- outputs=[body_f],
1898
- device=model.device,
1899
- )
1900
-
1901
-
1902
- def compute_forces(
1903
- model: Model,
1904
- state: State,
1905
- control: Control,
1906
- particle_f: wp.array,
1907
- body_f: wp.array,
1908
- dt: float,
1909
- friction_smoothing: float = 1.0,
1910
- ):
1911
- # damped springs
1912
- eval_spring_forces(model, state, particle_f)
1913
-
1914
- # triangle elastic and lift/drag forces
1915
- eval_triangle_forces(model, state, control, particle_f)
1916
-
1917
- # triangle/triangle contacts
1918
- eval_triangle_contact_forces(model, state, particle_f)
1919
-
1920
- # triangle bending
1921
- eval_bending_forces(model, state, particle_f)
1922
-
1923
- # tetrahedral FEM
1924
- eval_tetrahedral_forces(model, state, control, particle_f)
1925
-
1926
- # body joints
1927
- eval_body_joint_forces(model, state, control, body_f)
1928
-
1929
- # particle-particle interactions
1930
- eval_particle_forces(model, state, particle_f)
1931
-
1932
- # particle ground contacts
1933
- eval_particle_ground_contact_forces(model, state, particle_f)
1934
-
1935
- # body contacts
1936
- eval_body_contact_forces(model, state, particle_f, friction_smoothing=friction_smoothing)
1937
-
1938
- # particle shape contact
1939
- eval_particle_body_contact_forces(model, state, particle_f, body_f, body_f_in_world_frame=False)
1940
-
1941
- # muscles
1942
- if False:
1943
- eval_muscle_forces(model, state, control, body_f)
1944
-
1945
-
1946
- class SemiImplicitIntegrator(Integrator):
1947
- """A semi-implicit integrator using symplectic Euler
1948
-
1949
- After constructing `Model` and `State` objects this time-integrator
1950
- may be used to advance the simulation state forward in time.
1951
-
1952
- Semi-implicit time integration is a variational integrator that
1953
- preserves energy, however it not unconditionally stable, and requires a time-step
1954
- small enough to support the required stiffness and damping forces.
1955
-
1956
- See: https://en.wikipedia.org/wiki/Semi-implicit_Euler_method
1957
-
1958
- Example
1959
- -------
1960
-
1961
- .. code-block:: python
1962
-
1963
- integrator = wp.SemiImplicitIntegrator()
1964
-
1965
- # simulation loop
1966
- for i in range(100):
1967
- state = integrator.simulate(model, state_in, state_out, dt)
1968
-
1969
- """
1970
-
1971
- def __init__(self, angular_damping: float = 0.05, friction_smoothing: float = 1.0):
1972
- """
1973
- Args:
1974
- angular_damping (float, optional): Angular damping factor. Defaults to 0.05.
1975
- friction_smoothing (float, optional): The delta value for the Huber norm (see :func:`warp.math.norm_huber`) used for the friction velocity normalization. Defaults to 1.0.
1976
- """
1977
- self.angular_damping = angular_damping
1978
- self.friction_smoothing = friction_smoothing
1979
-
1980
- def simulate(self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None):
1981
- with wp.ScopedTimer("simulate", False):
1982
- particle_f = None
1983
- body_f = None
1984
-
1985
- if state_in.particle_count:
1986
- particle_f = state_in.particle_f
1987
-
1988
- if state_in.body_count:
1989
- body_f = state_in.body_f
1990
-
1991
- if control is None:
1992
- control = model.control(clone_variables=False)
1993
-
1994
- compute_forces(model, state_in, control, particle_f, body_f, dt, friction_smoothing=self.friction_smoothing)
1995
-
1996
- self.integrate_bodies(model, state_in, state_out, dt, self.angular_damping)
1997
-
1998
- self.integrate_particles(model, state_in, state_out, dt)
1999
-
2000
- return state_out