warp-lang 1.7.0__py3-none-manylinux_2_28_x86_64.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,258 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2024 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
+ import numpy as np
17
+
18
+ import warp as wp
19
+ import warp.examples
20
+ import warp.sim
21
+ from warp.sim.graph_coloring import (
22
+ ColoringAlgorithm,
23
+ construct_trimesh_graph_edges,
24
+ convert_to_color_groups,
25
+ validate_graph_coloring,
26
+ )
27
+ from warp.tests.unittest_utils import *
28
+
29
+
30
+ def color_lattice_grid(num_x, num_y):
31
+ colors = []
32
+ for _ in range(4):
33
+ colors.append([])
34
+
35
+ for xi in range(num_x + 1):
36
+ for yi in range(num_y + 1):
37
+ node_dx = yi * (num_x + 1) + xi
38
+
39
+ a = 1 if xi % 2 else 0
40
+ b = 1 if yi % 2 else 0
41
+
42
+ c = b * 2 + a
43
+
44
+ colors[c].append(node_dx)
45
+
46
+ color_groups = [np.array(group) for group in colors]
47
+
48
+ return color_groups
49
+
50
+
51
+ @unittest.skipUnless(USD_AVAILABLE, "Requires usd-core")
52
+ def test_coloring_trimesh(test, device):
53
+ from pxr import Usd, UsdGeom
54
+
55
+ with wp.ScopedDevice(device):
56
+ usd_stage = Usd.Stage.Open(os.path.join(wp.examples.get_asset_directory(), "bunny.usd"))
57
+ usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/root/bunny"))
58
+
59
+ vertices = np.array(usd_geom.GetPointsAttr().Get())
60
+ faces = np.array(usd_geom.GetFaceVertexIndicesAttr().Get())
61
+
62
+ builder = wp.sim.ModelBuilder()
63
+
64
+ builder.add_cloth_mesh(
65
+ pos=wp.vec3(0.0, 0.0, 0.0),
66
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
67
+ scale=1.0,
68
+ vertices=[wp.vec3(p) for p in vertices],
69
+ indices=faces.flatten(),
70
+ vel=wp.vec3(0.0, 0.0, 0.0),
71
+ density=0.02,
72
+ )
73
+
74
+ model = builder.finalize()
75
+
76
+ particle_colors = wp.empty(shape=(model.particle_count), dtype=int, device="cpu")
77
+
78
+ edge_indices_cpu = wp.array(model.edge_indices.numpy()[:, 2:], dtype=int, device="cpu")
79
+
80
+ # coloring without bending
81
+ num_colors_greedy = wp.context.runtime.core.graph_coloring(
82
+ model.particle_count,
83
+ edge_indices_cpu.__ctype__(),
84
+ ColoringAlgorithm.GREEDY.value,
85
+ particle_colors.__ctype__(),
86
+ )
87
+ wp.launch(
88
+ kernel=validate_graph_coloring,
89
+ inputs=[edge_indices_cpu, particle_colors],
90
+ dim=edge_indices_cpu.shape[0],
91
+ device="cpu",
92
+ )
93
+
94
+ num_colors_mcs = wp.context.runtime.core.graph_coloring(
95
+ model.particle_count,
96
+ edge_indices_cpu.__ctype__(),
97
+ ColoringAlgorithm.MCS.value,
98
+ particle_colors.__ctype__(),
99
+ )
100
+ wp.launch(
101
+ kernel=validate_graph_coloring,
102
+ inputs=[edge_indices_cpu, particle_colors],
103
+ dim=edge_indices_cpu.shape[0],
104
+ device="cpu",
105
+ )
106
+
107
+ # coloring with bending
108
+ edge_indices_cpu_with_bending = construct_trimesh_graph_edges(model.edge_indices, True)
109
+ num_colors_greedy = wp.context.runtime.core.graph_coloring(
110
+ model.particle_count,
111
+ edge_indices_cpu_with_bending.__ctype__(),
112
+ ColoringAlgorithm.GREEDY.value,
113
+ particle_colors.__ctype__(),
114
+ )
115
+ wp.context.runtime.core.balance_coloring(
116
+ model.particle_count,
117
+ edge_indices_cpu_with_bending.__ctype__(),
118
+ num_colors_greedy,
119
+ 1.1,
120
+ particle_colors.__ctype__(),
121
+ )
122
+ wp.launch(
123
+ kernel=validate_graph_coloring,
124
+ inputs=[edge_indices_cpu_with_bending, particle_colors],
125
+ dim=edge_indices_cpu_with_bending.shape[0],
126
+ device="cpu",
127
+ )
128
+
129
+ num_colors_mcs = wp.context.runtime.core.graph_coloring(
130
+ model.particle_count,
131
+ edge_indices_cpu_with_bending.__ctype__(),
132
+ ColoringAlgorithm.MCS.value,
133
+ particle_colors.__ctype__(),
134
+ )
135
+ max_min_ratio = wp.context.runtime.core.balance_coloring(
136
+ model.particle_count,
137
+ edge_indices_cpu_with_bending.__ctype__(),
138
+ num_colors_mcs,
139
+ 1.1,
140
+ particle_colors.__ctype__(),
141
+ )
142
+ wp.launch(
143
+ kernel=validate_graph_coloring,
144
+ inputs=[edge_indices_cpu_with_bending, particle_colors],
145
+ dim=edge_indices_cpu_with_bending.shape[0],
146
+ device="cpu",
147
+ )
148
+
149
+ color_categories_balanced = convert_to_color_groups(num_colors_mcs, particle_colors)
150
+
151
+ color_sizes = np.array([c.shape[0] for c in color_categories_balanced], dtype=np.float32)
152
+ test.assertTrue(np.max(color_sizes) / np.min(color_sizes) <= max_min_ratio)
153
+
154
+
155
+ @unittest.skipUnless(USD_AVAILABLE, "Requires usd-core")
156
+ def test_combine_coloring(test, device):
157
+ from pxr import Usd, UsdGeom
158
+
159
+ with wp.ScopedDevice(device):
160
+ builder1 = wp.sim.ModelBuilder()
161
+ usd_stage = Usd.Stage.Open(os.path.join(wp.examples.get_asset_directory(), "bunny.usd"))
162
+ usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/root/bunny"))
163
+
164
+ vertices = np.array(usd_geom.GetPointsAttr().Get())
165
+ faces = np.array(usd_geom.GetFaceVertexIndicesAttr().Get())
166
+
167
+ builder1.add_cloth_mesh(
168
+ pos=wp.vec3(0.0, 0.0, 0.0),
169
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
170
+ scale=1.0,
171
+ vertices=[wp.vec3(p) for p in vertices],
172
+ indices=faces.flatten(),
173
+ vel=wp.vec3(0.0, 0.0, 0.0),
174
+ density=0.02,
175
+ )
176
+
177
+ builder1.add_cloth_grid(
178
+ pos=wp.vec3(0.0, 4.0, 0.0),
179
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
180
+ vel=wp.vec3(0.0, 0.0, 0.0),
181
+ dim_x=50,
182
+ dim_y=100,
183
+ cell_x=0.1,
184
+ cell_y=0.1,
185
+ mass=0.1,
186
+ fix_left=True,
187
+ )
188
+ builder1.color()
189
+
190
+ builder2 = wp.sim.ModelBuilder()
191
+ builder2.add_cloth_grid(
192
+ pos=wp.vec3(0.0, 4.0, 0.0),
193
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
194
+ vel=wp.vec3(0.0, 0.0, 0.0),
195
+ dim_x=50,
196
+ dim_y=100,
197
+ cell_x=0.1,
198
+ cell_y=0.1,
199
+ mass=0.1,
200
+ # to include bending in coloring
201
+ edge_ke=100000,
202
+ fix_left=True,
203
+ )
204
+ builder2.color()
205
+
206
+ builder3 = wp.sim.ModelBuilder()
207
+ builder3.add_cloth_grid(
208
+ pos=wp.vec3(0.0, 4.0, 0.0),
209
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
210
+ vel=wp.vec3(0.0, 0.0, 0.0),
211
+ dim_x=50,
212
+ dim_y=100,
213
+ cell_x=0.1,
214
+ cell_y=0.1,
215
+ mass=0.1,
216
+ fix_left=True,
217
+ )
218
+
219
+ builder3.set_coloring(
220
+ color_lattice_grid(50, 100),
221
+ )
222
+
223
+ builder1.add_builder(builder2)
224
+ builder1.add_builder(builder3)
225
+
226
+ model = builder2.finalize()
227
+
228
+ particle_number_colored = np.full((model.particle_count), -1, dtype=int)
229
+ particle_colors = np.full((model.particle_count), -1, dtype=int)
230
+ for color, color_group in enumerate(model.particle_coloring):
231
+ particle_number_colored[color_group.numpy()] += 1
232
+ particle_colors[color_group.numpy()] = color
233
+
234
+ # all particles has been colored exactly once
235
+ assert_np_equal(particle_number_colored, 0)
236
+
237
+ edge_indices_cpu = wp.array(model.edge_indices.numpy()[:, 2:], dtype=int, device="cpu")
238
+ wp.launch(
239
+ kernel=validate_graph_coloring,
240
+ inputs=[edge_indices_cpu, wp.array(particle_colors, dtype=int, device="cpu")],
241
+ dim=edge_indices_cpu.shape[0],
242
+ device="cpu",
243
+ )
244
+
245
+
246
+ devices = get_test_devices()
247
+
248
+
249
+ class TestColoring(unittest.TestCase):
250
+ pass
251
+
252
+
253
+ add_function_test(TestColoring, "test_coloring_trimesh", test_coloring_trimesh, devices=devices)
254
+ add_function_test(TestColoring, "test_combine_coloring", test_combine_coloring, devices=devices)
255
+
256
+ if __name__ == "__main__":
257
+ wp.clear_kernel_cache()
258
+ unittest.main(verbosity=2)
@@ -0,0 +1,224 @@
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
+ import math
17
+ import unittest
18
+
19
+ import numpy as np
20
+
21
+ import warp as wp
22
+ from warp.sim import ModelBuilder
23
+ from warp.tests.unittest_utils import *
24
+
25
+
26
+ class TestModel(unittest.TestCase):
27
+ def test_add_triangles(self):
28
+ rng = np.random.default_rng(123)
29
+
30
+ pts = np.array(
31
+ [
32
+ [-0.00585869, 0.34189449, -1.17415233],
33
+ [-1.894547, 0.1788074, 0.9251329],
34
+ [-1.26141048, 0.16140787, 0.08823282],
35
+ [-0.08609255, -0.82722546, 0.65995427],
36
+ [0.78827592, -1.77375711, -0.55582718],
37
+ ]
38
+ )
39
+ tris = np.array([[0, 3, 4], [0, 2, 3], [2, 1, 3], [1, 4, 3]])
40
+
41
+ builder1 = ModelBuilder()
42
+ builder2 = ModelBuilder()
43
+ for pt in pts:
44
+ builder1.add_particle(wp.vec3(pt), wp.vec3(), 1.0)
45
+ builder2.add_particle(wp.vec3(pt), wp.vec3(), 1.0)
46
+
47
+ # test add_triangle(s) with default arguments:
48
+ areas = builder2.add_triangles(tris[:, 0], tris[:, 1], tris[:, 2])
49
+ for i, t in enumerate(tris):
50
+ area = builder1.add_triangle(t[0], t[1], t[2])
51
+ self.assertAlmostEqual(area, areas[i], places=6)
52
+
53
+ # test add_triangle(s) with non default arguments:
54
+ tri_ke = rng.standard_normal(size=pts.shape[0])
55
+ tri_ka = rng.standard_normal(size=pts.shape[0])
56
+ tri_kd = rng.standard_normal(size=pts.shape[0])
57
+ tri_drag = rng.standard_normal(size=pts.shape[0])
58
+ tri_lift = rng.standard_normal(size=pts.shape[0])
59
+ for i, t in enumerate(tris):
60
+ builder1.add_triangle(
61
+ t[0],
62
+ t[1],
63
+ t[2],
64
+ tri_ke[i],
65
+ tri_ka[i],
66
+ tri_kd[i],
67
+ tri_drag[i],
68
+ tri_lift[i],
69
+ )
70
+ builder2.add_triangles(tris[:, 0], tris[:, 1], tris[:, 2], tri_ke, tri_ka, tri_kd, tri_drag, tri_lift)
71
+
72
+ assert_np_equal(np.array(builder1.tri_indices), np.array(builder2.tri_indices))
73
+ assert_np_equal(np.array(builder1.tri_poses), np.array(builder2.tri_poses), tol=1.0e-6)
74
+ assert_np_equal(np.array(builder1.tri_activations), np.array(builder2.tri_activations))
75
+ assert_np_equal(np.array(builder1.tri_materials), np.array(builder2.tri_materials))
76
+
77
+ def test_add_edges(self):
78
+ rng = np.random.default_rng(123)
79
+
80
+ pts = np.array(
81
+ [
82
+ [-0.00585869, 0.34189449, -1.17415233],
83
+ [-1.894547, 0.1788074, 0.9251329],
84
+ [-1.26141048, 0.16140787, 0.08823282],
85
+ [-0.08609255, -0.82722546, 0.65995427],
86
+ [0.78827592, -1.77375711, -0.55582718],
87
+ ]
88
+ )
89
+ edges = np.array([[0, 4, 3, 1], [3, 2, 4, 1]])
90
+
91
+ builder1 = ModelBuilder()
92
+ builder2 = ModelBuilder()
93
+ for pt in pts:
94
+ builder1.add_particle(wp.vec3(pt), wp.vec3(), 1.0)
95
+ builder2.add_particle(wp.vec3(pt), wp.vec3(), 1.0)
96
+
97
+ # test defaults:
98
+ for i in range(2):
99
+ builder1.add_edge(edges[i, 0], edges[i, 1], edges[i, 2], edges[i, 3])
100
+ builder2.add_edges(edges[:, 0], edges[:, 1], edges[:, 2], edges[:, 3])
101
+
102
+ # test non defaults:
103
+ rest = rng.standard_normal(size=2)
104
+ edge_ke = rng.standard_normal(size=2)
105
+ edge_kd = rng.standard_normal(size=2)
106
+ for i in range(2):
107
+ builder1.add_edge(edges[i, 0], edges[i, 1], edges[i, 2], edges[i, 3], rest[i], edge_ke[i], edge_kd[i])
108
+ builder2.add_edges(edges[:, 0], edges[:, 1], edges[:, 2], edges[:, 3], rest, edge_ke, edge_kd)
109
+
110
+ assert_np_equal(np.array(builder1.edge_indices), np.array(builder2.edge_indices))
111
+ assert_np_equal(np.array(builder1.edge_rest_angle), np.array(builder2.edge_rest_angle), tol=1.0e-4)
112
+ assert_np_equal(np.array(builder1.edge_bending_properties), np.array(builder2.edge_bending_properties))
113
+
114
+ def test_collapse_fixed_joints(self):
115
+ def add_three_cubes(builder: ModelBuilder, parent_body=-1):
116
+ unit_cube = {"hx": 0.5, "hy": 0.5, "hz": 0.5, "density": 1.0}
117
+ b0 = builder.add_body()
118
+ builder.add_shape_box(body=b0, **unit_cube)
119
+ builder.add_joint_fixed(parent=parent_body, child=b0, parent_xform=wp.transform(wp.vec3(1.0, 0.0, 0.0)))
120
+ b1 = builder.add_body()
121
+ builder.add_shape_box(body=b1, **unit_cube)
122
+ builder.add_joint_fixed(parent=parent_body, child=b1, parent_xform=wp.transform(wp.vec3(0.0, 1.0, 0.0)))
123
+ b2 = builder.add_body()
124
+ builder.add_shape_box(body=b2, **unit_cube)
125
+ builder.add_joint_fixed(parent=parent_body, child=b2, parent_xform=wp.transform(wp.vec3(0.0, 0.0, 1.0)))
126
+ return b2
127
+
128
+ builder = ModelBuilder()
129
+ # only fixed joints
130
+ builder.add_articulation()
131
+ add_three_cubes(builder)
132
+ assert builder.joint_count == 3
133
+ assert builder.body_count == 3
134
+
135
+ # fixed joints followed by a non-fixed joint
136
+ builder.add_articulation()
137
+ last_body = add_three_cubes(builder)
138
+ assert builder.joint_count == 6
139
+ assert builder.body_count == 6
140
+ assert builder.articulation_count == 2
141
+ b3 = builder.add_body()
142
+ builder.add_shape_box(body=b3, hx=0.5, hy=0.5, hz=0.5, density=1.0, pos=wp.vec3(1.0, 2.0, 3.0))
143
+ builder.add_joint_revolute(parent=last_body, child=b3, axis=wp.vec3(0.0, 1.0, 0.0))
144
+
145
+ # a non-fixed joint followed by fixed joints
146
+ builder.add_articulation()
147
+ b4 = builder.add_body()
148
+ builder.add_shape_box(body=b4, hx=0.5, hy=0.5, hz=0.5, density=1.0)
149
+ builder.add_joint_free(parent=-1, child=b4, parent_xform=wp.transform(wp.vec3(0.0, -1.0, 0.0)))
150
+ assert builder.joint_count == 8
151
+ assert builder.body_count == 8
152
+ assert builder.articulation_count == 3
153
+ add_three_cubes(builder, parent_body=b4)
154
+
155
+ builder.collapse_fixed_joints()
156
+
157
+ assert builder.joint_count == 2
158
+ assert builder.articulation_count == 2
159
+ assert builder.articulation_start == [0, 1]
160
+ assert builder.joint_type == [wp.sim.JOINT_REVOLUTE, wp.sim.JOINT_FREE]
161
+ assert builder.shape_count == 11
162
+ assert builder.shape_body == [-1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1]
163
+ assert builder.body_count == 2
164
+ assert builder.body_com[0] == wp.vec3(1.0, 2.0, 3.0)
165
+ assert builder.body_com[1] == wp.vec3(0.25, 0.25, 0.25)
166
+ assert builder.body_mass == [1.0, 4.0]
167
+ assert builder.body_inv_mass == [1.0, 0.25]
168
+
169
+ # create another builder, test add_builder function
170
+ builder2 = ModelBuilder()
171
+ builder2.add_builder(builder)
172
+ assert builder2.articulation_count == builder.articulation_count
173
+ assert builder2.joint_count == builder.joint_count
174
+ assert builder2.body_count == builder.body_count
175
+ assert builder2.shape_count == builder.shape_count
176
+ assert builder2.articulation_start == builder.articulation_start
177
+ # add the same builder again
178
+ builder2.add_builder(builder)
179
+ assert builder2.articulation_count == 2 * builder.articulation_count
180
+ assert builder2.articulation_start == [0, 1, 2, 3]
181
+
182
+ def test_add_builder_with_open_edges(self):
183
+ builder = wp.sim.ModelBuilder()
184
+
185
+ dim_x = 16
186
+ dim_y = 16
187
+
188
+ env_builder = wp.sim.ModelBuilder()
189
+ env_builder.add_cloth_grid(
190
+ pos=wp.vec3(0.0, 0.0, 0.0),
191
+ vel=wp.vec3(0.1, 0.1, 0.0),
192
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), -math.pi * 0.25),
193
+ dim_x=dim_x,
194
+ dim_y=dim_y,
195
+ cell_x=1.0 / dim_x,
196
+ cell_y=1.0 / dim_y,
197
+ mass=1.0,
198
+ )
199
+
200
+ num_envs = 2
201
+ env_offsets = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]])
202
+
203
+ builder_open_edge_count = np.sum(np.array(builder.edge_indices) == -1)
204
+ env_builder_open_edge_count = np.sum(np.array(env_builder.edge_indices) == -1)
205
+
206
+ for i in range(num_envs):
207
+ xform = wp.transform(env_offsets[i], wp.quat_identity())
208
+ builder.add_builder(
209
+ env_builder,
210
+ xform,
211
+ update_num_env_count=True,
212
+ separate_collision_group=True,
213
+ )
214
+
215
+ self.assertEqual(
216
+ np.sum(np.array(builder.edge_indices) == -1),
217
+ builder_open_edge_count + num_envs * env_builder_open_edge_count,
218
+ "builder does not have the expected number of open edges",
219
+ )
220
+
221
+
222
+ if __name__ == "__main__":
223
+ wp.clear_kernel_cache()
224
+ unittest.main(verbosity=2)
@@ -0,0 +1,212 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 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
+ import numpy as np
17
+
18
+ import warp as wp
19
+ import warp.optim
20
+ import warp.sim
21
+ import warp.sim.render
22
+ from warp.tests.unittest_utils import *
23
+
24
+
25
+ @wp.kernel
26
+ def update_trajectory_kernel(
27
+ trajectory: wp.array(dtype=wp.vec3),
28
+ q: wp.array(dtype=wp.transform),
29
+ time_step: wp.int32,
30
+ q_idx: wp.int32,
31
+ ):
32
+ trajectory[time_step] = wp.transform_get_translation(q[q_idx])
33
+
34
+
35
+ @wp.kernel
36
+ def trajectory_loss_kernel(
37
+ trajectory: wp.array(dtype=wp.vec3f),
38
+ target_trajectory: wp.array(dtype=wp.vec3f),
39
+ loss: wp.array(dtype=wp.float32),
40
+ ):
41
+ tid = wp.tid()
42
+ diff = trajectory[tid] - target_trajectory[tid]
43
+ distance_loss = wp.dot(diff, diff)
44
+ wp.atomic_add(loss, 0, distance_loss)
45
+
46
+
47
+ class BallBounceLinearTest:
48
+ def __init__(self, gravity=True, rendering=False):
49
+ # Ball bouncing scenario inspired by https://github.com/NVIDIA/warp/issues/349
50
+ self.fps = 30
51
+ self.num_frames = 60
52
+ self.sim_substeps = 20 # XXX need to use enough substeps to achieve smooth gradients
53
+ self.frame_dt = 1.0 / self.fps
54
+ self.sim_dt = self.frame_dt / self.sim_substeps
55
+ self.sim_duration = self.num_frames * self.frame_dt
56
+ self.sim_steps = int(self.sim_duration // self.sim_dt)
57
+
58
+ self.target_force_linear = 100.0
59
+
60
+ if gravity:
61
+ builder = wp.sim.ModelBuilder(up_vector=wp.vec3(0, 0, 1))
62
+ else:
63
+ builder = wp.sim.ModelBuilder(gravity=0.0, up_vector=wp.vec3(0, 0, 1))
64
+
65
+ b = builder.add_body(origin=wp.transform((0.5, 0.0, 1.0), wp.quat_identity()), name="ball")
66
+ builder.add_shape_sphere(
67
+ body=b, radius=0.1, density=100.0, ke=2000.0, kd=10.0, kf=200.0, mu=0.2, thickness=0.01
68
+ )
69
+ builder.set_ground_plane(ke=10, kd=10, kf=0.0, mu=0.2)
70
+ self.model = builder.finalize(requires_grad=True)
71
+
72
+ self.time = np.linspace(0, self.sim_duration, self.sim_steps)
73
+
74
+ self.integrator = wp.sim.SemiImplicitIntegrator()
75
+ if rendering:
76
+ self.renderer = wp.sim.render.SimRendererOpenGL(self.model, "ball_bounce_linear")
77
+ else:
78
+ self.renderer = None
79
+
80
+ self.loss = wp.array([0], dtype=wp.float32, requires_grad=True)
81
+ self.states = [self.model.state() for _ in range(self.sim_steps + 1)]
82
+ self.target_states = [self.model.state() for _ in range(self.sim_steps + 1)]
83
+
84
+ self.target_force = wp.array([0.0, 0.0, 0.0, 0.0, self.target_force_linear, 0.0], dtype=wp.spatial_vectorf)
85
+
86
+ self.trajectory = wp.empty(len(self.time), dtype=wp.vec3, requires_grad=True)
87
+ self.target_trajectory = wp.empty(len(self.time), dtype=wp.vec3)
88
+
89
+ def _reset(self):
90
+ self.loss = wp.array([0], dtype=wp.float32, requires_grad=True)
91
+
92
+ def generate_target_trajectory(self):
93
+ for i in range(self.sim_steps):
94
+ curr_state = self.target_states[i]
95
+ next_state = self.target_states[i + 1]
96
+ curr_state.clear_forces()
97
+ if i == 0:
98
+ wp.copy(curr_state.body_f, self.target_force, dest_offset=0, src_offset=0, count=1)
99
+ wp.sim.collide(self.model, curr_state)
100
+ self.integrator.simulate(self.model, curr_state, next_state, self.sim_dt)
101
+ wp.launch(kernel=update_trajectory_kernel, dim=1, inputs=[self.target_trajectory, curr_state.body_q, i, 0])
102
+
103
+ def forward(self, force: wp.array):
104
+ for i in range(self.sim_steps):
105
+ curr_state = self.states[i]
106
+ next_state = self.states[i + 1]
107
+ curr_state.clear_forces()
108
+ if i == 0:
109
+ wp.copy(curr_state.body_f, force, dest_offset=0, src_offset=0, count=1)
110
+ wp.sim.collide(self.model, curr_state)
111
+ self.integrator.simulate(self.model, curr_state, next_state, self.sim_dt)
112
+ wp.launch(kernel=update_trajectory_kernel, dim=1, inputs=[self.trajectory, curr_state.body_q, i, 0])
113
+
114
+ if self.renderer:
115
+ self.renderer.begin_frame(self.time[i])
116
+ self.renderer.render(curr_state)
117
+ self.renderer.end_frame()
118
+
119
+ def step(self, force: wp.array):
120
+ self.tape = wp.Tape()
121
+ self._reset()
122
+ with self.tape:
123
+ self.forward(force)
124
+ wp.launch(
125
+ kernel=trajectory_loss_kernel,
126
+ dim=len(self.trajectory),
127
+ inputs=[self.trajectory, self.target_trajectory, self.loss],
128
+ )
129
+ self.tape.backward(self.loss)
130
+ force_grad = force.grad.numpy()[0, 4]
131
+ self.tape.zero()
132
+
133
+ return self.loss.numpy()[0], force_grad
134
+
135
+ def evaluate(self, num_samples, plot_results=False):
136
+ forces = np.linspace(0, self.target_force_linear * 2, num_samples)
137
+ losses = np.zeros_like(forces)
138
+ grads = np.zeros_like(forces)
139
+
140
+ for i, fx in enumerate(forces):
141
+ force = wp.array([[0.0, 0.0, 0.0, 0.0, fx, 0.0]], dtype=wp.spatial_vectorf, requires_grad=True)
142
+ losses[i], grads[i] = self.step(force)
143
+ if plot_results:
144
+ print(f"Iteration {i + 1}/{num_samples}")
145
+ print(f"Force: {fx:.2f}, Loss: {losses[i]:.6f}, Grad: {grads[i]:.6f}")
146
+
147
+ assert np.isfinite(losses[i])
148
+ assert np.isfinite(grads[i])
149
+ if i > 0:
150
+ assert grads[i] >= grads[i - 1]
151
+
152
+ if plot_results:
153
+ import matplotlib.pyplot as plt
154
+
155
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
156
+
157
+ # Plot the loss curve
158
+ ax1.plot(forces, losses, label="Loss")
159
+ ax1.set_xlabel("Force")
160
+ ax1.set_ylabel("Loss")
161
+ ax1.set_title("Loss vs Force")
162
+ ax1.legend()
163
+
164
+ # Make sure the grads are not too large
165
+ grads = np.clip(grads, -1e4, 1e4)
166
+
167
+ # Plot the gradient curve
168
+ ax2.plot(forces, grads, label="Gradient", color="orange")
169
+ ax2.set_xlabel("Force")
170
+ ax2.set_ylabel("Gradient")
171
+ ax2.set_title("Gradient vs Force")
172
+ ax2.legend()
173
+
174
+ plt.suptitle("Loss and Gradient vs Force")
175
+ plt.tight_layout(rect=[0, 0, 1, 0.95])
176
+ plt.show()
177
+
178
+ return losses, grads
179
+
180
+
181
+ def test_sim_grad_bounce_linear(test, device):
182
+ with wp.ScopedDevice(device):
183
+ model = BallBounceLinearTest()
184
+ model.generate_target_trajectory()
185
+
186
+ num_samples = 20
187
+ losses, grads = model.evaluate(num_samples=num_samples)
188
+ # gradients must approximate linear behavior with zero crossing in the middle
189
+ test.assertTrue(np.abs(grads[1:] - grads[:-1]).max() < 1.1)
190
+ test.assertTrue(np.all(grads[: num_samples // 2] <= 0.0))
191
+ test.assertTrue(np.all(grads[num_samples // 2 :] >= 0.0))
192
+ # losses must follow a parabolic behavior
193
+ test.assertTrue(np.allclose(losses[: num_samples // 2], losses[num_samples // 2 :][::-1], atol=1.0))
194
+ diffs = losses[1:] - losses[:-1]
195
+ test.assertTrue(np.all(diffs[: num_samples // 2 - 1] <= 0.0))
196
+ test.assertTrue(np.all(diffs[num_samples // 2 - 1 :] >= 0.0))
197
+ # second derivative must be constant positive
198
+ diffs2 = diffs[1:] - diffs[:-1]
199
+ test.assertTrue(np.allclose(diffs2, diffs2[0], atol=1e-2))
200
+ test.assertTrue(np.all(diffs2 >= 0.0))
201
+
202
+
203
+ class TestSimGradBounceLinear(unittest.TestCase):
204
+ pass
205
+
206
+
207
+ devices = get_test_devices("basic")
208
+ add_function_test(TestSimGradBounceLinear, "test_sim_grad_bounce_linear", test_sim_grad_bounce_linear, devices=devices)
209
+
210
+ if __name__ == "__main__":
211
+ wp.clear_kernel_cache()
212
+ unittest.main(verbosity=2, failfast=True)