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
warp/sim/import_usd.py ADDED
@@ -0,0 +1,894 @@
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 re
17
+
18
+ import numpy as np
19
+
20
+ import warp as wp
21
+
22
+
23
+ def parse_usd(
24
+ source,
25
+ builder,
26
+ default_density=1.0e3,
27
+ only_load_enabled_rigid_bodies=False,
28
+ only_load_enabled_joints=True,
29
+ contact_ke=1e5,
30
+ contact_kd=250.0,
31
+ contact_kf=500.0,
32
+ contact_ka=0.0,
33
+ contact_mu=0.6,
34
+ contact_restitution=0.0,
35
+ contact_thickness=0.0,
36
+ joint_limit_ke=100.0,
37
+ joint_limit_kd=10.0,
38
+ armature=0.0,
39
+ invert_rotations=False,
40
+ verbose=False,
41
+ ignore_paths=None,
42
+ ):
43
+ """
44
+ Parses a Universal Scene Description (USD) stage containing UsdPhysics schema definitions for rigid-body articulations and adds the bodies, shapes and joints to the given ModelBuilder.
45
+
46
+ The USD description has to be either a path (file name or URL), or an existing USD stage instance that implements the `UsdStage <https://openusd.org/dev/api/class_usd_stage.html>`_ interface.
47
+
48
+ Args:
49
+ source (str | pxr.UsdStage): The file path to the USD file, or an existing USD stage instance.
50
+ builder (ModelBuilder): The :class:`ModelBuilder` to add the bodies and joints to.
51
+ default_density (float): The default density to use for bodies without a density attribute.
52
+ only_load_enabled_rigid_bodies (bool): If True, only rigid bodies which do not have `physics:rigidBodyEnabled` set to False are loaded.
53
+ only_load_enabled_joints (bool): If True, only joints which do not have `physics:jointEnabled` set to False are loaded.
54
+ contact_ke (float): The default contact stiffness to use, only considered by the Euler integrators.
55
+ contact_kd (float): The default contact damping to use, only considered by the Euler integrators.
56
+ contact_kf (float): The default friction stiffness to use, only considered by the Euler integrators.
57
+ contact_ka (float): The default adhesion distance to use, only considered by the Euler integrators.
58
+ contact_mu (float): The default friction coefficient to use if a shape has not friction coefficient defined.
59
+ contact_restitution (float): The default coefficient of restitution to use if a shape has not coefficient of restitution defined.
60
+ contact_thickness (float): The thickness to add to the shape geometry.
61
+ joint_limit_ke (float): The default stiffness to use for joint limits, only considered by the Euler integrators.
62
+ joint_limit_kd (float): The default damping to use for joint limits, only considered by the Euler integrators.
63
+ armature (float): The armature to use for the bodies.
64
+ invert_rotations (bool): If True, inverts any rotations defined in the shape transforms.
65
+ verbose (bool): If True, print additional information about the parsed USD file.
66
+ ignore_paths (List[str]): A list of regular expressions matching prim paths to ignore.
67
+
68
+ Returns:
69
+ dict: Dictionary with the following entries:
70
+
71
+ .. list-table::
72
+ :widths: 25 75
73
+
74
+ * - "fps"
75
+ - USD stage frames per second
76
+ * - "duration"
77
+ - Difference between end time code and start time code of the USD stage
78
+ * - "up_axis"
79
+ - Upper-case string of the stage's up axis ("X", "Y", or "Z")
80
+ * - "path_shape_map"
81
+ - Mapping from prim path (str) of the UsdGeom to the respective shape index in :class:`ModelBuilder`
82
+ * - "path_body_map"
83
+ - Mapping from prim path (str) of a rigid body prim (e.g. that implements the PhysicsRigidBodyAPI) to the respective body index in :class:`ModelBuilder`
84
+ * - "path_shape_scale"
85
+ - Mapping from prim path (str) of the UsdGeom to its respective 3D world scale
86
+ * - "mass_unit"
87
+ - The stage's Kilograms Per Unit (KGPU) definition (1.0 by default)
88
+ * - "linear_unit"
89
+ - The stage's Meters Per Unit (MPU) definition (1.0 by default)
90
+
91
+
92
+ Note:
93
+ This importer is experimental and only supports a subset of the USD Physics schema. Please report any issues you encounter.
94
+ """
95
+ try:
96
+ from pxr import Usd, UsdGeom, UsdPhysics
97
+ except ImportError as e:
98
+ raise ImportError("Failed to import pxr. Please install USD (e.g. via `pip install usd-core`).") from e
99
+
100
+ if ignore_paths is None:
101
+ ignore_paths = []
102
+
103
+ def get_attribute(prim, name):
104
+ if "*" in name:
105
+ regex = name.replace("*", ".*")
106
+ for attr in prim.GetAttributes():
107
+ if re.match(regex, attr.GetName()):
108
+ return attr
109
+ else:
110
+ return prim.GetAttribute(name)
111
+
112
+ def has_attribute(prim, name):
113
+ attr = get_attribute(prim, name)
114
+ return attr.IsValid() and attr.HasAuthoredValue()
115
+
116
+ def parse_float(prim, name, default=None):
117
+ attr = get_attribute(prim, name)
118
+ if not attr or not attr.HasAuthoredValue():
119
+ return default
120
+ val = attr.Get()
121
+ if np.isfinite(val):
122
+ return val
123
+ return default
124
+
125
+ def parse_quat(prim, name, default=None):
126
+ attr = get_attribute(prim, name)
127
+ if not attr or not attr.HasAuthoredValue():
128
+ return default
129
+ val = attr.Get()
130
+ if invert_rotations:
131
+ quat = wp.quat(*val.imaginary, -val.real)
132
+ else:
133
+ quat = wp.quat(*val.imaginary, val.real)
134
+ l = wp.length(quat)
135
+ if np.isfinite(l) and l > 0.0:
136
+ return quat
137
+ return default
138
+
139
+ def parse_vec(prim, name, default=None):
140
+ attr = get_attribute(prim, name)
141
+ if not attr or not attr.HasAuthoredValue():
142
+ return default
143
+ val = attr.Get()
144
+ if np.isfinite(val).all():
145
+ return np.array(val, dtype=np.float32)
146
+ return default
147
+
148
+ def parse_generic(prim, name, default=None):
149
+ attr = get_attribute(prim, name)
150
+ if not attr or not attr.HasAuthoredValue():
151
+ return default
152
+ return attr.Get()
153
+
154
+ def str2axis(s: str) -> np.ndarray:
155
+ axis = np.zeros(3, dtype=np.float32)
156
+ axis["XYZ".index(s.upper())] = 1.0
157
+ return axis
158
+
159
+ if isinstance(source, str):
160
+ stage = Usd.Stage.Open(source, Usd.Stage.LoadAll)
161
+ else:
162
+ stage = source
163
+
164
+ mass_unit = 1.0
165
+ try:
166
+ if UsdPhysics.StageHasAuthoredKilogramsPerUnit(stage):
167
+ mass_unit = UsdPhysics.GetStageKilogramsPerUnit(stage)
168
+ except Exception as e:
169
+ if verbose:
170
+ print(f"Failed to get mass unit: {e}")
171
+ linear_unit = 1.0
172
+ try:
173
+ if UsdGeom.StageHasAuthoredMetersPerUnit(stage):
174
+ linear_unit = UsdGeom.GetStageMetersPerUnit(stage)
175
+ except Exception as e:
176
+ if verbose:
177
+ print(f"Failed to get linear unit: {e}")
178
+
179
+ def parse_xform(prim):
180
+ xform = UsdGeom.Xform(prim)
181
+ mat = np.array(xform.GetLocalTransformation(), dtype=np.float32)
182
+ if invert_rotations:
183
+ rot = wp.quat_from_matrix(wp.mat33(mat[:3, :3].T.flatten()))
184
+ else:
185
+ rot = wp.quat_from_matrix(wp.mat33(mat[:3, :3].flatten()))
186
+ pos = mat[3, :3] * linear_unit
187
+ scale = np.ones(3, dtype=np.float32)
188
+ for op in xform.GetOrderedXformOps():
189
+ if op.GetOpType() == UsdGeom.XformOp.TypeScale:
190
+ scale = np.array(op.Get(), dtype=np.float32)
191
+ return wp.transform(pos, rot), scale
192
+
193
+ def parse_axis(prim, type, joint_data, is_angular, axis=None):
194
+ # parse joint axis data
195
+ schemas = prim.GetAppliedSchemas()
196
+ schemas_str = "".join(schemas)
197
+ if f"DriveAPI:{type}" not in schemas_str and f"PhysicsLimitAPI:{type}" not in schemas_str:
198
+ return
199
+ drive_type = parse_generic(prim, f"drive:{type}:physics:type", "force")
200
+ if drive_type != "force":
201
+ print(f"Warning: only force drive type is supported, ignoring drive:{type} for joint {path}")
202
+ return
203
+ stiffness = parse_float(prim, f"drive:{type}:physics:stiffness", 0.0)
204
+ damping = parse_float(prim, f"drive:{type}:physics:damping", 0.0)
205
+ low = parse_float(prim, f"limit:{type}:physics:low")
206
+ high = parse_float(prim, f"limit:{type}:physics:high")
207
+ target_pos = parse_float(prim, f"drive:{type}:physics:targetPosition")
208
+ target_vel = parse_float(prim, f"drive:{type}:physics:targetVelocity")
209
+ if is_angular:
210
+ stiffness *= mass_unit * linear_unit**2
211
+ stiffness = np.deg2rad(stiffness)
212
+ damping *= mass_unit * linear_unit**2
213
+ damping = np.deg2rad(damping)
214
+ if target_pos is not None:
215
+ target_pos = np.deg2rad(target_pos)
216
+ if target_vel is not None:
217
+ target_vel = np.deg2rad(target_vel)
218
+ if low is None:
219
+ low = joint_data["lowerLimit"]
220
+ else:
221
+ low = np.deg2rad(low)
222
+ if high is None:
223
+ high = joint_data["upperLimit"]
224
+ else:
225
+ high = np.deg2rad(high)
226
+ else:
227
+ stiffness *= mass_unit
228
+ damping *= mass_unit
229
+ if target_pos is not None:
230
+ target_pos *= linear_unit
231
+ if target_vel is not None:
232
+ target_vel *= linear_unit
233
+ if low is None:
234
+ low = joint_data["lowerLimit"]
235
+ else:
236
+ low *= linear_unit
237
+ if high is None:
238
+ high = joint_data["upperLimit"]
239
+ else:
240
+ high *= linear_unit
241
+
242
+ mode = wp.sim.JOINT_MODE_FORCE
243
+ if f"DriveAPI:{type}" in schemas_str:
244
+ if target_vel is not None and target_vel != 0.0:
245
+ mode = wp.sim.JOINT_MODE_TARGET_VELOCITY
246
+ else:
247
+ mode = wp.sim.JOINT_MODE_TARGET_POSITION
248
+ if low > high:
249
+ low = (low + high) / 2
250
+ high = low
251
+ axis = wp.sim.JointAxis(
252
+ axis=(axis or joint_data["axis"]),
253
+ limit_lower=low,
254
+ limit_upper=high,
255
+ action=(target_pos or target_vel or (low + high) / 2),
256
+ target_ke=stiffness,
257
+ target_kd=damping,
258
+ mode=mode,
259
+ limit_ke=joint_limit_ke,
260
+ limit_kd=joint_limit_kd,
261
+ )
262
+ if is_angular:
263
+ joint_data["angular_axes"].append(axis)
264
+ else:
265
+ joint_data["linear_axes"].append(axis)
266
+
267
+ axis_str = "Y"
268
+ try:
269
+ axis_str = UsdGeom.GetStageUpAxis(stage)
270
+ except Exception as e:
271
+ if verbose:
272
+ print(f"Failed to parse stage up axis: {e}")
273
+ upaxis = str2axis(axis_str)
274
+
275
+ shape_types = {"Cube", "Sphere", "Mesh", "Capsule", "Plane", "Cylinder", "Cone"}
276
+
277
+ path_body_map = {}
278
+ path_shape_map = {}
279
+ path_shape_scale = {}
280
+ # maps prim path name to its world transform
281
+ path_world_poses = {}
282
+ # transform from body frame to where the actual joint child frame is
283
+ # so that the link's children will use the right parent tf for the joint
284
+ prim_joint_xforms = {}
285
+ path_collision_filters = set()
286
+ no_collision_shapes = set()
287
+
288
+ body_density = {} # mapping from body ID to defined density
289
+
290
+ # first find all joints and materials
291
+ joint_data = {} # mapping from path of child link to joint USD settings
292
+ materials = {} # mapping from material path to material USD settings
293
+ joint_parents = set() # paths of joint parents
294
+ for prim in stage.Traverse():
295
+ type_name = str(prim.GetTypeName())
296
+ path = str(prim.GetPath())
297
+ # if verbose:
298
+ # print(path, type_name)
299
+ if type_name.endswith("Joint"):
300
+ # the type name can sometimes be "DistancePhysicsJoint" or "PhysicsDistanceJoint" ...
301
+ type_name = type_name.replace("Physics", "").replace("Joint", "")
302
+ child = str(prim.GetRelationship("physics:body1").GetTargets()[0])
303
+ pos0 = parse_vec(prim, "physics:localPos0", np.zeros(3, dtype=np.float32)) * linear_unit
304
+ pos1 = parse_vec(prim, "physics:localPos1", np.zeros(3, dtype=np.float32)) * linear_unit
305
+ rot0 = parse_quat(prim, "physics:localRot0", wp.quat_identity())
306
+ rot1 = parse_quat(prim, "physics:localRot1", wp.quat_identity())
307
+ joint_data[child] = {
308
+ "type": type_name,
309
+ "name": str(prim.GetName()),
310
+ "parent_tf": wp.transform(pos0, rot0),
311
+ "child_tf": wp.transform(pos1, rot1),
312
+ "enabled": parse_generic(prim, "physics:jointEnabled", True),
313
+ "collisionEnabled": parse_generic(prim, "physics:collisionEnabled", False),
314
+ "excludeFromArticulation": parse_generic(prim, "physics:excludeFromArticulation", False),
315
+ "axis": str2axis(parse_generic(prim, "physics:axis", "X")),
316
+ "breakForce": parse_float(prim, "physics:breakForce", np.inf),
317
+ "breakTorque": parse_float(prim, "physics:breakTorque", np.inf),
318
+ "linear_axes": [],
319
+ "angular_axes": [],
320
+ }
321
+ if only_load_enabled_joints and not joint_data[child]["enabled"]:
322
+ print("Skipping disabled joint", path)
323
+ continue
324
+ # parse joint limits
325
+ lower = parse_float(prim, "physics:lowerLimit", -np.inf)
326
+ upper = parse_float(prim, "physics:upperLimit", np.inf)
327
+ if type_name == "Distance":
328
+ # if distance is negative the joint is not limited
329
+ joint_data[child]["lowerLimit"] = parse_float(prim, "physics:minDistance", -1.0) * linear_unit
330
+ joint_data[child]["upperLimit"] = parse_float(prim, "physics:maxDistance", -1.0) * linear_unit
331
+ elif type_name == "Prismatic":
332
+ joint_data[child]["lowerLimit"] = lower * linear_unit
333
+ joint_data[child]["upperLimit"] = upper * linear_unit
334
+ else:
335
+ joint_data[child]["lowerLimit"] = np.deg2rad(lower) if np.isfinite(lower) else lower
336
+ joint_data[child]["upperLimit"] = np.deg2rad(upper) if np.isfinite(upper) else upper
337
+
338
+ if joint_data[child]["lowerLimit"] > joint_data[child]["upperLimit"]:
339
+ joint_data[child]["lowerLimit"] = (
340
+ joint_data[child]["lowerLimit"] + joint_data[child]["upperLimit"]
341
+ ) / 2
342
+ joint_data[child]["upperLimit"] = joint_data[child]["lowerLimit"]
343
+ parents = prim.GetRelationship("physics:body0").GetTargets()
344
+ if len(parents) > 0:
345
+ parent_path = str(parents[0])
346
+ joint_data[child]["parent"] = parent_path
347
+ joint_parents.add(parent_path)
348
+ else:
349
+ joint_data[child]["parent"] = None
350
+
351
+ # parse joint drive
352
+ parse_axis(prim, "angular", joint_data[child], is_angular=True)
353
+ parse_axis(prim, "rotX", joint_data[child], is_angular=True, axis=(1.0, 0.0, 0.0))
354
+ parse_axis(prim, "rotY", joint_data[child], is_angular=True, axis=(0.0, 1.0, 0.0))
355
+ parse_axis(prim, "rotZ", joint_data[child], is_angular=True, axis=(0.0, 0.0, 1.0))
356
+ parse_axis(prim, "linear", joint_data[child], is_angular=False)
357
+ parse_axis(prim, "transX", joint_data[child], is_angular=False, axis=(1.0, 0.0, 0.0))
358
+ parse_axis(prim, "transY", joint_data[child], is_angular=False, axis=(0.0, 1.0, 0.0))
359
+ parse_axis(prim, "transZ", joint_data[child], is_angular=False, axis=(0.0, 0.0, 1.0))
360
+
361
+ elif type_name == "Material":
362
+ material = {}
363
+ if has_attribute(prim, "physics:density"):
364
+ material["density"] = parse_float(prim, "physics:density") * mass_unit # / (linear_unit**3)
365
+ if has_attribute(prim, "physics:restitution"):
366
+ material["restitution"] = parse_float(prim, "physics:restitution", contact_restitution)
367
+ if has_attribute(prim, "physics:staticFriction"):
368
+ material["staticFriction"] = parse_float(prim, "physics:staticFriction", contact_mu)
369
+ if has_attribute(prim, "physics:dynamicFriction"):
370
+ material["dynamicFriction"] = parse_float(prim, "physics:dynamicFriction", contact_mu)
371
+ materials[path] = material
372
+
373
+ elif type_name == "PhysicsScene":
374
+ try:
375
+ scene = UsdPhysics.Scene(prim)
376
+ g_vec = scene.GetGravityDirectionAttr()
377
+ g_mag = scene.GetGravityMagnitudeAttr()
378
+ if g_mag.HasAuthoredValue() and np.isfinite(g_mag.Get()):
379
+ builder.gravity = -np.abs(g_mag.Get() * linear_unit)
380
+ if g_vec.HasAuthoredValue() and np.linalg.norm(g_vec.Get()) > 0.0:
381
+ builder.up_vector = np.array(g_vec.Get(), dtype=np.float32)
382
+ if np.any(builder.up_vector < 0.0):
383
+ builder.up_vector = -builder.up_vector
384
+ else:
385
+ builder.up_vector = upaxis
386
+ except Exception as e:
387
+ if verbose:
388
+ print(f"Failed to parse physics scene: {e}")
389
+
390
+ def parse_prim(prim, incoming_xform, incoming_scale, parent_body: int = -1):
391
+ nonlocal builder
392
+ nonlocal joint_data
393
+ nonlocal path_body_map
394
+ nonlocal path_shape_map
395
+ nonlocal path_shape_scale
396
+ nonlocal path_world_poses
397
+ nonlocal prim_joint_xforms
398
+ nonlocal path_collision_filters
399
+ nonlocal no_collision_shapes
400
+ nonlocal body_density
401
+
402
+ path = str(prim.GetPath())
403
+ for pattern in ignore_paths:
404
+ if re.match(pattern, path):
405
+ return
406
+
407
+ type_name = str(prim.GetTypeName())
408
+ if type_name.endswith("Joint") or type_name.endswith("Light") or type_name.endswith("Material"):
409
+ return
410
+ if verbose:
411
+ print(f"parse_prim {prim.GetPath()} ({type_name})")
412
+ if type_name == "PhysicsScene":
413
+ # in case the PhysicsScene has bodies as children...
414
+ for child in prim.GetChildren():
415
+ parse_prim(child, incoming_xform, incoming_scale, parent_body)
416
+
417
+ schemas = set(prim.GetAppliedSchemas())
418
+ children_refs = prim.GetChildren()
419
+
420
+ prim_joint_xforms[path] = wp.transform()
421
+
422
+ local_xform, scale = parse_xform(prim)
423
+ scale = incoming_scale * scale
424
+ xform = wp.mul(incoming_xform, local_xform)
425
+ path_world_poses[path] = xform
426
+
427
+ geo_tf = local_xform
428
+ body_id = parent_body
429
+ is_rigid_body = "PhysicsRigidBodyAPI" in schemas and parent_body == -1
430
+ create_rigid_body = is_rigid_body or path in joint_parents
431
+ if create_rigid_body:
432
+ body_id = builder.add_body(
433
+ origin=xform,
434
+ name=prim.GetName(),
435
+ armature=armature,
436
+ )
437
+ path_body_map[path] = body_id
438
+ body_density[body_id] = 0.0
439
+
440
+ parent_body = body_id
441
+
442
+ geo_tf = wp.transform()
443
+
444
+ # set up joints between rigid bodies after the children have been added
445
+ if path in joint_data:
446
+ joint = joint_data[path]
447
+
448
+ joint_params = {
449
+ "child": body_id,
450
+ "linear_axes": joint["linear_axes"],
451
+ "angular_axes": joint["angular_axes"],
452
+ "name": joint["name"],
453
+ "enabled": joint["enabled"],
454
+ "parent_xform": joint["parent_tf"],
455
+ "child_xform": joint["child_tf"],
456
+ "armature": armature,
457
+ }
458
+
459
+ parent_path = joint["parent"]
460
+ if parent_path is None:
461
+ joint_params["parent"] = -1
462
+ parent_tf = wp.transform()
463
+ else:
464
+ joint_params["parent"] = path_body_map[parent_path]
465
+ parent_tf = path_world_poses[parent_path]
466
+
467
+ # the joint to which we are connected will transform this body already
468
+ geo_tf = wp.transform()
469
+
470
+ if verbose:
471
+ print(f"Adding joint {joint['name']} between {joint['parent']} and {path}")
472
+ print(" parent_xform", joint["parent_tf"])
473
+ print(" child_xform ", joint["child_tf"])
474
+ print(" parent_tf ", parent_tf)
475
+ print(f" geo_tf at {path} = {geo_tf} (xform was {xform})")
476
+
477
+ if joint["type"] == "Revolute":
478
+ joint_params["joint_type"] = wp.sim.JOINT_REVOLUTE
479
+ if len(joint_params["angular_axes"]) == 0:
480
+ joint_params["angular_axes"].append(
481
+ wp.sim.JointAxis(
482
+ joint["axis"],
483
+ limit_lower=joint["lowerLimit"],
484
+ limit_upper=joint["upperLimit"],
485
+ limit_ke=joint_limit_ke,
486
+ limit_kd=joint_limit_kd,
487
+ )
488
+ )
489
+ elif joint["type"] == "Prismatic":
490
+ joint_params["joint_type"] = wp.sim.JOINT_PRISMATIC
491
+ if len(joint_params["linear_axes"]) == 0:
492
+ joint_params["linear_axes"].append(
493
+ wp.sim.JointAxis(
494
+ joint["axis"],
495
+ limit_lower=joint["lowerLimit"],
496
+ limit_upper=joint["upperLimit"],
497
+ limit_ke=joint_limit_ke,
498
+ limit_kd=joint_limit_kd,
499
+ )
500
+ )
501
+ elif joint["type"] == "Spherical":
502
+ joint_params["joint_type"] = wp.sim.JOINT_BALL
503
+ elif joint["type"] == "Fixed":
504
+ joint_params["joint_type"] = wp.sim.JOINT_FIXED
505
+ elif joint["type"] == "Distance":
506
+ joint_params["joint_type"] = wp.sim.JOINT_DISTANCE
507
+ # we have to add a dummy linear X axis to define the joint limits
508
+ joint_params["linear_axes"].append(
509
+ wp.sim.JointAxis(
510
+ (1.0, 0.0, 0.0),
511
+ limit_lower=joint["lowerLimit"],
512
+ limit_upper=joint["upperLimit"],
513
+ limit_ke=joint_limit_ke,
514
+ limit_kd=joint_limit_kd,
515
+ )
516
+ )
517
+ elif joint["type"] == "":
518
+ joint_params["joint_type"] = wp.sim.JOINT_D6
519
+ else:
520
+ print(f"Warning: unsupported joint type {joint['type']} for {path}")
521
+
522
+ builder.add_joint(**joint_params)
523
+
524
+ elif is_rigid_body:
525
+ builder.add_joint_free(child=body_id)
526
+ # free joint; we set joint_q/qd, not body_q/qd since eval_fk is used after model creation
527
+ builder.joint_q[-4:] = xform.q
528
+ builder.joint_q[-7:-4] = xform.p
529
+ linear_vel = parse_vec(prim, "physics:velocity", np.zeros(3, dtype=np.float32)) * linear_unit
530
+ angular_vel = parse_vec(prim, "physics:angularVelocity", np.zeros(3, dtype=np.float32)) * linear_unit
531
+ builder.joint_qd[-6:-3] = angular_vel
532
+ builder.joint_qd[-3:] = linear_vel
533
+
534
+ if verbose:
535
+ print(f"added {type_name} body {body_id} ({path}) at {xform}")
536
+
537
+ density = None
538
+
539
+ material = None
540
+ if prim.HasRelationship("material:binding:physics"):
541
+ other_paths = prim.GetRelationship("material:binding:physics").GetTargets()
542
+ if len(other_paths) > 0:
543
+ material = materials[str(other_paths[0])]
544
+ if material is not None:
545
+ if "density" in material:
546
+ density = material["density"]
547
+ if has_attribute(prim, "physics:density"):
548
+ d = parse_float(prim, "physics:density")
549
+ density = d * mass_unit # / (linear_unit**3)
550
+
551
+ # assert prim.GetAttribute('orientation').Get() == "rightHanded", "Only right-handed orientations are supported."
552
+ enabled = parse_generic(prim, "physics:rigidBodyEnabled", True)
553
+ if only_load_enabled_rigid_bodies and not enabled:
554
+ if verbose:
555
+ print("Skipping disabled rigid body", path)
556
+ return
557
+ mass = parse_float(prim, "physics:mass")
558
+ if is_rigid_body:
559
+ if density is None:
560
+ density = default_density
561
+ body_density[body_id] = density
562
+ elif density is None:
563
+ if body_id >= 0:
564
+ density = body_density[body_id]
565
+ else:
566
+ density = 0.0
567
+
568
+ com = parse_vec(prim, "physics:centerOfMass", np.zeros(3, dtype=np.float32))
569
+ i_diag = parse_vec(prim, "physics:diagonalInertia", np.zeros(3, dtype=np.float32))
570
+ i_rot = parse_quat(prim, "physics:principalAxes", wp.quat_identity())
571
+
572
+ # parse children
573
+ if type_name == "Xform":
574
+ if prim.IsInstance():
575
+ proto = prim.GetPrototype()
576
+ for child in proto.GetChildren():
577
+ parse_prim(child, xform, scale, parent_body)
578
+ else:
579
+ for child in children_refs:
580
+ parse_prim(child, xform, scale, parent_body)
581
+ elif type_name == "Scope":
582
+ for child in children_refs:
583
+ parse_prim(child, incoming_xform, incoming_scale, parent_body)
584
+ elif type_name in shape_types:
585
+ # parse shapes
586
+ shape_params = {
587
+ "ke": contact_ke,
588
+ "kd": contact_kd,
589
+ "kf": contact_kf,
590
+ "ka": contact_ka,
591
+ "mu": contact_mu,
592
+ "restitution": contact_restitution,
593
+ }
594
+ if material is not None:
595
+ if "restitution" in material:
596
+ shape_params["restitution"] = material["restitution"]
597
+ if "dynamicFriction" in material:
598
+ shape_params["mu"] = material["dynamicFriction"]
599
+
600
+ if has_attribute(prim, "doubleSided") and not prim.GetAttribute("doubleSided").Get():
601
+ print(f"Warning: treating {path} as double-sided because single-sided collisions are not supported.")
602
+
603
+ if type_name == "Cube":
604
+ size = parse_float(prim, "size", 2.0)
605
+ if has_attribute(prim, "extents"):
606
+ extents = parse_vec(prim, "extents") * scale
607
+ # TODO position geom at extents center?
608
+ # geo_pos = 0.5 * (extents[0] + extents[1])
609
+ extents = extents[1] - extents[0]
610
+ else:
611
+ extents = scale * size
612
+ shape_id = builder.add_shape_box(
613
+ body_id,
614
+ geo_tf.p,
615
+ geo_tf.q,
616
+ hx=extents[0] / 2,
617
+ hy=extents[1] / 2,
618
+ hz=extents[2] / 2,
619
+ density=density,
620
+ thickness=contact_thickness,
621
+ **shape_params,
622
+ )
623
+ elif type_name == "Sphere":
624
+ if not (scale[0] == scale[1] == scale[2]):
625
+ print("Warning: Non-uniform scaling of spheres is not supported.")
626
+ if has_attribute(prim, "extents"):
627
+ extents = parse_vec(prim, "extents") * scale
628
+ # TODO position geom at extents center?
629
+ # geo_pos = 0.5 * (extents[0] + extents[1])
630
+ extents = extents[1] - extents[0]
631
+ if not (extents[0] == extents[1] == extents[2]):
632
+ print("Warning: Non-uniform extents of spheres are not supported.")
633
+ radius = extents[0]
634
+ else:
635
+ radius = parse_float(prim, "radius", 1.0) * scale[0]
636
+ shape_id = builder.add_shape_sphere(
637
+ body_id, geo_tf.p, geo_tf.q, radius, density=density, **shape_params
638
+ )
639
+ elif type_name == "Plane":
640
+ normal_str = parse_generic(prim, "axis", "Z").upper()
641
+ geo_rot = geo_tf.q
642
+ if normal_str != "Y":
643
+ normal = str2axis(normal_str)
644
+ c = np.cross(normal, (0.0, 1.0, 0.0))
645
+ angle = np.arcsin(np.linalg.norm(c))
646
+ axis = c / np.linalg.norm(c)
647
+ geo_rot = wp.mul(geo_rot, wp.quat_from_axis_angle(axis, angle))
648
+ width = parse_float(prim, "width", 0.0) * scale[0]
649
+ length = parse_float(prim, "length", 0.0) * scale[1]
650
+ shape_id = builder.add_shape_plane(
651
+ body=body_id,
652
+ pos=geo_tf.p,
653
+ rot=geo_rot,
654
+ width=width,
655
+ length=length,
656
+ thickness=contact_thickness,
657
+ **shape_params,
658
+ )
659
+ elif type_name == "Capsule":
660
+ axis_str = parse_generic(prim, "axis", "Z").upper()
661
+ radius = parse_float(prim, "radius", 0.5) * scale[0]
662
+ half_height = parse_float(prim, "height", 2.0) / 2 * scale[1]
663
+ assert not has_attribute(prim, "extents"), "Capsule extents are not supported."
664
+ shape_id = builder.add_shape_capsule(
665
+ body_id,
666
+ geo_tf.p,
667
+ geo_tf.q,
668
+ radius,
669
+ half_height,
670
+ density=density,
671
+ up_axis="XYZ".index(axis_str),
672
+ **shape_params,
673
+ )
674
+ elif type_name == "Cylinder":
675
+ axis_str = parse_generic(prim, "axis", "Z").upper()
676
+ radius = parse_float(prim, "radius", 0.5) * scale[0]
677
+ half_height = parse_float(prim, "height", 2.0) / 2 * scale[1]
678
+ assert not has_attribute(prim, "extents"), "Cylinder extents are not supported."
679
+ shape_id = builder.add_shape_cylinder(
680
+ body_id,
681
+ geo_tf.p,
682
+ geo_tf.q,
683
+ radius,
684
+ half_height,
685
+ density=density,
686
+ up_axis="XYZ".index(axis_str),
687
+ **shape_params,
688
+ )
689
+ elif type_name == "Cone":
690
+ axis_str = parse_generic(prim, "axis", "Z").upper()
691
+ radius = parse_float(prim, "radius", 0.5) * scale[0]
692
+ half_height = parse_float(prim, "height", 2.0) / 2 * scale[1]
693
+ assert not has_attribute(prim, "extents"), "Cone extents are not supported."
694
+ shape_id = builder.add_shape_cone(
695
+ body_id,
696
+ geo_tf.p,
697
+ geo_tf.q,
698
+ radius,
699
+ half_height,
700
+ density=density,
701
+ up_axis="XYZ".index(axis_str),
702
+ **shape_params,
703
+ )
704
+ elif type_name == "Mesh":
705
+ mesh = UsdGeom.Mesh(prim)
706
+ points = np.array(mesh.GetPointsAttr().Get(), dtype=np.float32)
707
+ indices = np.array(mesh.GetFaceVertexIndicesAttr().Get(), dtype=np.float32)
708
+ counts = mesh.GetFaceVertexCountsAttr().Get()
709
+ faces = []
710
+ face_id = 0
711
+ for count in counts:
712
+ if count == 3:
713
+ faces.append(indices[face_id : face_id + 3])
714
+ elif count == 4:
715
+ faces.append(indices[face_id : face_id + 3])
716
+ faces.append(indices[[face_id, face_id + 2, face_id + 3]])
717
+ else:
718
+ # assert False, f"Error while parsing USD mesh {path}: encountered polygon with {count} vertices, but only triangles and quads are supported."
719
+ continue
720
+ face_id += count
721
+ m = wp.sim.Mesh(points, np.array(faces, dtype=np.int32).flatten())
722
+ shape_id = builder.add_shape_mesh(
723
+ body_id,
724
+ geo_tf.p,
725
+ geo_tf.q,
726
+ scale=scale,
727
+ mesh=m,
728
+ density=density,
729
+ thickness=contact_thickness,
730
+ **shape_params,
731
+ )
732
+ else:
733
+ print(f"Warning: Unsupported geometry type {type_name} at {path}.")
734
+ return
735
+
736
+ path_body_map[path] = body_id
737
+ path_shape_map[path] = shape_id
738
+ path_shape_scale[path] = scale
739
+
740
+ if prim.HasRelationship("physics:filteredPairs"):
741
+ other_paths = prim.GetRelationship("physics:filteredPairs").GetTargets()
742
+ for other_path in other_paths:
743
+ path_collision_filters.add((path, str(other_path)))
744
+
745
+ if "PhysicsCollisionAPI" not in schemas or not parse_generic(prim, "physics:collisionEnabled", True):
746
+ no_collision_shapes.add(shape_id)
747
+
748
+ else:
749
+ print(f"Warning: encountered unsupported prim type {type_name}")
750
+
751
+ # update mass properties of rigid bodies in cases where properties are defined with higher precedence
752
+ if body_id >= 0:
753
+ com = parse_vec(prim, "physics:centerOfMass")
754
+ if com is not None:
755
+ # overwrite COM
756
+ builder.body_com[body_id] = com * scale
757
+
758
+ if mass is not None and not (is_rigid_body and mass == 0.0):
759
+ mass_ratio = mass / builder.body_mass[body_id]
760
+ # mass has precedence over density, so we overwrite the mass computed from density
761
+ builder.body_mass[body_id] = mass * mass_unit
762
+ if mass > 0.0:
763
+ builder.body_inv_mass[body_id] = 1.0 / builder.body_mass[body_id]
764
+ else:
765
+ builder.body_inv_mass[body_id] = 0.0
766
+ # update inertia
767
+ builder.body_inertia[body_id] *= mass_ratio
768
+ if np.array(builder.body_inertia[body_id]).any():
769
+ builder.body_inv_inertia[body_id] = wp.inverse(builder.body_inertia[body_id])
770
+ else:
771
+ builder.body_inv_inertia[body_id] = wp.mat33(*np.zeros((3, 3), dtype=np.float32))
772
+
773
+ if np.linalg.norm(i_diag) > 0.0:
774
+ rot = np.array(wp.quat_to_matrix(i_rot), dtype=np.float32).reshape(3, 3)
775
+ inertia = rot @ np.diag(i_diag) @ rot.T
776
+ builder.body_inertia[body_id] = inertia
777
+ if inertia.any():
778
+ builder.body_inv_inertia[body_id] = wp.inverse(wp.mat33(*inertia))
779
+ else:
780
+ builder.body_inv_inertia[body_id] = wp.mat33(*np.zeros((3, 3), dtype=np.float32))
781
+
782
+ parse_prim(
783
+ stage.GetDefaultPrim(), incoming_xform=wp.transform(), incoming_scale=np.ones(3, dtype=np.float32) * linear_unit
784
+ )
785
+
786
+ shape_count = len(builder.shape_geo_type)
787
+
788
+ # apply collision filters now that we have added all shapes
789
+ for path1, path2 in path_collision_filters:
790
+ shape1 = path_shape_map[path1]
791
+ shape2 = path_shape_map[path2]
792
+ builder.shape_collision_filter_pairs.add((shape1, shape2))
793
+
794
+ # apply collision filters to all shapes that have no collision
795
+ for shape_id in no_collision_shapes:
796
+ for other_shape_id in range(shape_count):
797
+ if other_shape_id != shape_id:
798
+ builder.shape_collision_filter_pairs.add((shape_id, other_shape_id))
799
+
800
+ # return stage parameters
801
+ return {
802
+ "fps": stage.GetFramesPerSecond(),
803
+ "duration": stage.GetEndTimeCode() - stage.GetStartTimeCode(),
804
+ "up_axis": UsdGeom.GetStageUpAxis(stage).upper(),
805
+ "path_shape_map": path_shape_map,
806
+ "path_body_map": path_body_map,
807
+ "path_shape_scale": path_shape_scale,
808
+ "mass_unit": mass_unit,
809
+ "linear_unit": linear_unit,
810
+ }
811
+
812
+
813
+ def resolve_usd_from_url(url: str, target_folder_name: str = None, export_usda: bool = False):
814
+ """
815
+ Downloads a USD file from a URL and resolves all references to other USD files to be downloaded to the given target folder.
816
+
817
+ Args:
818
+ url (str): URL to the USD file.
819
+ target_folder_name (str): Target folder name. If None, a timestamped folder will be created in the current directory.
820
+ export_usda (bool): If True, converts each downloaded USD file to USDA and saves the additional USDA file in the target folder with the same base name as the original USD file.
821
+
822
+ Returns:
823
+ str: File path to the downloaded USD file.
824
+ """
825
+ import datetime
826
+ import os
827
+
828
+ import requests
829
+
830
+ try:
831
+ from pxr import Usd
832
+ except ImportError as e:
833
+ raise ImportError("Failed to import pxr. Please install USD (e.g. via `pip install usd-core`).") from e
834
+
835
+ response = requests.get(url, allow_redirects=True)
836
+ if response.status_code != 200:
837
+ raise RuntimeError(f"Failed to download USD file. Status code: {response.status_code}")
838
+ file = response.content
839
+ dot = os.path.extsep
840
+ base = os.path.basename(url)
841
+ url_folder = os.path.dirname(url)
842
+ base_name = dot.join(base.split(dot)[:-1])
843
+ if target_folder_name is None:
844
+ timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
845
+ target_folder_name = os.path.join(".usd_cache", f"{base_name}_{timestamp}")
846
+ os.makedirs(target_folder_name, exist_ok=True)
847
+ target_filename = os.path.join(target_folder_name, base)
848
+ with open(target_filename, "wb") as f:
849
+ f.write(file)
850
+
851
+ stage = Usd.Stage.Open(target_filename, Usd.Stage.LoadNone)
852
+ stage_str = stage.GetRootLayer().ExportToString()
853
+ print(f"Downloaded USD file to {target_filename}.")
854
+ if export_usda:
855
+ usda_filename = os.path.join(target_folder_name, base_name + ".usda")
856
+ with open(usda_filename, "w") as f:
857
+ f.write(stage_str)
858
+ print(f"Exported USDA file to {usda_filename}.")
859
+
860
+ # parse referenced USD files like `references = @./franka_collisions.usd@`
861
+ downloaded = set()
862
+ for match in re.finditer(r"references.=.@(.*?)@", stage_str):
863
+ refname = match.group(1)
864
+ if refname.startswith("./"):
865
+ refname = refname[2:]
866
+ if refname in downloaded:
867
+ continue
868
+ try:
869
+ response = requests.get(f"{url_folder}/{refname}", allow_redirects=True)
870
+ if response.status_code != 200:
871
+ print(f"Failed to download reference {refname}. Status code: {response.status_code}")
872
+ continue
873
+ file = response.content
874
+ refdir = os.path.dirname(refname)
875
+ if refdir:
876
+ os.makedirs(os.path.join(target_folder_name, refdir), exist_ok=True)
877
+ ref_filename = os.path.join(target_folder_name, refname)
878
+ if not os.path.exists(ref_filename):
879
+ with open(ref_filename, "wb") as f:
880
+ f.write(file)
881
+ downloaded.add(refname)
882
+ print(f"Downloaded USD reference {refname} to {ref_filename}.")
883
+ if export_usda:
884
+ ref_stage = Usd.Stage.Open(ref_filename, Usd.Stage.LoadNone)
885
+ ref_stage_str = ref_stage.GetRootLayer().ExportToString()
886
+ base = os.path.basename(ref_filename)
887
+ base_name = dot.join(base.split(dot)[:-1])
888
+ usda_filename = os.path.join(target_folder_name, base_name + ".usda")
889
+ with open(usda_filename, "w") as f:
890
+ f.write(ref_stage_str)
891
+ print(f"Exported USDA file to {usda_filename}.")
892
+ except Exception:
893
+ print(f"Failed to download {refname}.")
894
+ return target_filename