warp-lang 1.7.2rc1__py3-none-manylinux_2_34_aarch64.whl → 1.8.1__py3-none-manylinux_2_34_aarch64.whl

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

Potentially problematic release.


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

Files changed (193) hide show
  1. warp/__init__.py +3 -1
  2. warp/__init__.pyi +3489 -1
  3. warp/autograd.py +45 -122
  4. warp/bin/warp-clang.so +0 -0
  5. warp/bin/warp.so +0 -0
  6. warp/build.py +241 -252
  7. warp/build_dll.py +130 -26
  8. warp/builtins.py +1907 -384
  9. warp/codegen.py +272 -104
  10. warp/config.py +12 -1
  11. warp/constants.py +1 -1
  12. warp/context.py +770 -238
  13. warp/dlpack.py +1 -1
  14. warp/examples/benchmarks/benchmark_cloth.py +2 -2
  15. warp/examples/benchmarks/benchmark_tile_sort.py +155 -0
  16. warp/examples/core/example_sample_mesh.py +1 -1
  17. warp/examples/core/example_spin_lock.py +93 -0
  18. warp/examples/core/example_work_queue.py +118 -0
  19. warp/examples/fem/example_adaptive_grid.py +5 -5
  20. warp/examples/fem/example_apic_fluid.py +1 -1
  21. warp/examples/fem/example_burgers.py +1 -1
  22. warp/examples/fem/example_convection_diffusion.py +9 -6
  23. warp/examples/fem/example_darcy_ls_optimization.py +489 -0
  24. warp/examples/fem/example_deformed_geometry.py +1 -1
  25. warp/examples/fem/example_diffusion.py +2 -2
  26. warp/examples/fem/example_diffusion_3d.py +1 -1
  27. warp/examples/fem/example_distortion_energy.py +1 -1
  28. warp/examples/fem/example_elastic_shape_optimization.py +387 -0
  29. warp/examples/fem/example_magnetostatics.py +5 -3
  30. warp/examples/fem/example_mixed_elasticity.py +5 -3
  31. warp/examples/fem/example_navier_stokes.py +11 -9
  32. warp/examples/fem/example_nonconforming_contact.py +5 -3
  33. warp/examples/fem/example_streamlines.py +8 -3
  34. warp/examples/fem/utils.py +9 -8
  35. warp/examples/interop/example_jax_callable.py +34 -4
  36. warp/examples/interop/example_jax_ffi_callback.py +2 -2
  37. warp/examples/interop/example_jax_kernel.py +27 -1
  38. warp/examples/optim/example_drone.py +1 -1
  39. warp/examples/sim/example_cloth.py +1 -1
  40. warp/examples/sim/example_cloth_self_contact.py +48 -54
  41. warp/examples/tile/example_tile_block_cholesky.py +502 -0
  42. warp/examples/tile/example_tile_cholesky.py +2 -1
  43. warp/examples/tile/example_tile_convolution.py +1 -1
  44. warp/examples/tile/example_tile_filtering.py +1 -1
  45. warp/examples/tile/example_tile_matmul.py +1 -1
  46. warp/examples/tile/example_tile_mlp.py +2 -0
  47. warp/fabric.py +7 -7
  48. warp/fem/__init__.py +5 -0
  49. warp/fem/adaptivity.py +1 -1
  50. warp/fem/cache.py +152 -63
  51. warp/fem/dirichlet.py +2 -2
  52. warp/fem/domain.py +136 -6
  53. warp/fem/field/field.py +141 -99
  54. warp/fem/field/nodal_field.py +85 -39
  55. warp/fem/field/virtual.py +99 -52
  56. warp/fem/geometry/adaptive_nanogrid.py +91 -86
  57. warp/fem/geometry/closest_point.py +13 -0
  58. warp/fem/geometry/deformed_geometry.py +102 -40
  59. warp/fem/geometry/element.py +56 -2
  60. warp/fem/geometry/geometry.py +323 -22
  61. warp/fem/geometry/grid_2d.py +157 -62
  62. warp/fem/geometry/grid_3d.py +116 -20
  63. warp/fem/geometry/hexmesh.py +86 -20
  64. warp/fem/geometry/nanogrid.py +166 -86
  65. warp/fem/geometry/partition.py +59 -25
  66. warp/fem/geometry/quadmesh.py +86 -135
  67. warp/fem/geometry/tetmesh.py +47 -119
  68. warp/fem/geometry/trimesh.py +77 -270
  69. warp/fem/integrate.py +181 -95
  70. warp/fem/linalg.py +25 -58
  71. warp/fem/operator.py +124 -27
  72. warp/fem/quadrature/pic_quadrature.py +36 -14
  73. warp/fem/quadrature/quadrature.py +40 -16
  74. warp/fem/space/__init__.py +1 -1
  75. warp/fem/space/basis_function_space.py +66 -46
  76. warp/fem/space/basis_space.py +17 -4
  77. warp/fem/space/dof_mapper.py +1 -1
  78. warp/fem/space/function_space.py +2 -2
  79. warp/fem/space/grid_2d_function_space.py +4 -1
  80. warp/fem/space/hexmesh_function_space.py +4 -2
  81. warp/fem/space/nanogrid_function_space.py +3 -1
  82. warp/fem/space/partition.py +11 -2
  83. warp/fem/space/quadmesh_function_space.py +4 -1
  84. warp/fem/space/restriction.py +5 -2
  85. warp/fem/space/shape/__init__.py +10 -8
  86. warp/fem/space/tetmesh_function_space.py +4 -1
  87. warp/fem/space/topology.py +52 -21
  88. warp/fem/space/trimesh_function_space.py +4 -1
  89. warp/fem/utils.py +53 -8
  90. warp/jax.py +1 -2
  91. warp/jax_experimental/ffi.py +210 -67
  92. warp/jax_experimental/xla_ffi.py +37 -24
  93. warp/math.py +171 -1
  94. warp/native/array.h +103 -4
  95. warp/native/builtin.h +182 -35
  96. warp/native/coloring.cpp +6 -2
  97. warp/native/cuda_util.cpp +1 -1
  98. warp/native/exports.h +118 -63
  99. warp/native/intersect.h +5 -5
  100. warp/native/mat.h +8 -13
  101. warp/native/mathdx.cpp +11 -5
  102. warp/native/matnn.h +1 -123
  103. warp/native/mesh.h +1 -1
  104. warp/native/quat.h +34 -6
  105. warp/native/rand.h +7 -7
  106. warp/native/sparse.cpp +121 -258
  107. warp/native/sparse.cu +181 -274
  108. warp/native/spatial.h +305 -17
  109. warp/native/svd.h +23 -8
  110. warp/native/tile.h +603 -73
  111. warp/native/tile_radix_sort.h +1112 -0
  112. warp/native/tile_reduce.h +239 -13
  113. warp/native/tile_scan.h +240 -0
  114. warp/native/tuple.h +189 -0
  115. warp/native/vec.h +10 -20
  116. warp/native/warp.cpp +36 -4
  117. warp/native/warp.cu +588 -52
  118. warp/native/warp.h +47 -74
  119. warp/optim/linear.py +5 -1
  120. warp/paddle.py +7 -8
  121. warp/py.typed +0 -0
  122. warp/render/render_opengl.py +110 -80
  123. warp/render/render_usd.py +124 -62
  124. warp/sim/__init__.py +9 -0
  125. warp/sim/collide.py +253 -80
  126. warp/sim/graph_coloring.py +8 -1
  127. warp/sim/import_mjcf.py +4 -3
  128. warp/sim/import_usd.py +11 -7
  129. warp/sim/integrator.py +5 -2
  130. warp/sim/integrator_euler.py +1 -1
  131. warp/sim/integrator_featherstone.py +1 -1
  132. warp/sim/integrator_vbd.py +761 -322
  133. warp/sim/integrator_xpbd.py +1 -1
  134. warp/sim/model.py +265 -260
  135. warp/sim/utils.py +10 -7
  136. warp/sparse.py +303 -166
  137. warp/tape.py +54 -51
  138. warp/tests/cuda/test_conditional_captures.py +1046 -0
  139. warp/tests/cuda/test_streams.py +1 -1
  140. warp/tests/geometry/test_volume.py +2 -2
  141. warp/tests/interop/test_dlpack.py +9 -9
  142. warp/tests/interop/test_jax.py +0 -1
  143. warp/tests/run_coverage_serial.py +1 -1
  144. warp/tests/sim/disabled_kinematics.py +2 -2
  145. warp/tests/sim/{test_vbd.py → test_cloth.py} +378 -112
  146. warp/tests/sim/test_collision.py +159 -51
  147. warp/tests/sim/test_coloring.py +91 -2
  148. warp/tests/test_array.py +254 -2
  149. warp/tests/test_array_reduce.py +2 -2
  150. warp/tests/test_assert.py +53 -0
  151. warp/tests/test_atomic_cas.py +312 -0
  152. warp/tests/test_codegen.py +142 -19
  153. warp/tests/test_conditional.py +47 -1
  154. warp/tests/test_ctypes.py +0 -20
  155. warp/tests/test_devices.py +8 -0
  156. warp/tests/test_fabricarray.py +4 -2
  157. warp/tests/test_fem.py +58 -25
  158. warp/tests/test_func.py +42 -1
  159. warp/tests/test_grad.py +1 -1
  160. warp/tests/test_lerp.py +1 -3
  161. warp/tests/test_map.py +481 -0
  162. warp/tests/test_mat.py +23 -24
  163. warp/tests/test_quat.py +28 -15
  164. warp/tests/test_rounding.py +10 -38
  165. warp/tests/test_runlength_encode.py +7 -7
  166. warp/tests/test_smoothstep.py +1 -1
  167. warp/tests/test_sparse.py +83 -2
  168. warp/tests/test_spatial.py +507 -1
  169. warp/tests/test_static.py +48 -0
  170. warp/tests/test_struct.py +2 -2
  171. warp/tests/test_tape.py +38 -0
  172. warp/tests/test_tuple.py +265 -0
  173. warp/tests/test_types.py +2 -2
  174. warp/tests/test_utils.py +24 -18
  175. warp/tests/test_vec.py +38 -408
  176. warp/tests/test_vec_constructors.py +325 -0
  177. warp/tests/tile/test_tile.py +438 -131
  178. warp/tests/tile/test_tile_mathdx.py +518 -14
  179. warp/tests/tile/test_tile_matmul.py +179 -0
  180. warp/tests/tile/test_tile_reduce.py +307 -5
  181. warp/tests/tile/test_tile_shared_memory.py +136 -7
  182. warp/tests/tile/test_tile_sort.py +121 -0
  183. warp/tests/unittest_suites.py +14 -6
  184. warp/types.py +462 -308
  185. warp/utils.py +647 -86
  186. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/METADATA +20 -6
  187. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/RECORD +190 -176
  188. warp/stubs.py +0 -3381
  189. warp/tests/sim/test_xpbd.py +0 -399
  190. warp/tests/test_mlp.py +0 -282
  191. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/WHEEL +0 -0
  192. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/licenses/LICENSE.md +0 -0
  193. {warp_lang-1.7.2rc1.dist-info → warp_lang-1.8.1.dist-info}/top_level.txt +0 -0
@@ -435,14 +435,8 @@ def test_error_collection_construct(test, device):
435
435
  x = [1.0, 2.0, 3.0]
436
436
 
437
437
  def kernel_2_fn():
438
- x = (1.0, 2.0, 3.0)
439
-
440
- def kernel_3_fn():
441
438
  x = {"a": 1.0, "b": 2.0, "c": 3.0}
442
439
 
443
- def kernel_4_fn():
444
- wp.length((1.0, 2.0, 3.0))
445
-
446
440
  kernel = wp.Kernel(func=kernel_1_fn)
447
441
  with test.assertRaisesRegex(
448
442
  RuntimeError,
@@ -451,22 +445,9 @@ def test_error_collection_construct(test, device):
451
445
  wp.launch(kernel, dim=1, device=device)
452
446
 
453
447
  kernel = wp.Kernel(func=kernel_2_fn)
454
- with test.assertRaisesRegex(
455
- RuntimeError,
456
- r"Tuple constructs are not supported in kernels. Use vectors like `wp.vec3\(\)` for small collections instead.",
457
- ):
458
- wp.launch(kernel, dim=1, device=device)
459
-
460
- kernel = wp.Kernel(func=kernel_3_fn)
461
448
  with test.assertRaisesRegex(RuntimeError, r"Construct `ast.Dict` not supported in kernels."):
462
449
  wp.launch(kernel, dim=1, device=device)
463
450
 
464
- kernel = wp.Kernel(func=kernel_4_fn)
465
- with test.assertRaisesRegex(
466
- RuntimeError, r"Tuple constructs are not supported in kernels. Use vectors like `wp.vec3\(\)` instead."
467
- ):
468
- wp.launch(kernel, dim=1, device=device)
469
-
470
451
 
471
452
  def test_error_unmatched_arguments(test, device):
472
453
  def kernel_1_fn():
@@ -693,6 +674,138 @@ def test_codegen_return_in_kernel(test, device):
693
674
  test.assertEqual(result.numpy()[0], grid_size - 256)
694
675
 
695
676
 
677
+ @wp.kernel
678
+ def conditional_ifexp(x: float, result: wp.array(dtype=wp.int32)):
679
+ wp.atomic_add(result, 0, 1) if x > 0.0 else wp.atomic_add(result, 1, 1)
680
+
681
+
682
+ def test_ifexp_only_executes_one_branch(test, device):
683
+ result = wp.zeros(2, dtype=wp.int32, device=device)
684
+
685
+ wp.launch(conditional_ifexp, dim=1, inputs=[1.0, result], device=device)
686
+
687
+ values = result.numpy()
688
+ # Only first branch is taken
689
+ test.assertEqual(values[0], 1)
690
+ test.assertEqual(values[1], 0)
691
+
692
+
693
+ @wp.kernel
694
+ def test_multiple_return_values_quat_to_axis_angle_kernel(
695
+ q: wp.quath,
696
+ expected_axis: wp.vec3h,
697
+ expected_angle: wp.float16,
698
+ ):
699
+ axis, angle = wp.quat_to_axis_angle(q)
700
+
701
+ wp.expect_near(axis[0], expected_axis[0], tolerance=wp.float16(1e-3))
702
+ wp.expect_near(axis[1], expected_axis[1], tolerance=wp.float16(1e-3))
703
+ wp.expect_near(axis[2], expected_axis[2], tolerance=wp.float16(1e-3))
704
+
705
+ wp.expect_near(angle, expected_angle, tolerance=wp.float16(1e-3))
706
+
707
+
708
+ @wp.kernel
709
+ def test_multiple_return_values_svd3_kernel(
710
+ A: wp.mat33f,
711
+ expected_U: wp.mat33f,
712
+ expected_sigma: wp.vec3f,
713
+ expected_V: wp.mat33f,
714
+ ):
715
+ U, sigma, V = wp.svd3(A)
716
+
717
+ wp.expect_near(U[0][0], expected_U[0][0], tolerance=1e-5)
718
+ wp.expect_near(U[0][1], expected_U[0][1], tolerance=1e-5)
719
+ wp.expect_near(U[0][2], expected_U[0][2], tolerance=1e-5)
720
+ wp.expect_near(U[1][0], expected_U[1][0], tolerance=1e-5)
721
+ wp.expect_near(U[1][1], expected_U[1][1], tolerance=1e-5)
722
+ wp.expect_near(U[1][2], expected_U[1][2], tolerance=1e-5)
723
+ wp.expect_near(U[2][0], expected_U[2][0], tolerance=1e-5)
724
+ wp.expect_near(U[2][1], expected_U[2][1], tolerance=1e-5)
725
+ wp.expect_near(U[2][2], expected_U[2][2], tolerance=1e-5)
726
+
727
+ wp.expect_near(sigma[0], expected_sigma[0], tolerance=1e-5)
728
+ wp.expect_near(sigma[1], expected_sigma[1], tolerance=1e-5)
729
+ wp.expect_near(sigma[2], expected_sigma[2], tolerance=1e-5)
730
+
731
+ wp.expect_near(V[0][0], expected_V[0][0], tolerance=1e-5)
732
+ wp.expect_near(V[0][1], expected_V[0][1], tolerance=1e-5)
733
+ wp.expect_near(V[0][2], expected_V[0][2], tolerance=1e-5)
734
+ wp.expect_near(V[1][0], expected_V[1][0], tolerance=1e-5)
735
+ wp.expect_near(V[1][1], expected_V[1][1], tolerance=1e-5)
736
+ wp.expect_near(V[1][2], expected_V[1][2], tolerance=1e-5)
737
+ wp.expect_near(V[2][0], expected_V[2][0], tolerance=1e-5)
738
+ wp.expect_near(V[2][1], expected_V[2][1], tolerance=1e-5)
739
+ wp.expect_near(V[2][2], expected_V[2][2], tolerance=1e-5)
740
+
741
+
742
+ def test_multiple_return_values(test, device):
743
+ q = wp.quath(1.0, 2.0, 3.0, 4.0)
744
+ expected_axis = wp.vec3h(0.26726124, 0.53452247, 0.80178368)
745
+ expected_angle = 1.50408018
746
+
747
+ axis, angle = wp.quat_to_axis_angle(q)
748
+
749
+ test.assertAlmostEqual(axis[0], expected_axis[0], places=3)
750
+ test.assertAlmostEqual(axis[1], expected_axis[1], places=3)
751
+ test.assertAlmostEqual(axis[2], expected_axis[2], places=3)
752
+
753
+ test.assertAlmostEqual(angle, expected_angle, places=3)
754
+
755
+ wp.launch(
756
+ test_multiple_return_values_quat_to_axis_angle_kernel,
757
+ dim=1,
758
+ inputs=(q, expected_axis, expected_angle),
759
+ )
760
+
761
+ # fmt: off
762
+ A = wp.mat33(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
763
+ expected_U = wp.mat33(
764
+ 0.21483721, 0.88723058, -0.40824816,
765
+ 0.52058744, 0.24964368, 0.81649637,
766
+ 0.82633746, -0.38794267, -0.40824834,
767
+ )
768
+ expected_sigma = wp.vec3(16.84809875, 1.06836915, 0.00000019)
769
+ expected_V = wp.mat33(
770
+ 0.47967088, -0.77669406, 0.40824246,
771
+ 0.57236743, -0.07568054, -0.81649727,
772
+ 0.66506463, 0.62531471, 0.40825251,
773
+ )
774
+ # fmt: on
775
+
776
+ U, sigma, V = wp.svd3(A)
777
+
778
+ test.assertAlmostEqual(U[0][0], expected_U[0][0], places=5)
779
+ test.assertAlmostEqual(U[0][1], expected_U[0][1], places=5)
780
+ test.assertAlmostEqual(U[0][2], expected_U[0][2], places=5)
781
+ test.assertAlmostEqual(U[1][0], expected_U[1][0], places=5)
782
+ test.assertAlmostEqual(U[1][1], expected_U[1][1], places=5)
783
+ test.assertAlmostEqual(U[1][2], expected_U[1][2], places=5)
784
+ test.assertAlmostEqual(U[2][0], expected_U[2][0], places=5)
785
+ test.assertAlmostEqual(U[2][1], expected_U[2][1], places=5)
786
+ test.assertAlmostEqual(U[2][2], expected_U[2][2], places=5)
787
+
788
+ test.assertAlmostEqual(sigma[0], expected_sigma[0], places=5)
789
+ test.assertAlmostEqual(sigma[1], expected_sigma[1], places=5)
790
+ test.assertAlmostEqual(sigma[2], expected_sigma[2], places=5)
791
+
792
+ test.assertAlmostEqual(V[0][0], expected_V[0][0], places=5)
793
+ test.assertAlmostEqual(V[0][1], expected_V[0][1], places=5)
794
+ test.assertAlmostEqual(V[0][2], expected_V[0][2], places=5)
795
+ test.assertAlmostEqual(V[1][0], expected_V[1][0], places=5)
796
+ test.assertAlmostEqual(V[1][1], expected_V[1][1], places=5)
797
+ test.assertAlmostEqual(V[1][2], expected_V[1][2], places=5)
798
+ test.assertAlmostEqual(V[2][0], expected_V[2][0], places=5)
799
+ test.assertAlmostEqual(V[2][1], expected_V[2][1], places=5)
800
+ test.assertAlmostEqual(V[2][2], expected_V[2][2], places=5)
801
+
802
+ wp.launch(
803
+ test_multiple_return_values_svd3_kernel,
804
+ dim=1,
805
+ inputs=(A, expected_U, expected_sigma, expected_V),
806
+ )
807
+
808
+
696
809
  class TestCodeGen(unittest.TestCase):
697
810
  pass
698
811
 
@@ -825,6 +938,16 @@ add_kernel_test(TestCodeGen, name="test_call_syntax", kernel=test_call_syntax, d
825
938
  add_kernel_test(TestCodeGen, name="test_shadow_builtin", kernel=test_shadow_builtin, dim=1, devices=devices)
826
939
  add_kernel_test(TestCodeGen, name="test_while_condition_eval", kernel=test_while_condition_eval, dim=1, devices=devices)
827
940
  add_function_test(TestCodeGen, "test_codegen_return_in_kernel", test_codegen_return_in_kernel, devices=devices)
941
+ add_function_test(
942
+ TestCodeGen, "test_ifexp_only_executes_one_branch", test_ifexp_only_executes_one_branch, devices=devices
943
+ )
944
+ add_function_test(
945
+ TestCodeGen,
946
+ func=test_multiple_return_values,
947
+ name="test_multiple_return_values",
948
+ devices=devices,
949
+ )
950
+
828
951
 
829
952
  if __name__ == "__main__":
830
953
  wp.clear_kernel_cache()
@@ -58,6 +58,48 @@ def test_conditional_if_else_nested():
58
58
  wp.expect_eq(e, -2.0)
59
59
 
60
60
 
61
+ @wp.kernel
62
+ def test_conditional_ifexp():
63
+ a = 0.5
64
+ b = 2.0
65
+
66
+ c = 1.0 if a > b else -1.0
67
+
68
+ wp.expect_eq(c, -1.0)
69
+
70
+
71
+ @wp.kernel
72
+ def test_conditional_ifexp_nested():
73
+ a = 1.0
74
+ b = 2.0
75
+
76
+ c = 3.0 if a > b else 6.0
77
+ d = 4.0 if a > b else 7.0
78
+ e = 1.0 if (a > b and c > d) else (-1.0 if a > b else (2.0 if c > d else -2.0))
79
+
80
+ wp.expect_eq(e, -2.0)
81
+
82
+
83
+ @wp.kernel
84
+ def test_conditional_ifexp_constant():
85
+ a = 1.0 if False else -1.0
86
+ b = 2.0 if 123 else -2.0
87
+
88
+ wp.expect_eq(a, -1.0)
89
+ wp.expect_eq(b, 2.0)
90
+
91
+
92
+ @wp.kernel
93
+ def test_conditional_ifexp_constant_nested():
94
+ a = 1.0 if False else (2.0 if True else 3.0)
95
+ b = 4.0 if 0 else (5.0 if 0 else (6.0 if False else 7.0))
96
+ c = 8.0 if False else (9.0 if False else (10.0 if 321 else 11.0))
97
+
98
+ wp.expect_eq(a, 2.0)
99
+ wp.expect_eq(b, 7.0)
100
+ wp.expect_eq(c, 10.0)
101
+
102
+
61
103
  @wp.kernel
62
104
  def test_boolean_and():
63
105
  a = 1.0
@@ -90,7 +132,7 @@ def test_boolean_compound():
90
132
 
91
133
  d = 1.0
92
134
 
93
- if a > 0.0 and b > 0.0 or c > a:
135
+ if (a > 0.0 and b > 0.0) or c > a:
94
136
  d = -1.0
95
137
 
96
138
  wp.expect_eq(d, -1.0)
@@ -231,6 +273,10 @@ class TestConditional(unittest.TestCase):
231
273
 
232
274
  add_kernel_test(TestConditional, kernel=test_conditional_if_else, dim=1, devices=devices)
233
275
  add_kernel_test(TestConditional, kernel=test_conditional_if_else_nested, dim=1, devices=devices)
276
+ add_kernel_test(TestConditional, kernel=test_conditional_ifexp, dim=1, devices=devices)
277
+ add_kernel_test(TestConditional, kernel=test_conditional_ifexp_nested, dim=1, devices=devices)
278
+ add_kernel_test(TestConditional, kernel=test_conditional_ifexp_constant, dim=1, devices=devices)
279
+ add_kernel_test(TestConditional, kernel=test_conditional_ifexp_constant_nested, dim=1, devices=devices)
234
280
  add_kernel_test(TestConditional, kernel=test_boolean_and, dim=1, devices=devices)
235
281
  add_kernel_test(TestConditional, kernel=test_boolean_or, dim=1, devices=devices)
236
282
  add_kernel_test(TestConditional, kernel=test_boolean_compound, dim=1, devices=devices)
warp/tests/test_ctypes.py CHANGED
@@ -541,25 +541,6 @@ def test_scalar_array_types(test, device, load, store):
541
541
  )
542
542
 
543
543
 
544
- @wp.kernel
545
- def test_transform_matrix():
546
- r = wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.5)
547
- t = wp.vec3(0.25, 0.5, -0.75)
548
- s = wp.vec3(2.0, 0.5, 0.75)
549
-
550
- m = wp.mat44(t, r, s)
551
-
552
- p = wp.vec3(1.0, 2.0, 3.0)
553
-
554
- r_0 = wp.quat_rotate(r, wp.cw_mul(s, p)) + t
555
- r_1 = wp.transform_point(m, p)
556
-
557
- r_2 = wp.transform_vector(m, p)
558
-
559
- wp.expect_near(r_0, r_1, 1.0e-4)
560
- wp.expect_near(r_2, r_0 - t, 1.0e-4)
561
-
562
-
563
544
  devices = get_test_devices()
564
545
 
565
546
 
@@ -628,7 +609,6 @@ add_function_test(TestCTypes, "test_vec2_transform", test_vec2_transform, device
628
609
  add_function_test(TestCTypes, "test_vec3_arg", test_vec3_arg, devices=devices, n=8)
629
610
  add_function_test(TestCTypes, "test_vec3_transform", test_vec3_transform, devices=devices, n=8)
630
611
  add_function_test(TestCTypes, "test_transform_multiply", test_transform_multiply, devices=devices, n=8)
631
- add_kernel_test(TestCTypes, name="test_transform_matrix", kernel=test_transform_matrix, dim=1, devices=devices)
632
612
  add_function_test(TestCTypes, "test_scalar_array", test_scalar_array, devices=devices)
633
613
  add_function_test(TestCTypes, "test_vector_array", test_vector_array, devices=devices)
634
614
 
@@ -70,6 +70,13 @@ def test_devices_can_access_self(test, device):
70
70
  test.assertNotEqual(device, device_str)
71
71
 
72
72
 
73
+ def test_devices_sm_count(test, device):
74
+ if device.is_cuda:
75
+ test.assertTrue(device.sm_count > 0)
76
+ else:
77
+ test.assertEqual(device.sm_count, 0)
78
+
79
+
73
80
  devices = get_test_devices()
74
81
 
75
82
 
@@ -90,6 +97,7 @@ add_function_test(
90
97
  )
91
98
  add_function_test(TestDevices, "test_devices_verify_cuda_device", test_devices_verify_cuda_device, devices=devices)
92
99
  add_function_test(TestDevices, "test_devices_can_access_self", test_devices_can_access_self, devices=devices)
100
+ add_function_test(TestDevices, "test_devices_sm_count", test_devices_sm_count, devices=devices)
93
101
 
94
102
 
95
103
  if __name__ == "__main__":
@@ -13,6 +13,8 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from __future__ import annotations
17
+
16
18
  import math
17
19
  import unittest
18
20
  from typing import Any
@@ -70,7 +72,7 @@ def _warp_type_to_fabric(dtype, is_array=False):
70
72
 
71
73
 
72
74
  # returns a fabric array interface constructed from a regular array
73
- def _create_fabric_array_interface(data: wp.array, attrib: str, bucket_sizes: list = None, copy=False):
75
+ def _create_fabric_array_interface(data: wp.array, attrib: str, bucket_sizes: list[int] | None = None, copy=False):
74
76
  assert isinstance(data, wp.array)
75
77
  assert data.ndim == 1
76
78
 
@@ -138,7 +140,7 @@ def _create_fabric_array_interface(data: wp.array, attrib: str, bucket_sizes: li
138
140
 
139
141
 
140
142
  # returns a fabric array array interface constructed from a list of regular arrays
141
- def _create_fabric_array_array_interface(data: list, attrib: str, bucket_sizes: list = None):
143
+ def _create_fabric_array_array_interface(data: list, attrib: str, bucket_sizes: list[int] | None = None):
142
144
  # data should be a list of arrays
143
145
  assert isinstance(data, list)
144
146
 
warp/tests/test_fem.py CHANGED
@@ -476,11 +476,8 @@ def _test_geo_cells(
476
476
  wp.atomic_add(cell_measures, s.element_index, fem.measure(domain, s) * s.qp_weight)
477
477
 
478
478
 
479
- @fem.integrand(kernel_options={"enable_backward": False})
480
- def _test_cell_lookup(
481
- s: fem.Sample,
482
- domain: fem.Domain,
483
- ):
479
+ @fem.integrand(kernel_options={"enable_backward": False, "max_unroll": 2})
480
+ def _test_cell_lookup(s: fem.Sample, domain: fem.Domain, cell_filter: wp.array(dtype=int)):
484
481
  pos = domain(s)
485
482
 
486
483
  s_guess = fem.lookup(domain, pos, s)
@@ -491,6 +488,23 @@ def _test_cell_lookup(
491
488
  wp.expect_eq(s_noguess.element_index, s.element_index)
492
489
  wp.expect_near(domain(s_noguess), pos, 0.001)
493
490
 
491
+ # Filtered lookup
492
+ max_dist = 10.0
493
+ filter_target = 1
494
+ s_filter = fem.lookup(domain, pos, max_dist, cell_filter, filter_target)
495
+ wp.expect_eq(s_filter.element_index, 0)
496
+
497
+ if s.element_index != 0:
498
+ # test closest point optimality
499
+ pos_f = domain(s_filter)
500
+ pos_f += 0.1 * (pos - pos_f)
501
+ coord_proj, _sq_dist = fem.element_closest_point(domain, s_filter.element_index, pos_f)
502
+ wp.expect_near(coord_proj, s_filter.element_coords, 0.001)
503
+
504
+ # test that extrapolated coordinates yield bak correct position
505
+ s_filter.element_coords = fem.element_coordinates(domain, s_filter.element_index, pos)
506
+ wp.expect_near(domain(s_filter), pos, 0.001)
507
+
494
508
 
495
509
  @fem.integrand(kernel_options={"enable_backward": False, "max_unroll": 1})
496
510
  def _test_geo_sides(
@@ -520,6 +534,7 @@ def _test_geo_sides(
520
534
 
521
535
  wp.expect_near(coords, inner_side_s.element_coords, 0.0001)
522
536
  wp.expect_near(coords, outer_side_s.element_coords, 0.0001)
537
+ wp.expect_near(coords, fem.element_coordinates(domain, side_index, pos_side), 0.001)
523
538
 
524
539
  area = fem.measure(domain, s)
525
540
  wp.atomic_add(side_measures, side_index, area * s.qp_weight)
@@ -544,7 +559,7 @@ def _test_side_normals(
544
559
  wp.expect_near(F_cross[k], nor[k], 0.0001)
545
560
 
546
561
 
547
- def _launch_test_geometry_kernel(geo: fem.Geometry, device, test_cell_lookup: bool = True):
562
+ def _launch_test_geometry_kernel(geo: fem.Geometry, device):
548
563
  cell_measures = wp.zeros(dtype=float, device=device, shape=geo.cell_count())
549
564
  cell_quadrature = fem.RegularQuadrature(fem.Cells(geo), order=2)
550
565
 
@@ -557,11 +572,11 @@ def _launch_test_geometry_kernel(geo: fem.Geometry, device, test_cell_lookup: bo
557
572
  quadrature=cell_quadrature,
558
573
  values={"cell_measures": cell_measures},
559
574
  )
560
- if test_cell_lookup:
561
- fem.interpolate(
562
- _test_cell_lookup,
563
- quadrature=cell_quadrature,
564
- )
575
+
576
+ cell_filter = np.zeros(geo.cell_count(), dtype=int)
577
+ cell_filter[0] = 1
578
+ cell_filter = wp.array(cell_filter, dtype=int)
579
+ fem.interpolate(_test_cell_lookup, quadrature=cell_quadrature, values={"cell_filter": cell_filter})
565
580
 
566
581
  fem.interpolate(
567
582
  _test_geo_sides,
@@ -637,14 +652,14 @@ def test_quad_mesh(test, device):
637
652
  with wp.ScopedDevice(device):
638
653
  positions, quad_vidx = _gen_quadmesh(N)
639
654
 
640
- geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
655
+ geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions, build_bvh=True)
641
656
 
642
657
  test.assertEqual(geo.cell_count(), N**2)
643
658
  test.assertEqual(geo.vertex_count(), (N + 1) ** 2)
644
659
  test.assertEqual(geo.side_count(), 2 * (N + 1) * N)
645
660
  test.assertEqual(geo.boundary_side_count(), 4 * N)
646
661
 
647
- side_measures, cell_measures = _launch_test_geometry_kernel(geo, device, test_cell_lookup=False)
662
+ side_measures, cell_measures = _launch_test_geometry_kernel(geo, device)
648
663
 
649
664
  assert_np_equal(side_measures.numpy(), np.full(side_measures.shape, 1.0 / (N)), tol=1.0e-4)
650
665
  assert_np_equal(cell_measures.numpy(), np.full(cell_measures.shape, 1.0 / (N**2)), tol=1.0e-4)
@@ -655,14 +670,14 @@ def test_quad_mesh(test, device):
655
670
  positions = np.hstack((positions, np.ones((positions.shape[0], 1))))
656
671
  positions = wp.array(positions, device=device, dtype=wp.vec3)
657
672
 
658
- geo = fem.Quadmesh3D(quad_vertex_indices=quad_vidx, positions=positions)
673
+ geo = fem.Quadmesh3D(quad_vertex_indices=quad_vidx, positions=positions, build_bvh=True)
659
674
 
660
675
  test.assertEqual(geo.cell_count(), N**2)
661
676
  test.assertEqual(geo.vertex_count(), (N + 1) ** 2)
662
677
  test.assertEqual(geo.side_count(), 2 * (N + 1) * N)
663
678
  test.assertEqual(geo.boundary_side_count(), 4 * N)
664
679
 
665
- side_measures, cell_measures = _launch_test_geometry_kernel(geo, device, test_cell_lookup=False)
680
+ side_measures, cell_measures = _launch_test_geometry_kernel(geo, device)
666
681
 
667
682
  assert_np_equal(side_measures.numpy(), np.full(side_measures.shape, 1.0 / (N)), tol=1.0e-4)
668
683
  assert_np_equal(cell_measures.numpy(), np.full(cell_measures.shape, 1.0 / (N**2)), tol=1.0e-4)
@@ -711,7 +726,7 @@ def test_hex_mesh(test, device):
711
726
  with wp.ScopedDevice(device):
712
727
  positions, tet_vidx = _gen_hexmesh(N)
713
728
 
714
- geo = fem.Hexmesh(hex_vertex_indices=tet_vidx, positions=positions)
729
+ geo = fem.Hexmesh(hex_vertex_indices=tet_vidx, positions=positions, build_bvh=True)
715
730
 
716
731
  test.assertEqual(geo.cell_count(), (N) ** 3)
717
732
  test.assertEqual(geo.vertex_count(), (N + 1) ** 3)
@@ -719,7 +734,7 @@ def test_hex_mesh(test, device):
719
734
  test.assertEqual(geo.boundary_side_count(), 6 * N * N)
720
735
  test.assertEqual(geo.edge_count(), 3 * N * (N + 1) ** 2)
721
736
 
722
- side_measures, cell_measures = _launch_test_geometry_kernel(geo, device, test_cell_lookup=False)
737
+ side_measures, cell_measures = _launch_test_geometry_kernel(geo, device)
723
738
 
724
739
  assert_np_equal(side_measures.numpy(), np.full(side_measures.shape, 1.0 / (N**2)), tol=1.0e-4)
725
740
  assert_np_equal(cell_measures.numpy(), np.full(cell_measures.shape, 1.0 / (N**3)), tol=1.0e-4)
@@ -844,7 +859,8 @@ def test_deformed_geometry(test, device):
844
859
  test.assertEqual(geo.side_count(), 6 * (N + 1) * N**2 + (N**3) * 4)
845
860
  test.assertEqual(geo.boundary_side_count(), 12 * N * N)
846
861
 
847
- side_measures, cell_measures = _launch_test_geometry_kernel(deformed_geo, device, test_cell_lookup=False)
862
+ deformed_geo.build_bvh()
863
+ side_measures, cell_measures = _launch_test_geometry_kernel(deformed_geo, device)
848
864
 
849
865
  test.assertAlmostEqual(
850
866
  np.sum(cell_measures.numpy()), scale**3, places=4, msg=f"cell_measures = {cell_measures.numpy()}"
@@ -1497,7 +1513,7 @@ def test_point_basis(test, device):
1497
1513
  point_test = fem.make_test(point_space, domain=domain)
1498
1514
 
1499
1515
  # Sample at particle positions
1500
- ones = fem.integrate(linear_form, fields={"u": point_test}, nodal=True)
1516
+ ones = fem.integrate(linear_form, fields={"u": point_test}, assembly="nodal")
1501
1517
  test.assertAlmostEqual(np.sum(ones.numpy()), 1.0, places=5)
1502
1518
 
1503
1519
  # Sampling outside of particle positions
@@ -1613,12 +1629,23 @@ def test_particle_quadratures(test, device):
1613
1629
  assert_np_equal(measures.grad.numpy(), np.full(3, 4.0)) # == 1.0 / cell_area
1614
1630
 
1615
1631
 
1616
- @fem.integrand
1617
- def _value_at_node(s: fem.Sample, f: fem.Field, values: wp.array(dtype=float)):
1632
+ @fem.integrand(kernel_options={"enable_backward": False})
1633
+ def _value_at_node(domain: fem.Domain, s: fem.Sample, f: fem.Field, values: wp.array(dtype=float)):
1634
+ # lookup at node is ambiguous, check that partition_lookup retains sample on current partition
1635
+ s_partition = fem.partition_lookup(domain, domain(s))
1636
+ wp.expect_eq(s.element_index, s_partition.element_index)
1637
+ wp.expect_neq(fem.operator.element_partition_index(domain, s.element_index), fem.NULL_ELEMENT_INDEX)
1638
+
1618
1639
  node_index = fem.operator.node_partition_index(f, s.qp_index)
1619
1640
  return values[node_index]
1620
1641
 
1621
1642
 
1643
+ @fem.integrand(kernel_options={"enable_backward": False})
1644
+ def _test_node_index(s: fem.Sample, u: fem.Field):
1645
+ wp.expect_eq(fem.node_index(u, s), s.qp_index)
1646
+ return 0.0
1647
+
1648
+
1622
1649
  def test_nodal_quadrature(test, device):
1623
1650
  geo = fem.Grid2D(res=wp.vec2i(2))
1624
1651
 
@@ -1635,15 +1662,18 @@ def test_nodal_quadrature(test, device):
1635
1662
 
1636
1663
  # test accessing data associated to a given node
1637
1664
 
1638
- piecewise_constant_space = fem.make_polynomial_space(geo, degree=0)
1639
- geo_partition = fem.LinearGeometryPartition(geo, 3, 4)
1640
- space_partition = fem.make_space_partition(piecewise_constant_space, geo_partition)
1665
+ piecewise_constant_space = fem.make_polynomial_space(geo, degree=1)
1666
+ geo_partition = fem.LinearGeometryPartition(geo, 2, 4)
1667
+ assert geo_partition.cell_count() == 1
1668
+
1669
+ space_partition = fem.make_space_partition(piecewise_constant_space, geo_partition, with_halo=False)
1670
+
1641
1671
  field = fem.make_discrete_field(piecewise_constant_space, space_partition=space_partition)
1642
1672
 
1643
1673
  partition_domain = fem.Cells(geo_partition)
1644
1674
  partition_nodal_quadrature = fem.NodalQuadrature(partition_domain, piecewise_constant_space)
1645
1675
 
1646
- partition_node_values = wp.array([5.0], dtype=float)
1676
+ partition_node_values = wp.full(value=5.0, shape=space_partition.node_count(), dtype=float)
1647
1677
  val = fem.integrate(
1648
1678
  _value_at_node,
1649
1679
  quadrature=partition_nodal_quadrature,
@@ -1652,6 +1682,9 @@ def test_nodal_quadrature(test, device):
1652
1682
  )
1653
1683
  test.assertAlmostEqual(val, 5.0 / geo.cell_count(), places=5)
1654
1684
 
1685
+ u_test = fem.make_test(space)
1686
+ fem.integrate(_test_node_index, assembly="nodal", fields={"u": u_test})
1687
+
1655
1688
 
1656
1689
  @wp.func
1657
1690
  def aniso_bicubic_fn(x: wp.vec2, scale: wp.vec2):
warp/tests/test_func.py CHANGED
@@ -259,7 +259,25 @@ def test_return_annotation_none() -> None:
259
259
  user_func_return_none()
260
260
 
261
261
 
262
- devices = get_test_devices()
262
+ @wp.func
263
+ def divide_by_zero(x: float):
264
+ return x / 0.0
265
+
266
+
267
+ @wp.func
268
+ def normalize_vector(vec_a: wp.vec3):
269
+ return wp.normalize(vec_a)
270
+
271
+
272
+ # This pair is to test the situation where one overload throws an error, but a second one works.
273
+ @wp.func
274
+ def divide_by_zero_overload(x: wp.float32):
275
+ return x / 0
276
+
277
+
278
+ @wp.func
279
+ def divide_by_zero_overload(x: wp.float64):
280
+ return wp.div(x, 0.0)
263
281
 
264
282
 
265
283
  class TestFunc(unittest.TestCase):
@@ -425,6 +443,29 @@ class TestFunc(unittest.TestCase):
425
443
  ):
426
444
  a * b
427
445
 
446
+ def test_cpython_call_user_function_with_error(self):
447
+ # Actually the following also includes a ZeroDivisionError in the message due to exception chaining,
448
+ # but I don't know how to test for that.
449
+ with self.assertRaisesRegex(
450
+ RuntimeError,
451
+ "Error calling function 'divide_by_zero'. No version succeeded. "
452
+ "See above for the error from the last version that was tried.",
453
+ ):
454
+ divide_by_zero(1.0)
455
+
456
+ def test_cpython_call_user_function_with_overloads(self):
457
+ self.assertEqual(divide_by_zero_overload(1.0), math.inf)
458
+
459
+ def test_cpython_call_user_function_with_wrong_argument_types(self):
460
+ with self.assertRaisesRegex(
461
+ RuntimeError,
462
+ "Error calling function 'normalize_vector'. No version succeeded. "
463
+ "See above for the error from the last version that was tried.",
464
+ ):
465
+ normalize_vector(1.0)
466
+
467
+
468
+ devices = get_test_devices()
428
469
 
429
470
  add_kernel_test(TestFunc, kernel=test_overload_func, name="test_overload_func", dim=1, devices=devices)
430
471
  add_function_test(TestFunc, func=test_return_func, name="test_return_func", devices=devices)
warp/tests/test_grad.py CHANGED
@@ -518,7 +518,7 @@ def test_mesh_grad(test, device):
518
518
  pos_np[i, j] += eps
519
519
  fd_grad[i, j] = (f1 - f2) / (2 * eps)
520
520
 
521
- assert np.allclose(ad_grad, fd_grad, atol=1e-3)
521
+ np.testing.assert_allclose(ad_grad, fd_grad, atol=1e-3)
522
522
 
523
523
 
524
524
  @wp.func
warp/tests/test_lerp.py CHANGED
@@ -119,9 +119,7 @@ def test_lerp(test, device):
119
119
  a = wp.array([test_data.a], dtype=data_type, device=device, requires_grad=True)
120
120
  b = wp.array([test_data.b], dtype=data_type, device=device, requires_grad=True)
121
121
  t = wp.array([test_data.t], dtype=float, device=device, requires_grad=True)
122
- out = wp.array(
123
- [0] * wp.types.type_length(data_type), dtype=data_type, device=device, requires_grad=True
124
- )
122
+ out = wp.array([0] * wp.types.type_size(data_type), dtype=data_type, device=device, requires_grad=True)
125
123
 
126
124
  with wp.Tape() as tape:
127
125
  wp.launch(kernel, dim=1, inputs=[a, b, t, out], device=device)