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,1103 @@
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 os
17
+ import tempfile
18
+ import unittest
19
+ from typing import Any
20
+
21
+ import numpy as np
22
+
23
+ import warp as wp
24
+ from warp.tests.unittest_utils import *
25
+
26
+
27
+ # float volume tests
28
+ @wp.kernel
29
+ def test_volume_lookup_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
30
+ tid = wp.tid()
31
+
32
+ p = points[tid]
33
+ expected = p[0] * p[1] * p[2]
34
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
35
+ expected = 10.0
36
+
37
+ i = int(p[0])
38
+ j = int(p[1])
39
+ k = int(p[2])
40
+
41
+ expect_eq(wp.volume_lookup_f(volume, i, j, k), expected)
42
+ expect_eq(wp.volume_lookup(volume, i, j, k, dtype=wp.float32), expected)
43
+
44
+
45
+ @wp.kernel
46
+ def test_volume_sample_closest_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
47
+ tid = wp.tid()
48
+
49
+ p = points[tid]
50
+ i = round(p[0])
51
+ j = round(p[1])
52
+ k = round(p[2])
53
+ expected = i * j * k
54
+ if abs(i) > 10.0 or abs(j) > 10.0 or abs(k) > 10.0:
55
+ expected = 10.0
56
+
57
+ expect_eq(wp.volume_sample_f(volume, p, wp.Volume.CLOSEST), expected)
58
+ expect_eq(wp.volume_sample(volume, p, wp.Volume.CLOSEST, dtype=wp.float32), expected)
59
+
60
+ q = wp.volume_index_to_world(volume, p)
61
+ q_inv = wp.volume_world_to_index(volume, q)
62
+ expect_eq(p, q_inv)
63
+
64
+
65
+ @wp.kernel
66
+ def test_volume_sample_linear_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
67
+ tid = wp.tid()
68
+
69
+ p = points[tid]
70
+
71
+ expected = p[0] * p[1] * p[2]
72
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
73
+ return # not testing against background values
74
+
75
+ expect_near(wp.volume_sample_f(volume, p, wp.Volume.LINEAR), expected, 2.0e-4)
76
+ expect_near(wp.volume_sample(volume, p, wp.Volume.LINEAR, dtype=wp.float32), expected, 2.0e-4)
77
+
78
+
79
+ @wp.kernel
80
+ def test_volume_sample_grad_linear_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
81
+ tid = wp.tid()
82
+
83
+ p = points[tid]
84
+
85
+ expected_val = p[0] * p[1] * p[2]
86
+ expected_gx = p[1] * p[2]
87
+ expected_gy = p[0] * p[2]
88
+ expected_gz = p[0] * p[1]
89
+
90
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
91
+ return # not testing against background values
92
+
93
+ grad = wp.vec3(0.0, 0.0, 0.0)
94
+ val = wp.volume_sample_grad_f(volume, p, wp.Volume.LINEAR, grad)
95
+
96
+ expect_near(val, expected_val, 2.0e-4)
97
+ expect_near(grad[0], expected_gx, 2.0e-4)
98
+ expect_near(grad[1], expected_gy, 2.0e-4)
99
+ expect_near(grad[2], expected_gz, 2.0e-4)
100
+
101
+ val = wp.volume_sample_grad(volume, p, wp.Volume.LINEAR, grad, dtype=wp.float32)
102
+
103
+ expect_near(val, expected_val, 2.0e-4)
104
+ expect_near(grad[0], expected_gx, 2.0e-4)
105
+ expect_near(grad[1], expected_gy, 2.0e-4)
106
+ expect_near(grad[2], expected_gz, 2.0e-4)
107
+
108
+
109
+ @wp.kernel
110
+ def test_volume_sample_local_f_linear_values(
111
+ volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32)
112
+ ):
113
+ tid = wp.tid()
114
+ p = points[tid]
115
+ values[tid] = wp.volume_sample_f(volume, p, wp.Volume.LINEAR)
116
+
117
+
118
+ @wp.kernel
119
+ def test_volume_sample_grad_local_f_linear_values(
120
+ volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32), case_num: int
121
+ ):
122
+ tid = wp.tid()
123
+ p = points[tid]
124
+
125
+ grad = wp.vec3(0.0, 0.0, 0.0)
126
+ val = wp.volume_sample_grad_f(volume, p, wp.Volume.LINEAR, grad)
127
+ if case_num == 0:
128
+ values[tid] = val
129
+ elif case_num == 1:
130
+ values[tid] = grad[0]
131
+ elif case_num == 2:
132
+ values[tid] = grad[1]
133
+ elif case_num == 3:
134
+ values[tid] = grad[2]
135
+
136
+
137
+ @wp.kernel
138
+ def test_volume_sample_world_f_linear_values(
139
+ volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32)
140
+ ):
141
+ tid = wp.tid()
142
+ q = points[tid]
143
+ p = wp.volume_world_to_index(volume, q)
144
+ values[tid] = wp.volume_sample_f(volume, p, wp.Volume.LINEAR)
145
+
146
+
147
+ @wp.kernel
148
+ def test_volume_sample_grad_world_f_linear_values(
149
+ volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32), case_num: int
150
+ ):
151
+ tid = wp.tid()
152
+ q = points[tid]
153
+ p = wp.volume_world_to_index(volume, q)
154
+
155
+ grad = wp.vec3(0.0, 0.0, 0.0)
156
+ val = wp.volume_sample_grad_f(volume, p, wp.Volume.LINEAR, grad)
157
+ if case_num == 0:
158
+ values[tid] = val
159
+ elif case_num == 1:
160
+ values[tid] = grad[0]
161
+ elif case_num == 2:
162
+ values[tid] = grad[1]
163
+ elif case_num == 3:
164
+ values[tid] = grad[2]
165
+
166
+
167
+ # vec3f volume tests
168
+ @wp.kernel
169
+ def test_volume_lookup_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
170
+ tid = wp.tid()
171
+
172
+ p = points[tid]
173
+ expected = wp.vec3(
174
+ p[0] + 2.0 * p[1] + 3.0 * p[2], 4.0 * p[0] + 5.0 * p[1] + 6.0 * p[2], 7.0 * p[0] + 8.0 * p[1] + 9.0 * p[2]
175
+ )
176
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
177
+ expected = wp.vec3(10.8, -4.13, 10.26)
178
+
179
+ i = int(p[0])
180
+ j = int(p[1])
181
+ k = int(p[2])
182
+
183
+ expect_eq(wp.volume_lookup_v(volume, i, j, k), expected)
184
+ expect_eq(wp.volume_lookup(volume, i, j, k, dtype=wp.vec3), expected)
185
+
186
+
187
+ @wp.kernel
188
+ def test_volume_sample_closest_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
189
+ tid = wp.tid()
190
+
191
+ p = points[tid]
192
+ i = round(p[0])
193
+ j = round(p[1])
194
+ k = round(p[2])
195
+ expected = wp.vec3(i + 2.0 * j + 3.0 * k, 4.0 * i + 5.0 * j + 6.0 * k, 7.0 * i + 8.0 * j + 9.0 * k)
196
+ if abs(i) > 10.0 or abs(j) > 10.0 or abs(k) > 10.0:
197
+ expected = wp.vec3(10.8, -4.13, 10.26)
198
+
199
+ expect_eq(wp.volume_sample_v(volume, p, wp.Volume.CLOSEST), expected)
200
+ expect_eq(wp.volume_sample(volume, p, wp.Volume.CLOSEST, dtype=wp.vec3), expected)
201
+
202
+ q = wp.volume_index_to_world(volume, p)
203
+ q_inv = wp.volume_world_to_index(volume, q)
204
+ expect_eq(p, q_inv)
205
+
206
+
207
+ @wp.kernel
208
+ def test_volume_sample_linear_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
209
+ tid = wp.tid()
210
+
211
+ p = points[tid]
212
+
213
+ expected = wp.vec3(
214
+ p[0] + 2.0 * p[1] + 3.0 * p[2], 4.0 * p[0] + 5.0 * p[1] + 6.0 * p[2], 7.0 * p[0] + 8.0 * p[1] + 9.0 * p[2]
215
+ )
216
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
217
+ return # not testing against background values
218
+
219
+ expect_near(wp.volume_sample_v(volume, p, wp.Volume.LINEAR), expected, 2.0e-4)
220
+ expect_near(wp.volume_sample(volume, p, wp.Volume.LINEAR, dtype=wp.vec3), expected, 2.0e-4)
221
+
222
+
223
+ @wp.kernel
224
+ def test_volume_sample_grad_linear_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
225
+ tid = wp.tid()
226
+
227
+ p = points[tid]
228
+
229
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
230
+ return # not testing against background values
231
+
232
+ expected_val = wp.vec3(
233
+ p[0] + 2.0 * p[1] + 3.0 * p[2], 4.0 * p[0] + 5.0 * p[1] + 6.0 * p[2], 7.0 * p[0] + 8.0 * p[1] + 9.0 * p[2]
234
+ )
235
+ expected_grad = wp.mat33(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
236
+
237
+ grad = wp.mat33(0.0)
238
+ val = wp.volume_sample_grad(volume, p, wp.Volume.LINEAR, grad, dtype=wp.vec3)
239
+
240
+ expect_near(val, expected_val, 2.0e-4)
241
+ expect_near(grad[0], expected_grad[0], 2.0e-4)
242
+ expect_near(grad[1], expected_grad[1], 2.0e-4)
243
+ expect_near(grad[2], expected_grad[2], 2.0e-4)
244
+
245
+
246
+ @wp.kernel
247
+ def test_volume_sample_local_v_linear_values(
248
+ volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32)
249
+ ):
250
+ tid = wp.tid()
251
+ p = points[tid]
252
+ ones = wp.vec3(1.0, 1.0, 1.0)
253
+ values[tid] = wp.dot(wp.volume_sample_v(volume, p, wp.Volume.LINEAR), ones)
254
+
255
+
256
+ @wp.kernel
257
+ def test_volume_sample_world_v_linear_values(
258
+ volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32)
259
+ ):
260
+ tid = wp.tid()
261
+ q = points[tid]
262
+ p = wp.volume_world_to_index(volume, q)
263
+ ones = wp.vec3(1.0, 1.0, 1.0)
264
+ values[tid] = wp.dot(wp.volume_sample_v(volume, p, wp.Volume.LINEAR), ones)
265
+
266
+
267
+ # int32 volume tests
268
+ @wp.kernel
269
+ def test_volume_lookup_i(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
270
+ tid = wp.tid()
271
+
272
+ p = points[tid]
273
+ i = int(p[0])
274
+ j = int(p[1])
275
+ k = int(p[2])
276
+ expected = i * j * k
277
+ if abs(i) > 10 or abs(j) > 10 or abs(k) > 10:
278
+ expected = 10
279
+
280
+ expect_eq(wp.volume_lookup_i(volume, i, j, k), expected)
281
+ expect_eq(wp.volume_lookup(volume, i, j, k, dtype=wp.int32), expected)
282
+
283
+
284
+ @wp.kernel
285
+ def test_volume_sample_i(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
286
+ tid = wp.tid()
287
+
288
+ p = points[tid]
289
+ i = round(p[0])
290
+ j = round(p[1])
291
+ k = round(p[2])
292
+ expected = int(i * j * k)
293
+ if abs(i) > 10.0 or abs(j) > 10.0 or abs(k) > 10.0:
294
+ expected = 10
295
+
296
+ expect_eq(wp.volume_sample_i(volume, p), expected)
297
+ expect_eq(wp.volume_sample(volume, p, wp.Volume.CLOSEST, dtype=wp.int32), expected)
298
+
299
+ q = wp.volume_index_to_world(volume, p)
300
+ q_inv = wp.volume_world_to_index(volume, q)
301
+ expect_eq(p, q_inv)
302
+
303
+
304
+ # Index/world transformation tests
305
+ @wp.kernel
306
+ def test_volume_index_to_world(
307
+ volume: wp.uint64,
308
+ points: wp.array(dtype=wp.vec3),
309
+ values: wp.array(dtype=wp.float32),
310
+ grad_values: wp.array(dtype=wp.vec3),
311
+ ):
312
+ tid = wp.tid()
313
+ p = points[tid]
314
+ ones = wp.vec3(1.0, 1.0, 1.0)
315
+ values[tid] = wp.dot(wp.volume_index_to_world(volume, p), ones)
316
+ grad_values[tid] = wp.volume_index_to_world_dir(volume, ones)
317
+
318
+
319
+ @wp.kernel
320
+ def test_volume_world_to_index(
321
+ volume: wp.uint64,
322
+ points: wp.array(dtype=wp.vec3),
323
+ values: wp.array(dtype=wp.float32),
324
+ grad_values: wp.array(dtype=wp.vec3),
325
+ ):
326
+ tid = wp.tid()
327
+ p = points[tid]
328
+ ones = wp.vec3(1.0, 1.0, 1.0)
329
+ values[tid] = wp.dot(wp.volume_world_to_index(volume, p), ones)
330
+ grad_values[tid] = wp.volume_world_to_index_dir(volume, ones)
331
+
332
+
333
+ # Volume write tests
334
+ @wp.kernel
335
+ def test_volume_store_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.float32)):
336
+ tid = wp.tid()
337
+
338
+ p = points[tid]
339
+ i = int(p[0])
340
+ j = int(p[1])
341
+ k = int(p[2])
342
+
343
+ wp.volume_store(volume, i, j, k, float(i + 100 * j + 10000 * k))
344
+ values[tid] = wp.volume_lookup_f(volume, i, j, k)
345
+
346
+
347
+ @wp.kernel
348
+ def test_volume_store_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.vec3)):
349
+ tid = wp.tid()
350
+
351
+ p = points[tid]
352
+ i = int(p[0])
353
+ j = int(p[1])
354
+ k = int(p[2])
355
+
356
+ wp.volume_store(volume, i, j, k, p)
357
+ values[tid] = wp.volume_lookup_v(volume, i, j, k)
358
+
359
+
360
+ @wp.kernel
361
+ def test_volume_store_i(volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.int32)):
362
+ tid = wp.tid()
363
+
364
+ p = points[tid]
365
+ i = int(p[0])
366
+ j = int(p[1])
367
+ k = int(p[2])
368
+
369
+ wp.volume_store(volume, i, j, k, i + 100 * j + 10000 * k)
370
+ values[tid] = wp.volume_lookup_i(volume, i, j, k)
371
+
372
+
373
+ @wp.kernel
374
+ def test_volume_store_v4(volume: wp.uint64, points: wp.array(dtype=wp.vec3), values: wp.array(dtype=wp.vec4)):
375
+ tid = wp.tid()
376
+
377
+ p = points[tid]
378
+ i = int(p[0])
379
+ j = int(p[1])
380
+ k = int(p[2])
381
+
382
+ v = wp.vec4(p[0], p[1], p[2], float(i + 100 * j + 10000 * k))
383
+
384
+ wp.volume_store(volume, i, j, k, v)
385
+
386
+ values[tid] = wp.volume_lookup(volume, i, j, k, dtype=wp.vec4)
387
+
388
+
389
+ devices = get_test_devices()
390
+ rng = np.random.default_rng(101215)
391
+
392
+ # Note about the test grids:
393
+ # test_grid and test_int32_grid
394
+ # active region: [-10,10]^3
395
+ # values: v[i,j,k] = i * j * k
396
+ # voxel size: 0.25
397
+ #
398
+ # test_vec_grid
399
+ # active region: [-10,10]^3
400
+ # values: v[i,j,k] = (i + 2*j + 3*k, 4*i + 5*j + 6*k, 7*i + 8*j + 9*k)
401
+ # voxel size: 0.25
402
+ #
403
+ # torus
404
+ # index to world transformation:
405
+ # [0.1, 0, 0, 0]
406
+ # [0, 0, 0.1, 0]
407
+ # [0, 0.1, 0, 0]
408
+ # [1, 2, 3, 1]
409
+ # (-90 degrees rotation along X)
410
+ # voxel size: 0.1
411
+ volume_paths = {
412
+ "float": os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "assets", "test_grid.nvdb")),
413
+ "int32": os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "assets", "test_int32_grid.nvdb")),
414
+ "vec3f": os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "assets", "test_vec_grid.nvdb")),
415
+ "index": os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "assets", "test_index_grid.nvdb")),
416
+ "torus": os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "assets", "torus.nvdb")),
417
+ "float_write": os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "assets", "test_grid.nvdb")),
418
+ }
419
+
420
+ test_volume_tiles = (
421
+ np.array([[i, j, k] for i in range(-2, 2) for j in range(-2, 2) for k in range(-2, 2)], dtype=np.int32) * 8
422
+ )
423
+
424
+ volumes = {}
425
+ for value_type, path in volume_paths.items():
426
+ volumes[value_type] = {}
427
+ volume_data = open(path, "rb").read()
428
+ for device in devices:
429
+ try:
430
+ volume = wp.Volume.load_from_nvdb(volume_data, device)
431
+ except RuntimeError as e:
432
+ raise RuntimeError(f'Failed to load volume from "{path}" to {device} memory:\n{e}') from e
433
+
434
+ volumes[value_type][device.alias] = volume
435
+
436
+ axis = np.linspace(-1, 1, 3)
437
+ point_grid = np.array([[x, y, z] for x in axis for y in axis for z in axis], dtype=np.float32)
438
+
439
+
440
+ def test_volume_sample_linear_f_gradient(test, device):
441
+ points = rng.uniform(-10.0, 10.0, size=(100, 3))
442
+ values = wp.array(np.zeros(1), dtype=wp.float32, device=device, requires_grad=True)
443
+ for test_case in points:
444
+ uvws = wp.array(test_case, dtype=wp.vec3, device=device, requires_grad=True)
445
+ xyzs = wp.array(test_case * 0.25, dtype=wp.vec3, device=device, requires_grad=True)
446
+
447
+ tape = wp.Tape()
448
+ with tape:
449
+ wp.launch(
450
+ test_volume_sample_local_f_linear_values,
451
+ dim=1,
452
+ inputs=[volumes["float"][device.alias].id, uvws, values],
453
+ device=device,
454
+ )
455
+ tape.backward(values)
456
+
457
+ x, y, z = test_case
458
+ grad_expected = np.array([y * z, x * z, x * y])
459
+ grad_computed = tape.gradients[uvws].numpy()[0]
460
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
461
+
462
+ tape = wp.Tape()
463
+ with tape:
464
+ wp.launch(
465
+ test_volume_sample_world_f_linear_values,
466
+ dim=1,
467
+ inputs=[volumes["float"][device.alias].id, xyzs, values],
468
+ device=device,
469
+ )
470
+ tape.backward(values)
471
+
472
+ x, y, z = test_case
473
+ grad_expected = np.array([y * z, x * z, x * y]) / 0.25
474
+ grad_computed = tape.gradients[xyzs].numpy()[0]
475
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
476
+
477
+
478
+ def test_volume_sample_grad_linear_f_gradient(test, device):
479
+ points = rng.uniform(-10.0, 10.0, size=(100, 3))
480
+ values = wp.array(np.zeros(1), dtype=wp.float32, device=device, requires_grad=True)
481
+ for test_case in points:
482
+ uvws = wp.array(test_case, dtype=wp.vec3, device=device, requires_grad=True)
483
+ xyzs = wp.array(test_case * 0.25, dtype=wp.vec3, device=device, requires_grad=True)
484
+
485
+ for case_num in range(4):
486
+ tape = wp.Tape()
487
+ with tape:
488
+ wp.launch(
489
+ test_volume_sample_grad_local_f_linear_values,
490
+ dim=1,
491
+ inputs=[volumes["float"][device.alias].id, uvws, values, case_num],
492
+ device=device,
493
+ )
494
+ tape.backward(values)
495
+
496
+ x, y, z = test_case
497
+ grad_computed = tape.gradients[uvws].numpy()[0]
498
+ if case_num == 0:
499
+ grad_expected = np.array([y * z, x * z, x * y])
500
+ elif case_num == 1:
501
+ grad_expected = np.array([0.0, z, y])
502
+ elif case_num == 2:
503
+ grad_expected = np.array([z, 0.0, x])
504
+ elif case_num == 3:
505
+ grad_expected = np.array([y, x, 0.0])
506
+
507
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
508
+ tape.zero()
509
+
510
+ for case_num in range(4):
511
+ tape = wp.Tape()
512
+ with tape:
513
+ wp.launch(
514
+ test_volume_sample_grad_world_f_linear_values,
515
+ dim=1,
516
+ inputs=[volumes["float"][device.alias].id, xyzs, values, case_num],
517
+ device=device,
518
+ )
519
+ tape.backward(values)
520
+
521
+ x, y, z = test_case
522
+ grad_computed = tape.gradients[xyzs].numpy()[0]
523
+ if case_num == 0:
524
+ grad_expected = np.array([y * z, x * z, x * y]) / 0.25
525
+ elif case_num == 1:
526
+ grad_expected = np.array([0.0, z, y]) / 0.25
527
+ elif case_num == 2:
528
+ grad_expected = np.array([z, 0.0, x]) / 0.25
529
+ elif case_num == 3:
530
+ grad_expected = np.array([y, x, 0.0]) / 0.25
531
+
532
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
533
+ tape.zero()
534
+
535
+
536
+ def test_volume_sample_linear_v_gradient(test, device):
537
+ points = rng.uniform(-10.0, 10.0, size=(100, 3))
538
+ values = wp.zeros(1, dtype=wp.float32, device=device, requires_grad=True)
539
+ for test_case in points:
540
+ uvws = wp.array(test_case, dtype=wp.vec3, device=device, requires_grad=True)
541
+ xyzs = wp.array(test_case * 0.25, dtype=wp.vec3, device=device, requires_grad=True)
542
+
543
+ tape = wp.Tape()
544
+ with tape:
545
+ wp.launch(
546
+ test_volume_sample_local_v_linear_values,
547
+ dim=1,
548
+ inputs=[volumes["vec3f"][device.alias].id, uvws, values],
549
+ device=device,
550
+ )
551
+ tape.backward(values)
552
+
553
+ grad_expected = np.array([12.0, 15.0, 18.0])
554
+ grad_computed = tape.gradients[uvws].numpy()[0]
555
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
556
+
557
+ tape = wp.Tape()
558
+ with tape:
559
+ wp.launch(
560
+ test_volume_sample_world_v_linear_values,
561
+ dim=1,
562
+ inputs=[volumes["vec3f"][device.alias].id, xyzs, values],
563
+ device=device,
564
+ )
565
+ tape.backward(values)
566
+
567
+ grad_expected = np.array([12.0, 15.0, 18.0]) / 0.25
568
+ grad_computed = tape.gradients[xyzs].numpy()[0]
569
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
570
+
571
+
572
+ def test_volume_transform_gradient(test, device):
573
+ values = wp.zeros(1, dtype=wp.float32, device=device, requires_grad=True)
574
+ grad_values = wp.zeros(1, dtype=wp.vec3, device=device)
575
+ test_points = rng.uniform(-10.0, 10.0, size=(10, 3))
576
+ for test_case in test_points:
577
+ points = wp.array(test_case, dtype=wp.vec3, device=device, requires_grad=True)
578
+ tape = wp.Tape()
579
+ with tape:
580
+ wp.launch(
581
+ test_volume_index_to_world,
582
+ dim=1,
583
+ inputs=[volumes["torus"][device.alias].id, points, values, grad_values],
584
+ device=device,
585
+ )
586
+ tape.backward(values)
587
+
588
+ grad_computed = tape.gradients[points].numpy()
589
+ grad_expected = grad_values.numpy()
590
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
591
+
592
+ grad_computed = tape.gradients[points].numpy()
593
+ grad_expected = grad_values.numpy()
594
+ np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
595
+
596
+
597
+ def test_volume_store(test, device):
598
+ values_ref = np.array([x + 100 * y + 10000 * z for x, y, z in point_grid])
599
+ points = wp.array(point_grid, dtype=wp.vec3, device=device)
600
+ values = wp.empty(len(point_grid), dtype=wp.float32, device=device)
601
+ wp.launch(
602
+ test_volume_store_f,
603
+ dim=len(point_grid),
604
+ inputs=[volumes["float_write"][device.alias].id, points, values],
605
+ device=device,
606
+ )
607
+
608
+ values_res = values.numpy()
609
+ np.testing.assert_equal(values_res, values_ref)
610
+
611
+
612
+ def test_volume_allocation_f(test, device):
613
+ bg_value = -123.0
614
+ points_np = np.append(point_grid, [[8096, 8096, 8096]], axis=0)
615
+ values_ref = np.append(np.array([x + 100 * y + 10000 * z for x, y, z in point_grid]), bg_value)
616
+
617
+ volume = wp.Volume.allocate(min=[-11, -11, -11], max=[11, 11, 11], voxel_size=0.1, bg_value=bg_value, device=device)
618
+ points = wp.array(points_np, dtype=wp.vec3, device=device)
619
+ values = wp.empty(len(points_np), dtype=wp.float32, device=device)
620
+ wp.launch(test_volume_store_f, dim=len(points_np), inputs=[volume.id, points, values], device=device)
621
+
622
+ values_res = values.numpy()
623
+ np.testing.assert_equal(values_res, values_ref)
624
+
625
+
626
+ def test_volume_allocation_v(test, device):
627
+ bg_value = (-1, 2.0, -3)
628
+ points_np = np.append(point_grid, [[8096, 8096, 8096]], axis=0)
629
+ values_ref = np.append(point_grid, [bg_value], axis=0)
630
+
631
+ volume = wp.Volume.allocate(min=[-11, -11, -11], max=[11, 11, 11], voxel_size=0.1, bg_value=bg_value, device=device)
632
+ points = wp.array(points_np, dtype=wp.vec3, device=device)
633
+ values = wp.empty(len(points_np), dtype=wp.vec3, device=device)
634
+ wp.launch(test_volume_store_v, dim=len(points_np), inputs=[volume.id, points, values], device=device)
635
+
636
+ values_res = values.numpy()
637
+ np.testing.assert_equal(values_res, values_ref)
638
+
639
+
640
+ def test_volume_allocation_i(test, device):
641
+ bg_value = -123
642
+ points_np = np.append(point_grid, [[8096, 8096, 8096]], axis=0)
643
+ values_ref = np.append(np.array([x + 100 * y + 10000 * z for x, y, z in point_grid], dtype=np.int32), bg_value)
644
+
645
+ volume = wp.Volume.allocate(min=[-11, -11, -11], max=[11, 11, 11], voxel_size=0.1, bg_value=bg_value, device=device)
646
+ points = wp.array(points_np, dtype=wp.vec3, device=device)
647
+ values = wp.empty(len(points_np), dtype=wp.int32, device=device)
648
+ wp.launch(test_volume_store_i, dim=len(points_np), inputs=[volume.id, points, values], device=device)
649
+
650
+ values_res = values.numpy()
651
+ np.testing.assert_equal(values_res, values_ref)
652
+
653
+
654
+ def test_volume_allocation_v4(test, device):
655
+ bg_value = (-1, 2.0, -3, 5)
656
+ points_np = np.append(point_grid, [[8096, 8096, 8096]], axis=0)
657
+
658
+ w_ref = np.array([x + 100 * y + 10000 * z for x, y, z in point_grid])[:, np.newaxis]
659
+ values_ref = np.append(np.hstack((point_grid, w_ref)), [bg_value], axis=0)
660
+
661
+ volume = wp.Volume.allocate(min=[-11, -11, -11], max=[11, 11, 11], voxel_size=0.1, bg_value=bg_value, device=device)
662
+ points = wp.array(points_np, dtype=wp.vec3, device=device)
663
+ values = wp.empty(len(points_np), dtype=wp.vec4, device=device)
664
+ wp.launch(test_volume_store_v4, dim=len(points_np), inputs=[volume.id, points, values], device=device)
665
+
666
+ values_res = values.numpy()
667
+ np.testing.assert_equal(values_res, values_ref)
668
+
669
+
670
+ def test_volume_introspection(test, device):
671
+ for volume_names in ("float", "vec3f"):
672
+ with test.subTest(volume_names=volume_names):
673
+ volume = volumes[volume_names][device.alias]
674
+ tiles_actual = volume.get_tiles().numpy()
675
+ tiles_sorted = tiles_actual[np.lexsort(tiles_actual.T[::-1])]
676
+ voxel_size = np.array(volume.get_voxel_size())
677
+
678
+ np.testing.assert_equal(test_volume_tiles, tiles_sorted)
679
+ np.testing.assert_equal([0.25] * 3, voxel_size)
680
+
681
+ voxel_count = volume.get_voxel_count()
682
+ voxels_actual = volume.get_voxels().numpy()
683
+ assert voxel_count == voxels_actual.shape[0]
684
+
685
+ # Voxel coordinates should be unique
686
+ voxels_unique = np.unique(voxels_actual, axis=0)
687
+ assert voxel_count == voxels_unique.shape[0]
688
+
689
+ # Get back tiles from voxels, should match get_tiles()
690
+ voxel_tiles = 8 * (voxels_unique // 8)
691
+ voxel_tiles_sorted = voxel_tiles[np.lexsort(voxel_tiles.T[::-1])]
692
+ voxel_tiles_unique = np.unique(voxel_tiles_sorted, axis=0)
693
+
694
+ np.testing.assert_equal(voxel_tiles_unique, tiles_sorted)
695
+
696
+
697
+ def test_volume_multiple_grids(test, device):
698
+ volume = volumes["index"][device.alias]
699
+
700
+ volume_2 = volume.load_next_grid()
701
+
702
+ test.assertIsNotNone(volume_2)
703
+
704
+ test.assertNotEqual(volume.id, volume_2.id)
705
+ test.assertNotEqual(volume.get_voxel_count(), volume_2.get_voxel_count())
706
+
707
+ test.assertEqual(volume.get_grid_info().grid_count, volume_2.get_grid_info().grid_count)
708
+ test.assertEqual(volume.get_grid_info().grid_index + 1, volume_2.get_grid_info().grid_index)
709
+
710
+ volume_3 = volume_2.load_next_grid()
711
+ test.assertIsNone(volume_3)
712
+
713
+
714
+ def test_volume_feature_array(test, device):
715
+ volume = volumes["index"][device.alias]
716
+
717
+ test.assertEqual(volume.get_feature_array_count(), 1)
718
+
719
+ array = volume.feature_array(0, dtype=wp.uint64)
720
+ test.assertEqual(array.device, device)
721
+ test.assertEqual(array.dtype, wp.uint64)
722
+
723
+ # fVDB convention, data starts with array ndim + shape
724
+ np.testing.assert_equal(array.numpy()[0:4], [3, volume.get_voxel_count(), 2, 3])
725
+
726
+
727
+ @wp.kernel
728
+ def fill_leaf_values_kernel(volume: wp.uint64, ijk: wp.array2d(dtype=wp.int32), values: wp.array(dtype=Any)):
729
+ tid = wp.tid()
730
+
731
+ i = ijk[tid, 0]
732
+ j = ijk[tid, 1]
733
+ k = ijk[tid, 2]
734
+
735
+ expect_eq(tid, wp.volume_lookup_index(volume, i, j, k))
736
+
737
+ values[tid] = wp.volume_lookup(volume, i, j, k, dtype=values.dtype)
738
+
739
+
740
+ @wp.kernel
741
+ def test_volume_sample_index_kernel(
742
+ volume: wp.uint64,
743
+ points: wp.array(dtype=wp.vec3),
744
+ values: wp.array(dtype=Any),
745
+ background: wp.array(dtype=Any),
746
+ sampled_values: wp.array(dtype=Any),
747
+ ):
748
+ tid = wp.tid()
749
+ p = points[tid]
750
+
751
+ ref = wp.volume_sample(volume, p, wp.Volume.LINEAR, dtype=values.dtype)
752
+ sampled_values[tid] = wp.volume_sample_index(volume, p, wp.Volume.LINEAR, values, background[0])
753
+ expect_eq(sampled_values[tid], ref)
754
+
755
+
756
+ @wp.kernel
757
+ def test_volume_sample_grad_index_kernel(
758
+ volume: wp.uint64,
759
+ points: wp.array(dtype=wp.vec3),
760
+ values: wp.array(dtype=Any),
761
+ background: wp.array(dtype=Any),
762
+ sampled_values: wp.array(dtype=Any),
763
+ sampled_grads: wp.array(dtype=Any),
764
+ ):
765
+ tid = wp.tid()
766
+ p = points[tid]
767
+
768
+ ref_grad = sampled_grads.dtype()
769
+ ref = wp.volume_sample_grad(volume, p, wp.Volume.LINEAR, ref_grad, dtype=values.dtype)
770
+
771
+ grad = type(ref_grad)()
772
+ sampled_values[tid] = wp.volume_sample_grad_index(volume, p, wp.Volume.LINEAR, values, background[0], grad)
773
+ expect_eq(sampled_values[tid], ref)
774
+
775
+ expect_eq(grad[0], ref_grad[0])
776
+ expect_eq(grad[1], ref_grad[1])
777
+ expect_eq(grad[2], ref_grad[2])
778
+ sampled_grads[tid] = grad
779
+
780
+
781
+ def test_volume_sample_index(test, device):
782
+ points = rng.uniform(-10.0, 10.0, size=(100, 3))
783
+ points[0:10, 0] += 100.0 # ensure some points are over unallocated voxels
784
+ uvws = wp.array(points, dtype=wp.vec3, device=device)
785
+
786
+ bg_values = {
787
+ "float": 10.0,
788
+ "vec3f": wp.vec3(10.8, -4.13, 10.26),
789
+ }
790
+ grad_types = {
791
+ "float": wp.vec3,
792
+ "vec3f": wp.mat33,
793
+ }
794
+
795
+ for volume_names in ("float", "vec3f"):
796
+ with test.subTest(volume_names=volume_names):
797
+ volume = volumes[volume_names][device.alias]
798
+
799
+ ijk = volume.get_voxels()
800
+
801
+ values = wp.empty(shape=volume.get_voxel_count(), dtype=volume.dtype, device=device, requires_grad=True)
802
+
803
+ vid = wp.uint64(volume.id)
804
+ wp.launch(fill_leaf_values_kernel, dim=values.shape, inputs=[vid, ijk, values], device=device)
805
+
806
+ sampled_values = wp.empty(shape=points.shape[0], dtype=volume.dtype, device=device, requires_grad=True)
807
+ background = wp.array([bg_values[volume_names]], dtype=volume.dtype, device=device, requires_grad=True)
808
+
809
+ tape = wp.Tape()
810
+ with tape:
811
+ wp.launch(
812
+ test_volume_sample_index_kernel,
813
+ dim=points.shape[0],
814
+ inputs=[vid, uvws, values, background, sampled_values],
815
+ device=device,
816
+ )
817
+
818
+ sampled_values.grad.fill_(1.0)
819
+ tape.backward()
820
+
821
+ # test adjoint w.r.t voxel and background value arrays
822
+ # we should have sum(sampled_values) = sum(adj_values * values) + (adj_background * background)
823
+ sum_sampled_values = np.sum(sampled_values.numpy(), axis=0)
824
+ sum_values_adj = np.sum(values.numpy() * values.grad.numpy(), axis=0)
825
+ sum_background_adj = background.numpy()[0] * background.grad.numpy()[0]
826
+
827
+ np.testing.assert_allclose(sum_sampled_values, sum_values_adj + sum_background_adj, rtol=1.0e-3)
828
+
829
+ tape.reset()
830
+
831
+ sampled_grads = wp.empty(
832
+ shape=points.shape[0], dtype=grad_types[volume_names], device=device, requires_grad=True
833
+ )
834
+
835
+ with tape:
836
+ wp.launch(
837
+ test_volume_sample_grad_index_kernel,
838
+ dim=points.shape[0],
839
+ inputs=[vid, uvws, values, background, sampled_values, sampled_grads],
840
+ device=device,
841
+ )
842
+
843
+ sampled_values.grad.fill_(1.0)
844
+ tape.backward()
845
+
846
+ # we should have sum(sampled_values) = sum(adj_values * values) + (adj_background * background)
847
+ sum_sampled_values = np.sum(sampled_values.numpy(), axis=0)
848
+ sum_values_adj = np.sum(values.numpy() * values.grad.numpy(), axis=0)
849
+ sum_background_adj = background.numpy()[0] * background.grad.numpy()[0]
850
+ np.testing.assert_allclose(sum_sampled_values, sum_values_adj + sum_background_adj, rtol=1.0e-3)
851
+
852
+ tape.zero()
853
+ sampled_values.grad.fill_(0.0)
854
+ sampled_grads.grad.fill_(1.0)
855
+ tape.backward()
856
+
857
+ # we should have sum(sampled_grad, axes=(0, -1)) = sum(adj_values * values) + (adj_background * background)
858
+ sum_sampled_grads = np.sum(np.sum(sampled_grads.numpy(), axis=0), axis=-1)
859
+ sum_values_adj = np.sum(values.numpy() * values.grad.numpy(), axis=0)
860
+ sum_background_adj = background.numpy()[0] * background.grad.numpy()[0]
861
+ np.testing.assert_allclose(sum_sampled_grads, sum_values_adj + sum_background_adj, rtol=1.0e-3)
862
+
863
+
864
+ def test_volume_from_numpy(test, device):
865
+ # Volume.allocate_from_tiles() is only available with CUDA
866
+ mins = np.array([-3.0, -3.0, -3.0])
867
+ voxel_size = 0.2
868
+ maxs = np.array([3.0, 3.0, 3.0])
869
+ nums = np.ceil((maxs - mins) / (voxel_size)).astype(dtype=int)
870
+ center = np.array([0.0, 0.0, 0.0])
871
+ rad = 2.5
872
+ sphere_sdf_np = np.zeros(tuple(nums))
873
+ for x in range(nums[0]):
874
+ for y in range(nums[1]):
875
+ for z in range(nums[2]):
876
+ pos = mins + voxel_size * np.array([x, y, z])
877
+ dis = np.linalg.norm(pos - center)
878
+ sphere_sdf_np[x, y, z] = dis - rad
879
+ sphere_vdb = wp.Volume.load_from_numpy(sphere_sdf_np, mins, voxel_size, rad + 3.0 * voxel_size, device=device)
880
+
881
+ test.assertNotEqual(sphere_vdb.id, 0)
882
+
883
+ sphere_vdb_array = sphere_vdb.array()
884
+ test.assertEqual(sphere_vdb_array.dtype, wp.uint8)
885
+ test.assertIsNone(sphere_vdb_array.deleter)
886
+
887
+
888
+ def test_volume_from_numpy_3d(test, device):
889
+ # Volume.allocate_from_tiles() is only available with CUDA
890
+ mins = np.array([-3.0, -3.0, -3.0])
891
+ voxel_size = 0.2
892
+ maxs = np.array([3.0, 3.0, 3.0])
893
+ nums = np.ceil((maxs - mins) / (voxel_size)).astype(dtype=int)
894
+ centers = np.array([[-1.0, -1.0, -1.0], [0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
895
+ rad = 2.5
896
+ sphere_sdf_np = np.zeros(tuple(nums) + (3,))
897
+ for x in range(nums[0]):
898
+ for y in range(nums[1]):
899
+ for z in range(nums[2]):
900
+ for k in range(3):
901
+ pos = mins + voxel_size * np.array([x, y, z])
902
+ dis = np.linalg.norm(pos - centers[k])
903
+ sphere_sdf_np[x, y, z, k] = dis - rad
904
+ sphere_vdb = wp.Volume.load_from_numpy(
905
+ sphere_sdf_np, mins, voxel_size, (rad + 3.0 * voxel_size,) * 3, device=device
906
+ )
907
+
908
+ test.assertNotEqual(sphere_vdb.id, 0)
909
+
910
+ sphere_vdb_array = sphere_vdb.array()
911
+ test.assertEqual(sphere_vdb_array.dtype, wp.uint8)
912
+ test.assertIsNone(sphere_vdb_array.deleter)
913
+
914
+
915
+ def test_volume_aniso_transform(test, device):
916
+ # XY-rotation + z scale
917
+ transform = [
918
+ [0, -1, 0],
919
+ [1, 0, 0],
920
+ [0, 0, 2],
921
+ ]
922
+
923
+ points = wp.array([[-1, 1, 4]], dtype=float, device=device)
924
+ volume = wp.Volume.allocate_by_voxels(voxel_points=points, transform=transform, device=device)
925
+
926
+ # Check that world points are correctly converted to local space
927
+ voxels = volume.get_voxels().numpy()
928
+ assert_np_equal(voxels, [[1, 1, 2]])
929
+
930
+ # Check that we retrieve the correct transform from the grid metadata
931
+ assert_np_equal(volume.get_voxel_size(), [-1, 1, 2])
932
+ assert_np_equal(transform, np.array(volume.get_grid_info().transform_matrix).reshape(3, 3))
933
+
934
+
935
+ def test_volume_write(test, device):
936
+ codecs = ["none", "zip", "blosc"]
937
+ try:
938
+ import blosc # noqa: F401 I001
939
+ except ImportError:
940
+ codecs.pop()
941
+
942
+ for volume_name in ("float", "vec3f", "index"):
943
+ for codec in codecs:
944
+ with test.subTest(volume_name=volume_name, codec=codec):
945
+ volume = volumes[volume_name][device.alias]
946
+ fd, file_path = tempfile.mkstemp(suffix=".nvdb")
947
+ os.close(fd)
948
+ try:
949
+ volume.save_to_nvdb(file_path, codec=codec)
950
+ with open(file_path, "rb") as f:
951
+ volume_2 = wp.Volume.load_from_nvdb(f)
952
+ next_volume = volume
953
+ while next_volume:
954
+ np.testing.assert_array_equal(next_volume.array().numpy(), volume_2.array().numpy())
955
+ next_volume = next_volume.load_next_grid()
956
+ volume_2 = volume_2.load_next_grid()
957
+
958
+ finally:
959
+ os.remove(file_path)
960
+
961
+ with test.subTest(volume_write="unsupported"):
962
+ volume = volumes["index"][device.alias]
963
+ volume = volume.load_next_grid()
964
+
965
+ fd, file_path = tempfile.mkstemp(suffix=".nvdb")
966
+ os.close(fd)
967
+
968
+ try:
969
+ with test.assertRaises(RuntimeError):
970
+ volume.save_to_nvdb(file_path, codec=codec)
971
+ finally:
972
+ os.remove(file_path)
973
+
974
+
975
+ class TestVolume(unittest.TestCase):
976
+ def test_volume_new_del(self):
977
+ # test the scenario in which a volume is created but not initialized before gc
978
+ instance = wp.Volume.__new__(wp.Volume)
979
+ instance.__del__()
980
+
981
+
982
+ add_function_test(
983
+ TestVolume, "test_volume_sample_linear_f_gradient", test_volume_sample_linear_f_gradient, devices=devices
984
+ )
985
+ add_function_test(
986
+ TestVolume, "test_volume_sample_grad_linear_f_gradient", test_volume_sample_grad_linear_f_gradient, devices=devices
987
+ )
988
+ add_function_test(
989
+ TestVolume, "test_volume_sample_linear_v_gradient", test_volume_sample_linear_v_gradient, devices=devices
990
+ )
991
+ add_function_test(TestVolume, "test_volume_transform_gradient", test_volume_transform_gradient, devices=devices)
992
+ add_function_test(TestVolume, "test_volume_store", test_volume_store, devices=devices)
993
+ add_function_test(
994
+ TestVolume, "test_volume_allocation_f", test_volume_allocation_f, devices=get_selected_cuda_test_devices()
995
+ )
996
+ add_function_test(
997
+ TestVolume, "test_volume_allocation_v", test_volume_allocation_v, devices=get_selected_cuda_test_devices()
998
+ )
999
+ add_function_test(
1000
+ TestVolume, "test_volume_allocation_i", test_volume_allocation_i, devices=get_selected_cuda_test_devices()
1001
+ )
1002
+ add_function_test(
1003
+ TestVolume, "test_volume_allocation_v4", test_volume_allocation_v4, devices=get_selected_cuda_test_devices()
1004
+ )
1005
+ add_function_test(TestVolume, "test_volume_introspection", test_volume_introspection, devices=devices)
1006
+ add_function_test(
1007
+ TestVolume, "test_volume_from_numpy", test_volume_from_numpy, devices=get_selected_cuda_test_devices()
1008
+ )
1009
+ add_function_test(
1010
+ TestVolume, "test_volume_from_numpy_3d", test_volume_from_numpy_3d, devices=get_selected_cuda_test_devices()
1011
+ )
1012
+ add_function_test(
1013
+ TestVolume, "test_volume_aniso_transform", test_volume_aniso_transform, devices=get_selected_cuda_test_devices()
1014
+ )
1015
+ add_function_test(TestVolume, "test_volume_multiple_grids", test_volume_multiple_grids, devices=devices)
1016
+ add_function_test(TestVolume, "test_volume_feature_array", test_volume_feature_array, devices=devices)
1017
+ add_function_test(TestVolume, "test_volume_sample_index", test_volume_sample_index, devices=devices)
1018
+ add_function_test(TestVolume, "test_volume_write", test_volume_write, devices=[wp.get_device("cpu")])
1019
+
1020
+ points = {}
1021
+ points_jittered = {}
1022
+ for device in devices:
1023
+ points_jittered_np = point_grid + rng.uniform(-0.5, 0.5, size=point_grid.shape)
1024
+ points[device.alias] = wp.array(point_grid, dtype=wp.vec3, device=device)
1025
+ points_jittered[device.alias] = wp.array(points_jittered_np, dtype=wp.vec3, device=device)
1026
+
1027
+ add_kernel_test(
1028
+ TestVolume,
1029
+ test_volume_lookup_f,
1030
+ dim=len(point_grid),
1031
+ inputs=[volumes["float"][device.alias].id, points[device.alias]],
1032
+ devices=[device],
1033
+ )
1034
+ add_kernel_test(
1035
+ TestVolume,
1036
+ test_volume_sample_closest_f,
1037
+ dim=len(point_grid),
1038
+ inputs=[volumes["float"][device.alias].id, points_jittered[device.alias]],
1039
+ devices=[device.alias],
1040
+ )
1041
+ add_kernel_test(
1042
+ TestVolume,
1043
+ test_volume_sample_linear_f,
1044
+ dim=len(point_grid),
1045
+ inputs=[volumes["float"][device.alias].id, points_jittered[device.alias]],
1046
+ devices=[device.alias],
1047
+ )
1048
+ add_kernel_test(
1049
+ TestVolume,
1050
+ test_volume_sample_grad_linear_f,
1051
+ dim=len(point_grid),
1052
+ inputs=[volumes["float"][device.alias].id, points_jittered[device.alias]],
1053
+ devices=[device.alias],
1054
+ )
1055
+
1056
+ add_kernel_test(
1057
+ TestVolume,
1058
+ test_volume_lookup_v,
1059
+ dim=len(point_grid),
1060
+ inputs=[volumes["vec3f"][device.alias].id, points[device.alias]],
1061
+ devices=[device.alias],
1062
+ )
1063
+ add_kernel_test(
1064
+ TestVolume,
1065
+ test_volume_sample_closest_v,
1066
+ dim=len(point_grid),
1067
+ inputs=[volumes["vec3f"][device.alias].id, points_jittered[device.alias]],
1068
+ devices=[device.alias],
1069
+ )
1070
+ add_kernel_test(
1071
+ TestVolume,
1072
+ test_volume_sample_linear_v,
1073
+ dim=len(point_grid),
1074
+ inputs=[volumes["vec3f"][device.alias].id, points_jittered[device.alias]],
1075
+ devices=[device.alias],
1076
+ )
1077
+ add_kernel_test(
1078
+ TestVolume,
1079
+ test_volume_sample_grad_linear_v,
1080
+ dim=len(point_grid),
1081
+ inputs=[volumes["vec3f"][device.alias].id, points_jittered[device.alias]],
1082
+ devices=[device.alias],
1083
+ )
1084
+
1085
+ add_kernel_test(
1086
+ TestVolume,
1087
+ test_volume_lookup_i,
1088
+ dim=len(point_grid),
1089
+ inputs=[volumes["int32"][device.alias].id, points[device.alias]],
1090
+ devices=[device.alias],
1091
+ )
1092
+ add_kernel_test(
1093
+ TestVolume,
1094
+ test_volume_sample_i,
1095
+ dim=len(point_grid),
1096
+ inputs=[volumes["int32"][device.alias].id, points_jittered[device.alias]],
1097
+ devices=[device.alias],
1098
+ )
1099
+
1100
+
1101
+ if __name__ == "__main__":
1102
+ wp.clear_kernel_cache()
1103
+ unittest.main(verbosity=2)