warp-lang 1.7.0__py3-none-manylinux_2_34_aarch64.whl

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

Potentially problematic release.


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

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