warp-lang 1.1.0__py3-none-manylinux2014_x86_64.whl → 1.2.0__py3-none-manylinux2014_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 (218) hide show
  1. warp/bin/warp-clang.so +0 -0
  2. warp/bin/warp.so +0 -0
  3. warp/build.py +10 -37
  4. warp/build_dll.py +2 -2
  5. warp/builtins.py +274 -6
  6. warp/codegen.py +51 -4
  7. warp/config.py +2 -2
  8. warp/constants.py +4 -0
  9. warp/context.py +418 -203
  10. warp/examples/benchmarks/benchmark_api.py +0 -2
  11. warp/examples/benchmarks/benchmark_cloth_warp.py +0 -1
  12. warp/examples/benchmarks/benchmark_launches.py +0 -2
  13. warp/examples/core/example_dem.py +0 -2
  14. warp/examples/core/example_fluid.py +0 -2
  15. warp/examples/core/example_graph_capture.py +0 -2
  16. warp/examples/core/example_marching_cubes.py +0 -2
  17. warp/examples/core/example_mesh.py +0 -2
  18. warp/examples/core/example_mesh_intersect.py +0 -2
  19. warp/examples/core/example_nvdb.py +0 -2
  20. warp/examples/core/example_raycast.py +0 -2
  21. warp/examples/core/example_raymarch.py +0 -2
  22. warp/examples/core/example_render_opengl.py +0 -2
  23. warp/examples/core/example_sph.py +0 -2
  24. warp/examples/core/example_torch.py +0 -3
  25. warp/examples/core/example_wave.py +0 -2
  26. warp/examples/fem/example_apic_fluid.py +140 -115
  27. warp/examples/fem/example_burgers.py +262 -0
  28. warp/examples/fem/example_convection_diffusion.py +0 -2
  29. warp/examples/fem/example_convection_diffusion_dg.py +0 -2
  30. warp/examples/fem/example_deformed_geometry.py +0 -2
  31. warp/examples/fem/example_diffusion.py +0 -2
  32. warp/examples/fem/example_diffusion_3d.py +5 -4
  33. warp/examples/fem/example_diffusion_mgpu.py +0 -2
  34. warp/examples/fem/example_mixed_elasticity.py +0 -2
  35. warp/examples/fem/example_navier_stokes.py +0 -2
  36. warp/examples/fem/example_stokes.py +0 -2
  37. warp/examples/fem/example_stokes_transfer.py +0 -2
  38. warp/examples/optim/example_bounce.py +0 -2
  39. warp/examples/optim/example_cloth_throw.py +0 -2
  40. warp/examples/optim/example_diffray.py +0 -2
  41. warp/examples/optim/example_drone.py +0 -2
  42. warp/examples/optim/example_inverse_kinematics.py +0 -2
  43. warp/examples/optim/example_inverse_kinematics_torch.py +0 -2
  44. warp/examples/optim/example_spring_cage.py +0 -2
  45. warp/examples/optim/example_trajectory.py +0 -2
  46. warp/examples/optim/example_walker.py +0 -2
  47. warp/examples/sim/example_cartpole.py +0 -2
  48. warp/examples/sim/example_cloth.py +0 -2
  49. warp/examples/sim/example_granular.py +0 -2
  50. warp/examples/sim/example_granular_collision_sdf.py +0 -2
  51. warp/examples/sim/example_jacobian_ik.py +0 -2
  52. warp/examples/sim/example_particle_chain.py +0 -2
  53. warp/examples/sim/example_quadruped.py +0 -2
  54. warp/examples/sim/example_rigid_chain.py +0 -2
  55. warp/examples/sim/example_rigid_contact.py +0 -2
  56. warp/examples/sim/example_rigid_force.py +0 -2
  57. warp/examples/sim/example_rigid_gyroscopic.py +0 -2
  58. warp/examples/sim/example_rigid_soft_contact.py +0 -2
  59. warp/examples/sim/example_soft_body.py +0 -2
  60. warp/fem/__init__.py +1 -0
  61. warp/fem/cache.py +3 -1
  62. warp/fem/geometry/__init__.py +1 -0
  63. warp/fem/geometry/element.py +4 -0
  64. warp/fem/geometry/grid_3d.py +0 -4
  65. warp/fem/geometry/nanogrid.py +455 -0
  66. warp/fem/integrate.py +63 -9
  67. warp/fem/space/__init__.py +43 -158
  68. warp/fem/space/basis_space.py +34 -0
  69. warp/fem/space/collocated_function_space.py +1 -1
  70. warp/fem/space/grid_2d_function_space.py +13 -132
  71. warp/fem/space/grid_3d_function_space.py +16 -154
  72. warp/fem/space/hexmesh_function_space.py +37 -134
  73. warp/fem/space/nanogrid_function_space.py +202 -0
  74. warp/fem/space/quadmesh_2d_function_space.py +12 -119
  75. warp/fem/space/restriction.py +4 -1
  76. warp/fem/space/shape/__init__.py +77 -0
  77. warp/fem/space/shape/cube_shape_function.py +5 -15
  78. warp/fem/space/tetmesh_function_space.py +6 -76
  79. warp/fem/space/trimesh_2d_function_space.py +6 -76
  80. warp/native/array.h +12 -3
  81. warp/native/builtin.h +48 -5
  82. warp/native/bvh.cpp +14 -10
  83. warp/native/bvh.cu +23 -15
  84. warp/native/bvh.h +1 -0
  85. warp/native/clang/clang.cpp +2 -1
  86. warp/native/crt.cpp +11 -1
  87. warp/native/crt.h +18 -1
  88. warp/native/exports.h +187 -0
  89. warp/native/mat.h +47 -0
  90. warp/native/mesh.cpp +1 -1
  91. warp/native/mesh.cu +1 -2
  92. warp/native/nanovdb/GridHandle.h +366 -0
  93. warp/native/nanovdb/HostBuffer.h +590 -0
  94. warp/native/nanovdb/NanoVDB.h +3999 -2157
  95. warp/native/nanovdb/PNanoVDB.h +936 -99
  96. warp/native/quat.h +28 -1
  97. warp/native/rand.h +5 -1
  98. warp/native/vec.h +45 -1
  99. warp/native/volume.cpp +335 -103
  100. warp/native/volume.cu +39 -13
  101. warp/native/volume.h +725 -303
  102. warp/native/volume_builder.cu +381 -360
  103. warp/native/volume_builder.h +16 -1
  104. warp/native/volume_impl.h +61 -0
  105. warp/native/warp.cu +8 -2
  106. warp/native/warp.h +15 -7
  107. warp/render/render_opengl.py +191 -52
  108. warp/sim/integrator_featherstone.py +10 -3
  109. warp/sim/integrator_xpbd.py +16 -22
  110. warp/sparse.py +89 -27
  111. warp/stubs.py +83 -0
  112. warp/tests/assets/test_index_grid.nvdb +0 -0
  113. warp/tests/aux_test_dependent.py +0 -2
  114. warp/tests/aux_test_grad_customs.py +0 -2
  115. warp/tests/aux_test_reference.py +0 -2
  116. warp/tests/aux_test_reference_reference.py +0 -2
  117. warp/tests/aux_test_square.py +0 -2
  118. warp/tests/disabled_kinematics.py +0 -2
  119. warp/tests/test_adam.py +0 -2
  120. warp/tests/test_arithmetic.py +0 -36
  121. warp/tests/test_array.py +9 -11
  122. warp/tests/test_array_reduce.py +0 -2
  123. warp/tests/test_async.py +0 -2
  124. warp/tests/test_atomic.py +0 -2
  125. warp/tests/test_bool.py +58 -50
  126. warp/tests/test_builtins_resolution.py +0 -2
  127. warp/tests/test_bvh.py +0 -2
  128. warp/tests/test_closest_point_edge_edge.py +0 -1
  129. warp/tests/test_codegen.py +0 -4
  130. warp/tests/test_compile_consts.py +130 -10
  131. warp/tests/test_conditional.py +0 -2
  132. warp/tests/test_copy.py +0 -2
  133. warp/tests/test_ctypes.py +6 -8
  134. warp/tests/test_dense.py +0 -2
  135. warp/tests/test_devices.py +0 -2
  136. warp/tests/test_dlpack.py +9 -11
  137. warp/tests/test_examples.py +42 -39
  138. warp/tests/test_fabricarray.py +0 -3
  139. warp/tests/test_fast_math.py +0 -2
  140. warp/tests/test_fem.py +75 -54
  141. warp/tests/test_fp16.py +0 -2
  142. warp/tests/test_func.py +0 -2
  143. warp/tests/test_generics.py +27 -2
  144. warp/tests/test_grad.py +147 -8
  145. warp/tests/test_grad_customs.py +0 -2
  146. warp/tests/test_hash_grid.py +1 -3
  147. warp/tests/test_import.py +0 -2
  148. warp/tests/test_indexedarray.py +0 -2
  149. warp/tests/test_intersect.py +0 -2
  150. warp/tests/test_jax.py +0 -2
  151. warp/tests/test_large.py +11 -9
  152. warp/tests/test_launch.py +0 -2
  153. warp/tests/test_lerp.py +10 -54
  154. warp/tests/test_linear_solvers.py +3 -5
  155. warp/tests/test_lvalue.py +0 -2
  156. warp/tests/test_marching_cubes.py +0 -2
  157. warp/tests/test_mat.py +0 -2
  158. warp/tests/test_mat_lite.py +0 -2
  159. warp/tests/test_mat_scalar_ops.py +0 -2
  160. warp/tests/test_math.py +0 -2
  161. warp/tests/test_matmul.py +35 -37
  162. warp/tests/test_matmul_lite.py +29 -31
  163. warp/tests/test_mempool.py +0 -2
  164. warp/tests/test_mesh.py +0 -3
  165. warp/tests/test_mesh_query_aabb.py +0 -2
  166. warp/tests/test_mesh_query_point.py +0 -2
  167. warp/tests/test_mesh_query_ray.py +0 -2
  168. warp/tests/test_mlp.py +0 -2
  169. warp/tests/test_model.py +0 -2
  170. warp/tests/test_module_hashing.py +111 -0
  171. warp/tests/test_modules_lite.py +0 -3
  172. warp/tests/test_multigpu.py +0 -2
  173. warp/tests/test_noise.py +0 -4
  174. warp/tests/test_operators.py +0 -2
  175. warp/tests/test_options.py +0 -2
  176. warp/tests/test_peer.py +0 -2
  177. warp/tests/test_pinned.py +0 -2
  178. warp/tests/test_print.py +0 -2
  179. warp/tests/test_quat.py +0 -2
  180. warp/tests/test_rand.py +41 -5
  181. warp/tests/test_reload.py +0 -10
  182. warp/tests/test_rounding.py +0 -2
  183. warp/tests/test_runlength_encode.py +0 -2
  184. warp/tests/test_sim_grad.py +0 -2
  185. warp/tests/test_sim_kinematics.py +0 -2
  186. warp/tests/test_smoothstep.py +0 -2
  187. warp/tests/test_snippet.py +0 -2
  188. warp/tests/test_sparse.py +0 -2
  189. warp/tests/test_spatial.py +0 -2
  190. warp/tests/test_special_values.py +362 -0
  191. warp/tests/test_streams.py +0 -2
  192. warp/tests/test_struct.py +0 -2
  193. warp/tests/test_tape.py +0 -2
  194. warp/tests/test_torch.py +0 -2
  195. warp/tests/test_transient_module.py +0 -2
  196. warp/tests/test_types.py +0 -2
  197. warp/tests/test_utils.py +0 -2
  198. warp/tests/test_vec.py +0 -2
  199. warp/tests/test_vec_lite.py +0 -2
  200. warp/tests/test_vec_scalar_ops.py +0 -2
  201. warp/tests/test_verify_fp.py +0 -2
  202. warp/tests/test_volume.py +237 -13
  203. warp/tests/test_volume_write.py +86 -3
  204. warp/tests/unittest_serial.py +10 -9
  205. warp/tests/unittest_suites.py +6 -2
  206. warp/tests/unittest_utils.py +2 -171
  207. warp/tests/unused_test_misc.py +0 -2
  208. warp/tests/walkthrough_debug.py +1 -1
  209. warp/thirdparty/unittest_parallel.py +37 -40
  210. warp/types.py +514 -77
  211. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/METADATA +57 -30
  212. warp_lang-1.2.0.dist-info/RECORD +359 -0
  213. warp/examples/fem/example_convection_diffusion_dg0.py +0 -204
  214. warp/native/nanovdb/PNanoVDBWrite.h +0 -295
  215. warp_lang-1.1.0.dist-info/RECORD +0 -352
  216. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/LICENSE.md +0 -0
  217. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/WHEEL +0 -0
  218. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/top_level.txt +0 -0
warp/tests/test_volume.py CHANGED
@@ -6,14 +6,13 @@
6
6
  # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
7
 
8
8
  import unittest
9
+ from typing import Any
9
10
 
10
11
  import numpy as np
11
12
 
12
13
  import warp as wp
13
14
  from warp.tests.unittest_utils import *
14
15
 
15
- wp.init()
16
-
17
16
 
18
17
  # float volume tests
19
18
  @wp.kernel
@@ -30,6 +29,7 @@ def test_volume_lookup_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
30
29
  k = int(p[2])
31
30
 
32
31
  expect_eq(wp.volume_lookup_f(volume, i, j, k), expected)
32
+ expect_eq(wp.volume_lookup(volume, i, j, k, dtype=wp.float32), expected)
33
33
 
34
34
 
35
35
  @wp.kernel
@@ -45,6 +45,7 @@ def test_volume_sample_closest_f(volume: wp.uint64, points: wp.array(dtype=wp.ve
45
45
  expected = 10.0
46
46
 
47
47
  expect_eq(wp.volume_sample_f(volume, p, wp.Volume.CLOSEST), expected)
48
+ expect_eq(wp.volume_sample(volume, p, wp.Volume.CLOSEST, dtype=wp.float32), expected)
48
49
 
49
50
  q = wp.volume_index_to_world(volume, p)
50
51
  q_inv = wp.volume_world_to_index(volume, q)
@@ -62,6 +63,7 @@ def test_volume_sample_linear_f(volume: wp.uint64, points: wp.array(dtype=wp.vec
62
63
  return # not testing against background values
63
64
 
64
65
  expect_near(wp.volume_sample_f(volume, p, wp.Volume.LINEAR), expected, 2.0e-4)
66
+ expect_near(wp.volume_sample(volume, p, wp.Volume.LINEAR, dtype=wp.float32), expected, 2.0e-4)
65
67
 
66
68
 
67
69
  @wp.kernel
@@ -86,6 +88,13 @@ def test_volume_sample_grad_linear_f(volume: wp.uint64, points: wp.array(dtype=w
86
88
  expect_near(grad[1], expected_gy, 2.0e-4)
87
89
  expect_near(grad[2], expected_gz, 2.0e-4)
88
90
 
91
+ val = wp.volume_sample_grad(volume, p, wp.Volume.LINEAR, grad, dtype=wp.float32)
92
+
93
+ expect_near(val, expected_val, 2.0e-4)
94
+ expect_near(grad[0], expected_gx, 2.0e-4)
95
+ expect_near(grad[1], expected_gy, 2.0e-4)
96
+ expect_near(grad[2], expected_gz, 2.0e-4)
97
+
89
98
 
90
99
  @wp.kernel
91
100
  def test_volume_sample_local_f_linear_values(
@@ -162,6 +171,7 @@ def test_volume_lookup_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
162
171
  k = int(p[2])
163
172
 
164
173
  expect_eq(wp.volume_lookup_v(volume, i, j, k), expected)
174
+ expect_eq(wp.volume_lookup(volume, i, j, k, dtype=wp.vec3), expected)
165
175
 
166
176
 
167
177
  @wp.kernel
@@ -177,6 +187,7 @@ def test_volume_sample_closest_v(volume: wp.uint64, points: wp.array(dtype=wp.ve
177
187
  expected = wp.vec3(10.8, -4.13, 10.26)
178
188
 
179
189
  expect_eq(wp.volume_sample_v(volume, p, wp.Volume.CLOSEST), expected)
190
+ expect_eq(wp.volume_sample(volume, p, wp.Volume.CLOSEST, dtype=wp.vec3), expected)
180
191
 
181
192
  q = wp.volume_index_to_world(volume, p)
182
193
  q_inv = wp.volume_world_to_index(volume, q)
@@ -196,6 +207,30 @@ def test_volume_sample_linear_v(volume: wp.uint64, points: wp.array(dtype=wp.vec
196
207
  return # not testing against background values
197
208
 
198
209
  expect_near(wp.volume_sample_v(volume, p, wp.Volume.LINEAR), expected, 2.0e-4)
210
+ expect_near(wp.volume_sample(volume, p, wp.Volume.LINEAR, dtype=wp.vec3), expected, 2.0e-4)
211
+
212
+
213
+ @wp.kernel
214
+ def test_volume_sample_grad_linear_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
215
+ tid = wp.tid()
216
+
217
+ p = points[tid]
218
+
219
+ if abs(p[0]) > 10.0 or abs(p[1]) > 10.0 or abs(p[2]) > 10.0:
220
+ return # not testing against background values
221
+
222
+ expected_val = wp.vec3(
223
+ 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]
224
+ )
225
+ expected_grad = wp.mat33(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
226
+
227
+ grad = wp.mat33(0.0)
228
+ val = wp.volume_sample_grad(volume, p, wp.Volume.LINEAR, grad, dtype=wp.vec3)
229
+
230
+ expect_near(val, expected_val, 2.0e-4)
231
+ expect_near(grad[0], expected_grad[0], 2.0e-4)
232
+ expect_near(grad[1], expected_grad[1], 2.0e-4)
233
+ expect_near(grad[2], expected_grad[2], 2.0e-4)
199
234
 
200
235
 
201
236
  @wp.kernel
@@ -233,6 +268,7 @@ def test_volume_lookup_i(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
233
268
  expected = 10
234
269
 
235
270
  expect_eq(wp.volume_lookup_i(volume, i, j, k), expected)
271
+ expect_eq(wp.volume_lookup(volume, i, j, k, dtype=wp.int32), expected)
236
272
 
237
273
 
238
274
  @wp.kernel
@@ -248,6 +284,7 @@ def test_volume_sample_i(volume: wp.uint64, points: wp.array(dtype=wp.vec3)):
248
284
  expected = 10
249
285
 
250
286
  expect_eq(wp.volume_sample_i(volume, p), expected)
287
+ expect_eq(wp.volume_sample(volume, p, wp.Volume.CLOSEST, dtype=wp.int32), expected)
251
288
 
252
289
  q = wp.volume_index_to_world(volume, p)
253
290
  q_inv = wp.volume_world_to_index(volume, q)
@@ -293,9 +330,7 @@ def test_volume_store_f(volume: wp.uint64, points: wp.array(dtype=wp.vec3), valu
293
330
  j = int(p[1])
294
331
  k = int(p[2])
295
332
 
296
- # NB: Writing outside the allocated domain overwrites the background value of the Volume
297
- if abs(i) <= 11 and abs(j) <= 11 and abs(k) <= 11:
298
- wp.volume_store_f(volume, i, j, k, float(i + 100 * j + 10000 * k))
333
+ wp.volume_store(volume, i, j, k, float(i + 100 * j + 10000 * k))
299
334
  values[tid] = wp.volume_lookup_f(volume, i, j, k)
300
335
 
301
336
 
@@ -308,9 +343,7 @@ def test_volume_store_v(volume: wp.uint64, points: wp.array(dtype=wp.vec3), valu
308
343
  j = int(p[1])
309
344
  k = int(p[2])
310
345
 
311
- # NB: Writing outside the allocated domain overwrites the background value of the Volume
312
- if abs(i) <= 11 and abs(j) <= 11 and abs(k) <= 11:
313
- wp.volume_store_v(volume, i, j, k, p)
346
+ wp.volume_store(volume, i, j, k, p)
314
347
  values[tid] = wp.volume_lookup_v(volume, i, j, k)
315
348
 
316
349
 
@@ -323,9 +356,7 @@ def test_volume_store_i(volume: wp.uint64, points: wp.array(dtype=wp.vec3), valu
323
356
  j = int(p[1])
324
357
  k = int(p[2])
325
358
 
326
- # NB: Writing outside the allocated domain overwrites the background value of the Volume
327
- if abs(i) <= 11 and abs(j) <= 11 and abs(k) <= 11:
328
- wp.volume_store_i(volume, i, j, k, i + 100 * j + 10000 * k)
359
+ wp.volume_store(volume, i, j, k, i + 100 * j + 10000 * k)
329
360
  values[tid] = wp.volume_lookup_i(volume, i, j, k)
330
361
 
331
362
 
@@ -355,6 +386,7 @@ volume_paths = {
355
386
  "float": os.path.abspath(os.path.join(os.path.dirname(__file__), "assets/test_grid.nvdb")),
356
387
  "int32": os.path.abspath(os.path.join(os.path.dirname(__file__), "assets/test_int32_grid.nvdb")),
357
388
  "vec3f": os.path.abspath(os.path.join(os.path.dirname(__file__), "assets/test_vec_grid.nvdb")),
389
+ "index": os.path.abspath(os.path.join(os.path.dirname(__file__), "assets/test_index_grid.nvdb")),
358
390
  "torus": os.path.abspath(os.path.join(os.path.dirname(__file__), "assets/torus.nvdb")),
359
391
  "float_write": os.path.abspath(os.path.join(os.path.dirname(__file__), "assets/test_grid.nvdb")),
360
392
  }
@@ -492,7 +524,7 @@ def test_volume_sample_linear_v_gradient(test, device):
492
524
  )
493
525
  tape.backward(values)
494
526
 
495
- grad_expected = np.array([6.0, 15.0, 24.0])
527
+ grad_expected = np.array([12.0, 15.0, 18.0])
496
528
  grad_computed = tape.gradients[uvws].numpy()[0]
497
529
  np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
498
530
 
@@ -506,7 +538,7 @@ def test_volume_sample_linear_v_gradient(test, device):
506
538
  )
507
539
  tape.backward(values)
508
540
 
509
- grad_expected = np.array([6.0, 15.0, 24.0]) / 0.25
541
+ grad_expected = np.array([12.0, 15.0, 18.0]) / 0.25
510
542
  grad_computed = tape.gradients[xyzs].numpy()[0]
511
543
  np.testing.assert_allclose(grad_computed, grad_expected, rtol=1e-4)
512
544
 
@@ -604,6 +636,188 @@ def test_volume_introspection(test, device):
604
636
  np.testing.assert_equal(test_volume_tiles, tiles_sorted)
605
637
  np.testing.assert_equal([0.25] * 3, voxel_size)
606
638
 
639
+ voxel_count = volume.get_voxel_count()
640
+ voxels_actual = volume.get_voxels().numpy()
641
+ assert voxel_count == voxels_actual.shape[0]
642
+
643
+ # Voxel coordinates should be unique
644
+ voxels_unique = np.unique(voxels_actual, axis=0)
645
+ assert voxel_count == voxels_unique.shape[0]
646
+
647
+ # Get back tiles from voxels, should match get_tiles()
648
+ voxel_tiles = 8 * (voxels_unique // 8)
649
+ voxel_tiles_sorted = voxel_tiles[np.lexsort(voxel_tiles.T[::-1])]
650
+ voxel_tiles_unique = np.unique(voxel_tiles_sorted, axis=0)
651
+
652
+ np.testing.assert_equal(voxel_tiles_unique, tiles_sorted)
653
+
654
+
655
+ def test_volume_multiple_grids(test, device):
656
+ volume = volumes["index"][device.alias]
657
+
658
+ volume_2 = volume.load_next_grid()
659
+
660
+ test.assertIsNotNone(volume_2)
661
+
662
+ test.assertNotEqual(volume.id, volume_2.id)
663
+ test.assertNotEqual(volume.get_voxel_count(), volume_2.get_voxel_count())
664
+
665
+ test.assertEqual(volume.get_grid_info().grid_count, volume_2.get_grid_info().grid_count)
666
+ test.assertEqual(volume.get_grid_info().grid_index + 1, volume_2.get_grid_info().grid_index)
667
+
668
+ volume_3 = volume_2.load_next_grid()
669
+ test.assertIsNone(volume_3)
670
+
671
+
672
+ def test_volume_feature_array(test, device):
673
+ volume = volumes["index"][device.alias]
674
+
675
+ test.assertEqual(volume.get_feature_array_count(), 1)
676
+
677
+ array = volume.feature_array(0, dtype=wp.uint64)
678
+ test.assertEqual(array.device, device)
679
+ test.assertEqual(array.dtype, wp.uint64)
680
+
681
+ # fVDB convention, data starts with array ndim + shape
682
+ np.testing.assert_equal(array.numpy()[0:4], [3, volume.get_voxel_count(), 2, 3])
683
+
684
+
685
+ @wp.kernel
686
+ def fill_leaf_values_kernel(volume: wp.uint64, ijk: wp.array2d(dtype=wp.int32), values: wp.array(dtype=Any)):
687
+ tid = wp.tid()
688
+
689
+ i = ijk[tid, 0]
690
+ j = ijk[tid, 1]
691
+ k = ijk[tid, 2]
692
+
693
+ expect_eq(tid, wp.volume_lookup_index(volume, i, j, k))
694
+
695
+ values[tid] = wp.volume_lookup(volume, i, j, k, dtype=values.dtype)
696
+
697
+
698
+ @wp.kernel
699
+ def test_volume_sample_index_kernel(
700
+ volume: wp.uint64,
701
+ points: wp.array(dtype=wp.vec3),
702
+ values: wp.array(dtype=Any),
703
+ background: wp.array(dtype=Any),
704
+ sampled_values: wp.array(dtype=Any),
705
+ ):
706
+ tid = wp.tid()
707
+ p = points[tid]
708
+
709
+ ref = wp.volume_sample(volume, p, wp.Volume.LINEAR, dtype=values.dtype)
710
+ sampled_values[tid] = wp.volume_sample_index(volume, p, wp.Volume.LINEAR, values, background[0])
711
+ expect_eq(sampled_values[tid], ref)
712
+
713
+
714
+ @wp.kernel
715
+ def test_volume_sample_grad_index_kernel(
716
+ volume: wp.uint64,
717
+ points: wp.array(dtype=wp.vec3),
718
+ values: wp.array(dtype=Any),
719
+ background: wp.array(dtype=Any),
720
+ sampled_values: wp.array(dtype=Any),
721
+ sampled_grads: wp.array(dtype=Any),
722
+ ):
723
+ tid = wp.tid()
724
+ p = points[tid]
725
+
726
+ ref_grad = sampled_grads.dtype()
727
+ ref = wp.volume_sample_grad(volume, p, wp.Volume.LINEAR, ref_grad, dtype=values.dtype)
728
+
729
+ grad = type(ref_grad)()
730
+ sampled_values[tid] = wp.volume_sample_grad_index(volume, p, wp.Volume.LINEAR, values, background[0], grad)
731
+ expect_eq(sampled_values[tid], ref)
732
+
733
+ expect_eq(grad[0], ref_grad[0])
734
+ expect_eq(grad[1], ref_grad[1])
735
+ expect_eq(grad[2], ref_grad[2])
736
+ sampled_grads[tid] = grad
737
+
738
+
739
+ def test_volume_sample_index(test, device):
740
+ points = rng.uniform(-10.0, 10.0, size=(100, 3))
741
+ points[0:10, 0] += 100.0 # ensure some points are over unallocated voxels
742
+ uvws = wp.array(points, dtype=wp.vec3, device=device)
743
+
744
+ bg_values = {
745
+ "float": 10.0,
746
+ "vec3f": wp.vec3(10.8, -4.13, 10.26),
747
+ }
748
+ grad_types = {
749
+ "float": wp.vec3,
750
+ "vec3f": wp.mat33,
751
+ }
752
+
753
+ for volume_names in ("float", "vec3f"):
754
+ with test.subTest(volume_names=volume_names):
755
+ volume = volumes[volume_names][device.alias]
756
+
757
+ ijk = volume.get_voxels()
758
+
759
+ values = wp.empty(shape=volume.get_voxel_count(), dtype=volume.dtype, device=device, requires_grad=True)
760
+
761
+ vid = wp.uint64(volume.id)
762
+ wp.launch(fill_leaf_values_kernel, dim=values.shape, inputs=[vid, ijk, values], device=device)
763
+
764
+ sampled_values = wp.empty(shape=points.shape[0], dtype=volume.dtype, device=device, requires_grad=True)
765
+ background = wp.array([bg_values[volume_names]], dtype=volume.dtype, device=device, requires_grad=True)
766
+
767
+ tape = wp.Tape()
768
+ with tape:
769
+ wp.launch(
770
+ test_volume_sample_index_kernel,
771
+ dim=points.shape[0],
772
+ inputs=[vid, uvws, values, background, sampled_values],
773
+ device=device,
774
+ )
775
+
776
+ sampled_values.grad.fill_(1.0)
777
+ tape.backward()
778
+
779
+ # test adjoint w.r.t voxel and background value arrays
780
+ # we should have sum(sampled_values) = sum(adj_values * values) + (adj_background * background)
781
+ sum_sampled_values = np.sum(sampled_values.numpy(), axis=0)
782
+ sum_values_adj = np.sum(values.numpy() * values.grad.numpy(), axis=0)
783
+ sum_background_adj = background.numpy()[0] * background.grad.numpy()[0]
784
+
785
+ np.testing.assert_allclose(sum_sampled_values, sum_values_adj + sum_background_adj, rtol=1.0e-3)
786
+
787
+ tape.reset()
788
+
789
+ sampled_grads = wp.empty(
790
+ shape=points.shape[0], dtype=grad_types[volume_names], device=device, requires_grad=True
791
+ )
792
+
793
+ with tape:
794
+ wp.launch(
795
+ test_volume_sample_grad_index_kernel,
796
+ dim=points.shape[0],
797
+ inputs=[vid, uvws, values, background, sampled_values, sampled_grads],
798
+ device=device,
799
+ )
800
+
801
+ sampled_values.grad.fill_(1.0)
802
+ tape.backward()
803
+
804
+ # we should have sum(sampled_values) = sum(adj_values * values) + (adj_background * background)
805
+ sum_sampled_values = np.sum(sampled_values.numpy(), axis=0)
806
+ sum_values_adj = np.sum(values.numpy() * values.grad.numpy(), axis=0)
807
+ sum_background_adj = background.numpy()[0] * background.grad.numpy()[0]
808
+ np.testing.assert_allclose(sum_sampled_values, sum_values_adj + sum_background_adj, rtol=1.0e-3)
809
+
810
+ tape.zero()
811
+ sampled_values.grad.fill_(0.0)
812
+ sampled_grads.grad.fill_(1.0)
813
+ tape.backward()
814
+
815
+ # we should have sum(sampled_grad, axes=(0, -1)) = sum(adj_values * values) + (adj_background * background)
816
+ sum_sampled_grads = np.sum(np.sum(sampled_grads.numpy(), axis=0), axis=-1)
817
+ sum_values_adj = np.sum(values.numpy() * values.grad.numpy(), axis=0)
818
+ sum_background_adj = background.numpy()[0] * background.grad.numpy()[0]
819
+ np.testing.assert_allclose(sum_sampled_grads, sum_values_adj + sum_background_adj, rtol=1.0e-3)
820
+
607
821
 
608
822
  def test_volume_from_numpy(test, device):
609
823
  # Volume.allocate_from_tiles() is only available with CUDA
@@ -657,6 +871,9 @@ add_function_test(TestVolume, "test_volume_introspection", test_volume_introspec
657
871
  add_function_test(
658
872
  TestVolume, "test_volume_from_numpy", test_volume_from_numpy, devices=get_selected_cuda_test_devices()
659
873
  )
874
+ add_function_test(TestVolume, "test_volume_multiple_grids", test_volume_multiple_grids, devices=devices)
875
+ add_function_test(TestVolume, "test_volume_feature_array", test_volume_feature_array, devices=devices)
876
+ add_function_test(TestVolume, "test_volume_sample_index", test_volume_sample_index, devices=devices)
660
877
 
661
878
  points = {}
662
879
  points_jittered = {}
@@ -715,6 +932,13 @@ for device in devices:
715
932
  inputs=[volumes["vec3f"][device.alias].id, points_jittered[device.alias]],
716
933
  devices=[device.alias],
717
934
  )
935
+ add_kernel_test(
936
+ TestVolume,
937
+ test_volume_sample_grad_linear_v,
938
+ dim=len(point_grid),
939
+ inputs=[volumes["vec3f"][device.alias].id, points_jittered[device.alias]],
940
+ devices=[device.alias],
941
+ )
718
942
 
719
943
  add_kernel_test(
720
944
  TestVolume,
@@ -12,9 +12,6 @@ import numpy as np
12
12
  import warp as wp
13
13
  from warp.tests.unittest_utils import *
14
14
 
15
- wp.init()
16
- # wp.config.cache_kernels = False
17
-
18
15
 
19
16
  # Volume write tests
20
17
  @wp.kernel
@@ -166,6 +163,10 @@ def test_volume_allocation(test, device):
166
163
  points_in_world_space=True,
167
164
  device=device,
168
165
  )
166
+
167
+ assert wp.types.types_equal(volume_a.dtype, wp.float32)
168
+ assert wp.types.types_equal(volume_b.dtype, wp.float32)
169
+
169
170
  points = wp.array(points_ref, dtype=wp.vec3, device=device)
170
171
  values_a = wp.empty(num_points, dtype=wp.float32, device=device)
171
172
  values_b = wp.empty(num_points, dtype=wp.float32, device=device)
@@ -201,6 +202,10 @@ def test_volume_allocate_by_tiles_f(test, device):
201
202
  points_ws_d = wp.array(points_ws, dtype=wp.vec3, device=device)
202
203
  volume_a = wp.Volume.allocate_by_tiles(points_is_d, voxel_size, background_value, translation, device=device)
203
204
  volume_b = wp.Volume.allocate_by_tiles(points_ws_d, voxel_size, background_value, translation, device=device)
205
+
206
+ assert wp.types.types_equal(volume_a.dtype, wp.float32)
207
+ assert wp.types.types_equal(volume_b.dtype, wp.float32)
208
+
204
209
  values_a = wp.empty(num_tiles * 512, dtype=wp.float32, device=device)
205
210
  values_b = wp.empty(num_tiles * 512, dtype=wp.float32, device=device)
206
211
 
@@ -229,6 +234,9 @@ def test_volume_allocate_by_tiles_v(test, device):
229
234
 
230
235
  points_d = wp.array(points_is, dtype=wp.int32, device=device)
231
236
  volume = wp.Volume.allocate_by_tiles(points_d, 0.1, wp.vec3(1, 2, 3), device=device)
237
+
238
+ assert wp.types.types_equal(volume.dtype, wp.vec3)
239
+
232
240
  values = wp.empty(len(points_d) * 512, dtype=wp.vec3, device=device)
233
241
 
234
242
  wp.launch(test_volume_tile_store_v, dim=len(points_d), inputs=[volume.id, points_d], device=device)
@@ -238,6 +246,72 @@ def test_volume_allocate_by_tiles_v(test, device):
238
246
  np.testing.assert_equal(values_res, values_ref)
239
247
 
240
248
 
249
+ def test_volume_allocate_by_tiles_index(test, device):
250
+ num_tiles = 10
251
+ rng = np.random.default_rng(101215)
252
+ tiles = rng.integers(-512, 512, size=(num_tiles, 3), dtype=np.int32)
253
+ points_is = tiles * 8
254
+
255
+ points_d = wp.array(points_is, dtype=wp.int32, device=device)
256
+ volume = wp.Volume.allocate_by_tiles(points_d, 0.1, bg_value=None, device=device)
257
+
258
+ assert volume.is_index
259
+
260
+ vol_tiles = volume.get_tiles().numpy() / 8
261
+ vol_tile_sorted = vol_tiles[np.lexsort(vol_tiles.T[::-1])]
262
+ vol_tile_unique = np.unique(vol_tile_sorted, axis=0)
263
+
264
+ tile_sorted = tiles[np.lexsort(tiles.T[::-1])]
265
+ tile_unique = np.unique(tile_sorted, axis=0)
266
+
267
+ np.testing.assert_equal(tile_unique, vol_tile_unique)
268
+
269
+
270
+ def test_volume_allocation_from_voxels(test, device):
271
+ point_count = 387
272
+ rng = np.random.default_rng(101215)
273
+
274
+ # Create from world-space points
275
+ points = wp.array(rng.uniform(5.0, 10.0, size=(point_count, 3)), dtype=float, device=device)
276
+
277
+ volume = wp.Volume.allocate_by_voxels(
278
+ voxel_points=points, voxel_size=0.25, translation=(0.0, 5.0, 10.0), device=device
279
+ )
280
+
281
+ assert volume.is_index
282
+
283
+ test.assertNotEqual(volume.id, 0)
284
+
285
+ test.assertAlmostEqual(volume.get_voxel_size(), (0.25, 0.25, 0.25))
286
+ voxel_count = volume.get_voxel_count()
287
+ test.assertGreaterEqual(point_count, voxel_count)
288
+ test.assertGreaterEqual(voxel_count, 1)
289
+
290
+ voxels = volume.get_voxels()
291
+
292
+ # Check that world-to-index transform has been correctly applied
293
+ voxel_low = np.min(voxels.numpy(), axis=0)
294
+ voxel_up = np.max(voxels.numpy(), axis=0)
295
+ np.testing.assert_array_less([19, -1, -21], voxel_low)
296
+ np.testing.assert_array_less(voxel_up, [41, 21, 1])
297
+
298
+ # Recreate the volume from ijk coords
299
+ volume_from_ijk = wp.Volume.allocate_by_voxels(
300
+ voxel_points=voxels, voxel_size=0.25, translation=(0.0, 5.0, 10.0), device=device
301
+ )
302
+
303
+ assert volume_from_ijk.is_index
304
+
305
+ assert volume_from_ijk.get_voxel_count() == voxel_count
306
+ ijk_voxels = volume_from_ijk.get_voxels().numpy()
307
+
308
+ voxels = voxels.numpy()
309
+ voxel_sorted = voxels[np.lexsort(voxels.T[::-1])]
310
+ ijk_voxel_sorted = ijk_voxels[np.lexsort(ijk_voxels.T[::-1])]
311
+
312
+ np.testing.assert_equal(voxel_sorted, ijk_voxel_sorted)
313
+
314
+
241
315
  devices = get_selected_cuda_test_devices()
242
316
 
243
317
 
@@ -248,6 +322,15 @@ class TestVolumeWrite(unittest.TestCase):
248
322
  add_function_test(TestVolumeWrite, "test_volume_allocation", test_volume_allocation, devices=devices)
249
323
  add_function_test(TestVolumeWrite, "test_volume_allocate_by_tiles_f", test_volume_allocate_by_tiles_f, devices=devices)
250
324
  add_function_test(TestVolumeWrite, "test_volume_allocate_by_tiles_v", test_volume_allocate_by_tiles_v, devices=devices)
325
+ add_function_test(
326
+ TestVolumeWrite, "test_volume_allocate_by_tiles_index", test_volume_allocate_by_tiles_index, devices=devices
327
+ )
328
+ add_function_test(
329
+ TestVolumeWrite,
330
+ "test_volume_allocation_from_voxels",
331
+ test_volume_allocation_from_voxels,
332
+ devices=devices,
333
+ )
251
334
 
252
335
 
253
336
  if __name__ == "__main__":
@@ -5,28 +5,29 @@
5
5
  # distribution of this software and related documentation without an express
6
6
  # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
7
 
8
- import warp as wp
9
- from warp.tests.unittest_utils import TeamCityTestRunner
8
+ import unittest
10
9
 
11
- wp.init()
10
+ import warp as wp
11
+ import warp.tests.unittest_suites
12
12
 
13
13
 
14
14
  def run_suite() -> bool:
15
15
  """Run a test suite"""
16
16
 
17
- import warp.tests.unittest_suites
18
-
19
17
  # force rebuild of all kernels
20
18
  wp.build.clear_kernel_cache()
21
19
  print("Cleared Warp kernel cache")
22
20
 
23
- runner = TeamCityTestRunner(verbosity=2, failfast=False)
21
+ runner = unittest.TextTestRunner(verbosity=2, failfast=True)
22
+
23
+ # Can swap out different suites
24
+ suite = warp.tests.unittest_suites.default_suite()
25
+ # suite = warp.tests.unittest_suites.auto_discover_suite()
26
+ # suite = warp.tests.unittest_suites.kit_suite()
24
27
 
25
- # Can swap out warp.tests.unittest_suites.explicit_suite()
26
- suite = warp.tests.unittest_suites.auto_discover_suite()
27
28
  print(f"Test suite has {suite.countTestCases()} tests")
28
29
 
29
- ret = not runner.run(suite, "WarpTests").wasSuccessful()
30
+ ret = not runner.run(suite).wasSuccessful()
30
31
  return ret
31
32
 
32
33
 
@@ -82,7 +82,7 @@ def compare_unittest_suites(
82
82
  return test_suite
83
83
 
84
84
 
85
- def default_suite(test_loader: unittest.TestLoader):
85
+ def default_suite(test_loader: unittest.TestLoader = unittest.defaultTestLoader):
86
86
  """Example of a manually constructed test suite.
87
87
 
88
88
  Intended to be modified to create additional test suites
@@ -144,6 +144,7 @@ def default_suite(test_loader: unittest.TestLoader):
144
144
  from warp.tests.test_mesh_query_ray import TestMeshQueryRay
145
145
  from warp.tests.test_mlp import TestMLP
146
146
  from warp.tests.test_model import TestModel
147
+ from warp.tests.test_module_hashing import TestModuleHashing
147
148
  from warp.tests.test_modules_lite import TestModuleLite
148
149
  from warp.tests.test_multigpu import TestMultiGPU
149
150
  from warp.tests.test_noise import TestNoise
@@ -234,6 +235,7 @@ def default_suite(test_loader: unittest.TestLoader):
234
235
  TestMeshQueryRay,
235
236
  TestMLP,
236
237
  TestModel,
238
+ TestModuleHashing,
237
239
  TestModuleLite,
238
240
  TestMultiGPU,
239
241
  TestNoise,
@@ -271,7 +273,7 @@ def default_suite(test_loader: unittest.TestLoader):
271
273
  return _create_suite_from_test_classes(test_loader, test_classes)
272
274
 
273
275
 
274
- def kit_suite(test_loader: unittest.TestLoader):
276
+ def kit_suite(test_loader: unittest.TestLoader = unittest.defaultTestLoader):
275
277
  """Tries to mimic the test suite used for testing omni.warp.core in Kit
276
278
 
277
279
  Requires manual updates with test_ext.py for now.
@@ -300,6 +302,7 @@ def kit_suite(test_loader: unittest.TestLoader):
300
302
  from warp.tests.test_mesh_query_aabb import TestMeshQueryAABBMethods
301
303
  from warp.tests.test_mesh_query_point import TestMeshQueryPoint
302
304
  from warp.tests.test_mesh_query_ray import TestMeshQueryRay
305
+ from warp.tests.test_module_hashing import TestModuleHashing
303
306
  from warp.tests.test_modules_lite import TestModuleLite
304
307
  from warp.tests.test_noise import TestNoise
305
308
  from warp.tests.test_operators import TestOperators
@@ -342,6 +345,7 @@ def kit_suite(test_loader: unittest.TestLoader):
342
345
  TestMeshQueryAABBMethods,
343
346
  TestMeshQueryPoint,
344
347
  TestMeshQueryRay,
348
+ TestModuleHashing,
345
349
  TestModuleLite,
346
350
  TestNoise,
347
351
  TestOperators,