warp-lang 1.9.1__py3-none-win_amd64.whl → 1.10.0rc2__py3-none-win_amd64.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 (346) hide show
  1. warp/__init__.py +301 -287
  2. warp/__init__.pyi +794 -305
  3. warp/_src/__init__.py +14 -0
  4. warp/_src/autograd.py +1075 -0
  5. warp/_src/build.py +618 -0
  6. warp/_src/build_dll.py +640 -0
  7. warp/{builtins.py → _src/builtins.py} +1382 -377
  8. warp/_src/codegen.py +4359 -0
  9. warp/{config.py → _src/config.py} +178 -169
  10. warp/_src/constants.py +57 -0
  11. warp/_src/context.py +8294 -0
  12. warp/_src/dlpack.py +462 -0
  13. warp/_src/fabric.py +355 -0
  14. warp/_src/fem/__init__.py +14 -0
  15. warp/_src/fem/adaptivity.py +508 -0
  16. warp/_src/fem/cache.py +687 -0
  17. warp/_src/fem/dirichlet.py +188 -0
  18. warp/{fem → _src/fem}/domain.py +40 -30
  19. warp/_src/fem/field/__init__.py +131 -0
  20. warp/_src/fem/field/field.py +701 -0
  21. warp/{fem → _src/fem}/field/nodal_field.py +30 -15
  22. warp/{fem → _src/fem}/field/restriction.py +1 -1
  23. warp/{fem → _src/fem}/field/virtual.py +53 -27
  24. warp/_src/fem/geometry/__init__.py +32 -0
  25. warp/{fem → _src/fem}/geometry/adaptive_nanogrid.py +77 -163
  26. warp/_src/fem/geometry/closest_point.py +97 -0
  27. warp/{fem → _src/fem}/geometry/deformed_geometry.py +14 -22
  28. warp/{fem → _src/fem}/geometry/element.py +32 -10
  29. warp/{fem → _src/fem}/geometry/geometry.py +48 -20
  30. warp/{fem → _src/fem}/geometry/grid_2d.py +12 -23
  31. warp/{fem → _src/fem}/geometry/grid_3d.py +12 -23
  32. warp/{fem → _src/fem}/geometry/hexmesh.py +40 -63
  33. warp/{fem → _src/fem}/geometry/nanogrid.py +255 -248
  34. warp/{fem → _src/fem}/geometry/partition.py +121 -63
  35. warp/{fem → _src/fem}/geometry/quadmesh.py +26 -45
  36. warp/{fem → _src/fem}/geometry/tetmesh.py +40 -63
  37. warp/{fem → _src/fem}/geometry/trimesh.py +26 -45
  38. warp/{fem → _src/fem}/integrate.py +164 -158
  39. warp/_src/fem/linalg.py +383 -0
  40. warp/_src/fem/operator.py +396 -0
  41. warp/_src/fem/polynomial.py +229 -0
  42. warp/{fem → _src/fem}/quadrature/pic_quadrature.py +15 -20
  43. warp/{fem → _src/fem}/quadrature/quadrature.py +95 -47
  44. warp/_src/fem/space/__init__.py +248 -0
  45. warp/{fem → _src/fem}/space/basis_function_space.py +20 -11
  46. warp/_src/fem/space/basis_space.py +679 -0
  47. warp/{fem → _src/fem}/space/dof_mapper.py +3 -3
  48. warp/{fem → _src/fem}/space/function_space.py +14 -13
  49. warp/{fem → _src/fem}/space/grid_2d_function_space.py +4 -7
  50. warp/{fem → _src/fem}/space/grid_3d_function_space.py +4 -4
  51. warp/{fem → _src/fem}/space/hexmesh_function_space.py +4 -10
  52. warp/{fem → _src/fem}/space/nanogrid_function_space.py +3 -9
  53. warp/{fem → _src/fem}/space/partition.py +117 -60
  54. warp/{fem → _src/fem}/space/quadmesh_function_space.py +4 -10
  55. warp/{fem → _src/fem}/space/restriction.py +66 -33
  56. warp/_src/fem/space/shape/__init__.py +152 -0
  57. warp/{fem → _src/fem}/space/shape/cube_shape_function.py +9 -9
  58. warp/{fem → _src/fem}/space/shape/shape_function.py +8 -9
  59. warp/{fem → _src/fem}/space/shape/square_shape_function.py +6 -6
  60. warp/{fem → _src/fem}/space/shape/tet_shape_function.py +3 -3
  61. warp/{fem → _src/fem}/space/shape/triangle_shape_function.py +3 -3
  62. warp/{fem → _src/fem}/space/tetmesh_function_space.py +3 -9
  63. warp/_src/fem/space/topology.py +459 -0
  64. warp/{fem → _src/fem}/space/trimesh_function_space.py +3 -9
  65. warp/_src/fem/types.py +112 -0
  66. warp/_src/fem/utils.py +486 -0
  67. warp/_src/jax.py +186 -0
  68. warp/_src/jax_experimental/__init__.py +14 -0
  69. warp/_src/jax_experimental/custom_call.py +387 -0
  70. warp/_src/jax_experimental/ffi.py +1284 -0
  71. warp/_src/jax_experimental/xla_ffi.py +656 -0
  72. warp/_src/marching_cubes.py +708 -0
  73. warp/_src/math.py +414 -0
  74. warp/_src/optim/__init__.py +14 -0
  75. warp/_src/optim/adam.py +163 -0
  76. warp/_src/optim/linear.py +1606 -0
  77. warp/_src/optim/sgd.py +112 -0
  78. warp/_src/paddle.py +406 -0
  79. warp/_src/render/__init__.py +14 -0
  80. warp/_src/render/imgui_manager.py +289 -0
  81. warp/_src/render/render_opengl.py +3636 -0
  82. warp/_src/render/render_usd.py +937 -0
  83. warp/_src/render/utils.py +160 -0
  84. warp/_src/sparse.py +2716 -0
  85. warp/_src/tape.py +1206 -0
  86. warp/{thirdparty → _src/thirdparty}/unittest_parallel.py +9 -2
  87. warp/_src/torch.py +391 -0
  88. warp/_src/types.py +5870 -0
  89. warp/_src/utils.py +1693 -0
  90. warp/autograd.py +12 -1054
  91. warp/bin/warp-clang.dll +0 -0
  92. warp/bin/warp.dll +0 -0
  93. warp/build.py +8 -588
  94. warp/build_dll.py +6 -721
  95. warp/codegen.py +6 -4251
  96. warp/constants.py +6 -39
  97. warp/context.py +12 -8062
  98. warp/dlpack.py +6 -444
  99. warp/examples/distributed/example_jacobi_mpi.py +4 -5
  100. warp/examples/fem/example_adaptive_grid.py +1 -1
  101. warp/examples/fem/example_apic_fluid.py +1 -1
  102. warp/examples/fem/example_burgers.py +8 -8
  103. warp/examples/fem/example_diffusion.py +1 -1
  104. warp/examples/fem/example_distortion_energy.py +1 -1
  105. warp/examples/fem/example_mixed_elasticity.py +2 -2
  106. warp/examples/fem/example_navier_stokes.py +1 -1
  107. warp/examples/fem/example_nonconforming_contact.py +7 -7
  108. warp/examples/fem/example_stokes.py +1 -1
  109. warp/examples/fem/example_stokes_transfer.py +1 -1
  110. warp/examples/fem/utils.py +2 -2
  111. warp/examples/interop/example_jax_callable.py +1 -1
  112. warp/examples/interop/example_jax_ffi_callback.py +1 -1
  113. warp/examples/interop/example_jax_kernel.py +1 -1
  114. warp/examples/tile/example_tile_mcgp.py +191 -0
  115. warp/fabric.py +6 -337
  116. warp/fem/__init__.py +159 -97
  117. warp/fem/adaptivity.py +7 -489
  118. warp/fem/cache.py +9 -648
  119. warp/fem/dirichlet.py +6 -184
  120. warp/fem/field/__init__.py +8 -109
  121. warp/fem/field/field.py +7 -652
  122. warp/fem/geometry/__init__.py +7 -18
  123. warp/fem/geometry/closest_point.py +11 -77
  124. warp/fem/linalg.py +18 -366
  125. warp/fem/operator.py +11 -369
  126. warp/fem/polynomial.py +9 -209
  127. warp/fem/space/__init__.py +5 -211
  128. warp/fem/space/basis_space.py +6 -662
  129. warp/fem/space/shape/__init__.py +41 -118
  130. warp/fem/space/topology.py +6 -437
  131. warp/fem/types.py +6 -81
  132. warp/fem/utils.py +11 -444
  133. warp/jax.py +8 -165
  134. warp/jax_experimental/__init__.py +14 -1
  135. warp/jax_experimental/custom_call.py +8 -365
  136. warp/jax_experimental/ffi.py +17 -873
  137. warp/jax_experimental/xla_ffi.py +5 -605
  138. warp/marching_cubes.py +5 -689
  139. warp/math.py +16 -393
  140. warp/native/array.h +385 -37
  141. warp/native/builtin.h +314 -37
  142. warp/native/bvh.cpp +43 -9
  143. warp/native/bvh.cu +62 -27
  144. warp/native/bvh.h +310 -309
  145. warp/native/clang/clang.cpp +102 -97
  146. warp/native/coloring.cpp +0 -1
  147. warp/native/crt.h +208 -0
  148. warp/native/exports.h +156 -0
  149. warp/native/hashgrid.cu +2 -0
  150. warp/native/intersect.h +24 -1
  151. warp/native/intersect_tri.h +44 -35
  152. warp/native/mat.h +1456 -276
  153. warp/native/mesh.cpp +4 -4
  154. warp/native/mesh.cu +4 -2
  155. warp/native/mesh.h +176 -61
  156. warp/native/quat.h +0 -52
  157. warp/native/scan.cu +2 -0
  158. warp/native/sparse.cu +7 -3
  159. warp/native/spatial.h +12 -0
  160. warp/native/tile.h +681 -89
  161. warp/native/tile_radix_sort.h +1 -1
  162. warp/native/tile_reduce.h +394 -46
  163. warp/native/tile_scan.h +4 -4
  164. warp/native/vec.h +469 -0
  165. warp/native/version.h +23 -0
  166. warp/native/volume.cpp +1 -1
  167. warp/native/volume.cu +1 -0
  168. warp/native/volume.h +1 -1
  169. warp/native/volume_builder.cu +2 -0
  170. warp/native/warp.cpp +57 -29
  171. warp/native/warp.cu +253 -171
  172. warp/native/warp.h +11 -8
  173. warp/optim/__init__.py +6 -3
  174. warp/optim/adam.py +6 -145
  175. warp/optim/linear.py +14 -1585
  176. warp/optim/sgd.py +6 -94
  177. warp/paddle.py +6 -388
  178. warp/render/__init__.py +8 -4
  179. warp/render/imgui_manager.py +7 -267
  180. warp/render/render_opengl.py +6 -3618
  181. warp/render/render_usd.py +6 -919
  182. warp/render/utils.py +6 -142
  183. warp/sparse.py +37 -2563
  184. warp/tape.py +6 -1188
  185. warp/tests/__main__.py +1 -1
  186. warp/tests/cuda/test_async.py +4 -4
  187. warp/tests/cuda/test_conditional_captures.py +1 -1
  188. warp/tests/cuda/test_multigpu.py +1 -1
  189. warp/tests/cuda/test_streams.py +58 -1
  190. warp/tests/geometry/test_bvh.py +157 -22
  191. warp/tests/geometry/test_marching_cubes.py +0 -1
  192. warp/tests/geometry/test_mesh.py +5 -3
  193. warp/tests/geometry/test_mesh_query_aabb.py +5 -12
  194. warp/tests/geometry/test_mesh_query_point.py +5 -2
  195. warp/tests/geometry/test_mesh_query_ray.py +15 -3
  196. warp/tests/geometry/test_volume_write.py +5 -5
  197. warp/tests/interop/test_dlpack.py +14 -14
  198. warp/tests/interop/test_jax.py +772 -49
  199. warp/tests/interop/test_paddle.py +1 -1
  200. warp/tests/test_adam.py +0 -1
  201. warp/tests/test_arithmetic.py +9 -9
  202. warp/tests/test_array.py +527 -100
  203. warp/tests/test_array_reduce.py +3 -3
  204. warp/tests/test_atomic.py +12 -8
  205. warp/tests/test_atomic_bitwise.py +209 -0
  206. warp/tests/test_atomic_cas.py +4 -4
  207. warp/tests/test_bool.py +2 -2
  208. warp/tests/test_builtins_resolution.py +5 -571
  209. warp/tests/test_codegen.py +33 -14
  210. warp/tests/test_conditional.py +1 -1
  211. warp/tests/test_context.py +6 -6
  212. warp/tests/test_copy.py +242 -161
  213. warp/tests/test_ctypes.py +3 -3
  214. warp/tests/test_devices.py +24 -2
  215. warp/tests/test_examples.py +16 -84
  216. warp/tests/test_fabricarray.py +35 -35
  217. warp/tests/test_fast_math.py +0 -2
  218. warp/tests/test_fem.py +56 -10
  219. warp/tests/test_fixedarray.py +3 -3
  220. warp/tests/test_func.py +8 -5
  221. warp/tests/test_generics.py +1 -1
  222. warp/tests/test_indexedarray.py +24 -24
  223. warp/tests/test_intersect.py +39 -9
  224. warp/tests/test_large.py +1 -1
  225. warp/tests/test_lerp.py +3 -1
  226. warp/tests/test_linear_solvers.py +1 -1
  227. warp/tests/test_map.py +35 -4
  228. warp/tests/test_mat.py +52 -62
  229. warp/tests/test_mat_constructors.py +4 -5
  230. warp/tests/test_mat_lite.py +1 -1
  231. warp/tests/test_mat_scalar_ops.py +121 -121
  232. warp/tests/test_math.py +34 -0
  233. warp/tests/test_module_aot.py +4 -4
  234. warp/tests/test_modules_lite.py +28 -2
  235. warp/tests/test_print.py +11 -11
  236. warp/tests/test_quat.py +93 -58
  237. warp/tests/test_runlength_encode.py +1 -1
  238. warp/tests/test_scalar_ops.py +38 -10
  239. warp/tests/test_smoothstep.py +1 -1
  240. warp/tests/test_sparse.py +126 -15
  241. warp/tests/test_spatial.py +105 -87
  242. warp/tests/test_special_values.py +6 -6
  243. warp/tests/test_static.py +7 -7
  244. warp/tests/test_struct.py +13 -2
  245. warp/tests/test_triangle_closest_point.py +48 -1
  246. warp/tests/test_types.py +27 -15
  247. warp/tests/test_utils.py +52 -52
  248. warp/tests/test_vec.py +29 -29
  249. warp/tests/test_vec_constructors.py +5 -5
  250. warp/tests/test_vec_scalar_ops.py +97 -97
  251. warp/tests/test_version.py +75 -0
  252. warp/tests/tile/test_tile.py +178 -0
  253. warp/tests/tile/test_tile_atomic_bitwise.py +403 -0
  254. warp/tests/tile/test_tile_cholesky.py +7 -4
  255. warp/tests/tile/test_tile_load.py +26 -2
  256. warp/tests/tile/test_tile_mathdx.py +3 -3
  257. warp/tests/tile/test_tile_matmul.py +1 -1
  258. warp/tests/tile/test_tile_mlp.py +2 -4
  259. warp/tests/tile/test_tile_reduce.py +214 -13
  260. warp/tests/unittest_suites.py +6 -14
  261. warp/tests/unittest_utils.py +10 -9
  262. warp/tests/walkthrough_debug.py +3 -1
  263. warp/torch.py +6 -373
  264. warp/types.py +29 -5764
  265. warp/utils.py +10 -1659
  266. {warp_lang-1.9.1.dist-info → warp_lang-1.10.0rc2.dist-info}/METADATA +46 -99
  267. warp_lang-1.10.0rc2.dist-info/RECORD +468 -0
  268. warp_lang-1.10.0rc2.dist-info/licenses/licenses/Gaia-LICENSE.txt +6 -0
  269. warp_lang-1.10.0rc2.dist-info/licenses/licenses/appdirs-LICENSE.txt +22 -0
  270. warp_lang-1.10.0rc2.dist-info/licenses/licenses/asset_pixel_jpg-LICENSE.txt +3 -0
  271. warp_lang-1.10.0rc2.dist-info/licenses/licenses/cuda-LICENSE.txt +1582 -0
  272. warp_lang-1.10.0rc2.dist-info/licenses/licenses/dlpack-LICENSE.txt +201 -0
  273. warp_lang-1.10.0rc2.dist-info/licenses/licenses/fp16-LICENSE.txt +28 -0
  274. warp_lang-1.10.0rc2.dist-info/licenses/licenses/libmathdx-LICENSE.txt +220 -0
  275. warp_lang-1.10.0rc2.dist-info/licenses/licenses/llvm-LICENSE.txt +279 -0
  276. warp_lang-1.10.0rc2.dist-info/licenses/licenses/moller-LICENSE.txt +16 -0
  277. warp_lang-1.10.0rc2.dist-info/licenses/licenses/nanovdb-LICENSE.txt +2 -0
  278. warp_lang-1.10.0rc2.dist-info/licenses/licenses/nvrtc-LICENSE.txt +1592 -0
  279. warp_lang-1.10.0rc2.dist-info/licenses/licenses/svd-LICENSE.txt +23 -0
  280. warp_lang-1.10.0rc2.dist-info/licenses/licenses/unittest_parallel-LICENSE.txt +21 -0
  281. warp_lang-1.10.0rc2.dist-info/licenses/licenses/usd-LICENSE.txt +213 -0
  282. warp_lang-1.10.0rc2.dist-info/licenses/licenses/windingnumber-LICENSE.txt +21 -0
  283. warp/examples/assets/cartpole.urdf +0 -110
  284. warp/examples/assets/crazyflie.usd +0 -0
  285. warp/examples/assets/nv_ant.xml +0 -92
  286. warp/examples/assets/nv_humanoid.xml +0 -183
  287. warp/examples/assets/quadruped.urdf +0 -268
  288. warp/examples/optim/example_bounce.py +0 -266
  289. warp/examples/optim/example_cloth_throw.py +0 -228
  290. warp/examples/optim/example_drone.py +0 -870
  291. warp/examples/optim/example_inverse_kinematics.py +0 -182
  292. warp/examples/optim/example_inverse_kinematics_torch.py +0 -191
  293. warp/examples/optim/example_softbody_properties.py +0 -400
  294. warp/examples/optim/example_spring_cage.py +0 -245
  295. warp/examples/optim/example_trajectory.py +0 -227
  296. warp/examples/sim/example_cartpole.py +0 -143
  297. warp/examples/sim/example_cloth.py +0 -225
  298. warp/examples/sim/example_cloth_self_contact.py +0 -316
  299. warp/examples/sim/example_granular.py +0 -130
  300. warp/examples/sim/example_granular_collision_sdf.py +0 -202
  301. warp/examples/sim/example_jacobian_ik.py +0 -244
  302. warp/examples/sim/example_particle_chain.py +0 -124
  303. warp/examples/sim/example_quadruped.py +0 -203
  304. warp/examples/sim/example_rigid_chain.py +0 -203
  305. warp/examples/sim/example_rigid_contact.py +0 -195
  306. warp/examples/sim/example_rigid_force.py +0 -133
  307. warp/examples/sim/example_rigid_gyroscopic.py +0 -115
  308. warp/examples/sim/example_rigid_soft_contact.py +0 -140
  309. warp/examples/sim/example_soft_body.py +0 -196
  310. warp/examples/tile/example_tile_walker.py +0 -327
  311. warp/sim/__init__.py +0 -74
  312. warp/sim/articulation.py +0 -793
  313. warp/sim/collide.py +0 -2570
  314. warp/sim/graph_coloring.py +0 -307
  315. warp/sim/import_mjcf.py +0 -791
  316. warp/sim/import_snu.py +0 -227
  317. warp/sim/import_urdf.py +0 -579
  318. warp/sim/import_usd.py +0 -898
  319. warp/sim/inertia.py +0 -357
  320. warp/sim/integrator.py +0 -245
  321. warp/sim/integrator_euler.py +0 -2000
  322. warp/sim/integrator_featherstone.py +0 -2101
  323. warp/sim/integrator_vbd.py +0 -2487
  324. warp/sim/integrator_xpbd.py +0 -3295
  325. warp/sim/model.py +0 -4821
  326. warp/sim/particles.py +0 -121
  327. warp/sim/render.py +0 -431
  328. warp/sim/utils.py +0 -431
  329. warp/tests/sim/disabled_kinematics.py +0 -244
  330. warp/tests/sim/test_cloth.py +0 -863
  331. warp/tests/sim/test_collision.py +0 -743
  332. warp/tests/sim/test_coloring.py +0 -347
  333. warp/tests/sim/test_inertia.py +0 -161
  334. warp/tests/sim/test_model.py +0 -226
  335. warp/tests/sim/test_sim_grad.py +0 -287
  336. warp/tests/sim/test_sim_grad_bounce_linear.py +0 -212
  337. warp/tests/sim/test_sim_kinematics.py +0 -98
  338. warp/thirdparty/__init__.py +0 -0
  339. warp_lang-1.9.1.dist-info/RECORD +0 -456
  340. /warp/{fem → _src/fem}/quadrature/__init__.py +0 -0
  341. /warp/{tests/sim → _src/thirdparty}/__init__.py +0 -0
  342. /warp/{thirdparty → _src/thirdparty}/appdirs.py +0 -0
  343. /warp/{thirdparty → _src/thirdparty}/dlpack.py +0 -0
  344. {warp_lang-1.9.1.dist-info → warp_lang-1.10.0rc2.dist-info}/WHEEL +0 -0
  345. {warp_lang-1.9.1.dist-info → warp_lang-1.10.0rc2.dist-info}/licenses/LICENSE.md +0 -0
  346. {warp_lang-1.9.1.dist-info → warp_lang-1.10.0rc2.dist-info}/top_level.txt +0 -0
warp/marching_cubes.py CHANGED
@@ -13,696 +13,12 @@
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
16
+ # TODO: Remove after cleaning up the public API.
17
17
 
18
- import numpy as np
18
+ from warp._src import marching_cubes as _marching_cubes
19
19
 
20
- import warp as wp
21
20
 
21
+ def __getattr__(name):
22
+ from warp._src.utils import get_deprecated_api
22
23
 
23
- def marching_cubes_extract_vertices(
24
- field: wp.array3d(dtype=wp.float32),
25
- threshold: float,
26
- domain_bounds_lower_corner: wp.vec3,
27
- grid_pos_delta: wp.vec3,
28
- ):
29
- """Invoke kernels to extract vertices and indices to uniquely identify them."""
30
- device = field.device
31
- nnode_x, nnode_y, nnode_z = field.shape[0], field.shape[1], field.shape[2]
32
-
33
- ### First pass: count the vertices each thread will generate
34
- thread_output_count = wp.zeros(shape=(nnode_x * nnode_y * nnode_z * 3), dtype=wp.int32, device=device)
35
- wp.launch(
36
- extract_vertices_kernel,
37
- dim=(nnode_x, nnode_y, nnode_z, 3),
38
- inputs=[
39
- field,
40
- threshold,
41
- domain_bounds_lower_corner,
42
- grid_pos_delta,
43
- None,
44
- True, # count only == True : just count the vertices
45
- ],
46
- outputs=[thread_output_count, None, None, None],
47
- device=device,
48
- )
49
-
50
- ### Evaluate a cumulative sum, to compute the output index for each generated vertex
51
- vertex_result_ind = wp.zeros(shape=(nnode_x * nnode_y * nnode_z * 3), dtype=wp.int32, device=device)
52
- wp.utils.array_scan(thread_output_count, vertex_result_ind, inclusive=True)
53
-
54
- # (synchronization point!)
55
- N_vert = int(vertex_result_ind[-1:].numpy()[0])
56
-
57
- # Allocate output arrays
58
- # edge_generated_vert_ind: corresponds to the the 3 positive-facing edges emanating from each node.
59
- # The last boundary entries of this array will be unused, but we can't make it any smaller.
60
- edge_generated_vert_ind = wp.zeros(shape=(nnode_x, nnode_y, nnode_z, 3), dtype=wp.int32, device=device)
61
- verts_pos_out = wp.empty(
62
- shape=N_vert, dtype=wp.vec3, device=device, requires_grad=field.requires_grad
63
- ) # TODO is this the right way to decide setting requires_grad?
64
- verts_is_boundary_out = wp.empty(shape=N_vert, dtype=wp.bool, device=device)
65
-
66
- ### Second pass: actually generate the vertices and write to the output arrays
67
- wp.launch(
68
- extract_vertices_kernel,
69
- dim=(nnode_x, nnode_y, nnode_z, 3),
70
- inputs=[
71
- field,
72
- threshold,
73
- domain_bounds_lower_corner,
74
- grid_pos_delta,
75
- vertex_result_ind,
76
- False, # count only == False : actually write out the vertices
77
- ],
78
- outputs=[
79
- None,
80
- verts_pos_out,
81
- verts_is_boundary_out,
82
- edge_generated_vert_ind,
83
- ],
84
- device=device,
85
- )
86
-
87
- return (verts_pos_out, verts_is_boundary_out, edge_generated_vert_ind)
88
-
89
-
90
- @wp.kernel
91
- def extract_vertices_kernel(
92
- values: wp.array3d(dtype=wp.float32),
93
- threshold: wp.float32,
94
- domain_bounds_lower_corner: wp.vec3,
95
- grid_pos_delta: wp.vec3,
96
- vertex_result_ind: wp.array(dtype=wp.int32),
97
- count_only: bool,
98
- thread_output_count: wp.array(dtype=wp.int32),
99
- verts_pos_out: wp.array(dtype=wp.vec3),
100
- verts_is_boundary_out: wp.array(dtype=wp.bool),
101
- edge_generated_vert_ind: wp.array(dtype=wp.int32, ndim=4),
102
- ):
103
- """Kernel for vertex extraction.
104
-
105
- This kernel runs in two different "modes", which share much of their logic.
106
- In a first pass when count_only==True, we just count the number of vertices that will be
107
- generated. We then cumulative-sum those counts to generate output indices. Then, in a
108
- second pass when count_only==False, we actually generate the vertices and write them to
109
- the appropriate output location.
110
- """
111
- ti, tj, tk, t_side = wp.tid()
112
- nnode_x, nnode_y, nnode_z = values.shape[0], values.shape[1], values.shape[2]
113
-
114
- # Assemble indices
115
- i_opp = ti + wp.where(t_side == 0, 1, 0)
116
- j_opp = tj + wp.where(t_side == 1, 1, 0)
117
- k_opp = tk + wp.where(t_side == 2, 1, 0)
118
- out_ind = -1
119
-
120
- # Out of bounds edges off the sides of the grid
121
- if i_opp >= nnode_x or j_opp >= nnode_y or k_opp >= nnode_z:
122
- if not count_only:
123
- edge_generated_vert_ind[ti, tj, tk, t_side] = out_ind
124
- return
125
-
126
- # Fetch values from the field
127
- this_val = values[ti, tj, tk]
128
- opp_val = values[i_opp, j_opp, k_opp]
129
-
130
- ind = ti * nnode_y * nnode_z * 3 + tj * nnode_z * 3 + tk * 3 + t_side
131
-
132
- # Check if we generate a vertex
133
- if (this_val >= threshold and opp_val < threshold) or (this_val < threshold and opp_val >= threshold):
134
- if count_only:
135
- thread_output_count[ind] = 1
136
- else:
137
- out_ind = vertex_result_ind[ind] - 1
138
-
139
- # generated vertex along the edge
140
- t_interp = (threshold - this_val) / (opp_val - this_val)
141
- t_interp = wp.clamp(t_interp, 0.0, 1.0)
142
- this_pos = domain_bounds_lower_corner + wp.vec3(
143
- wp.float32(ti) * grid_pos_delta.x,
144
- wp.float32(tj) * grid_pos_delta.y,
145
- wp.float32(tk) * grid_pos_delta.z,
146
- )
147
- opp_pos = domain_bounds_lower_corner + wp.vec3(
148
- wp.float32(i_opp) * grid_pos_delta.x,
149
- wp.float32(j_opp) * grid_pos_delta.y,
150
- wp.float32(k_opp) * grid_pos_delta.z,
151
- )
152
- interp_pos = wp.lerp(this_pos, opp_pos, t_interp)
153
- this_boundary = (
154
- ti == 0 or (ti + 1) == nnode_x or tj == 0 or (tj + 1) == nnode_y or tk == 0 or (tk + 1) == nnode_z
155
- )
156
- opp_boundary = (
157
- i_opp == 0
158
- or (i_opp + 1) == nnode_x
159
- or j_opp == 0
160
- or (j_opp + 1) == nnode_y
161
- or k_opp == 0
162
- or (k_opp + 1) == nnode_z
163
- )
164
- vert_is_boundary = this_boundary and opp_boundary
165
-
166
- # store output data
167
- verts_pos_out[out_ind] = interp_pos
168
- verts_is_boundary_out[out_ind] = vert_is_boundary
169
-
170
- if not count_only:
171
- edge_generated_vert_ind[ti, tj, tk, t_side] = out_ind
172
-
173
-
174
- def marching_cubes_extract_faces(
175
- values: wp.array3d(dtype=wp.float32),
176
- threshold: wp.float32,
177
- edge_generated_vert_ind: wp.array(dtype=wp.int32, ndim=4),
178
- ):
179
- """Invoke kernels to extract faces and index the appropriate vertices."""
180
- device = values.device
181
- nnode_x, nnode_y, nnode_z = values.shape[0], values.shape[1], values.shape[2]
182
- ncell_x, ncell_y, ncell_z = nnode_x - 1, nnode_y - 1, nnode_z - 1
183
-
184
- # First pass: count the number of faces each thread will generate
185
- thread_output_count = wp.zeros(shape=(ncell_x * ncell_y * ncell_z), dtype=wp.int32, device=device)
186
- wp.launch(
187
- extract_faces_kernel,
188
- dim=(ncell_x, ncell_y, ncell_z),
189
- inputs=[
190
- values,
191
- threshold,
192
- edge_generated_vert_ind,
193
- None,
194
- _get_mc_case_to_tri_range_table(device),
195
- _get_mc_tri_local_inds_table(device),
196
- _get_mc_edge_offset_table(device),
197
- True,
198
- ],
199
- outputs=[
200
- thread_output_count,
201
- None,
202
- ],
203
- device=device,
204
- )
205
-
206
- ### Evaluate a cumulative sum, to compute the output index for each generated face
207
- face_result_ind = wp.zeros(shape=(ncell_x * ncell_y * ncell_z), dtype=wp.int32, device=device)
208
- wp.utils.array_scan(thread_output_count, face_result_ind, inclusive=True)
209
-
210
- # (synchronization point!)
211
- N_faces = int(face_result_ind[-1:].numpy()[0])
212
-
213
- # Allocate output array
214
- faces_out = wp.empty(shape=3 * N_faces, dtype=wp.int32, device=device)
215
-
216
- ### Second pass: actually generate the faces and write to the output array
217
- wp.launch(
218
- extract_faces_kernel,
219
- dim=(ncell_x, ncell_y, ncell_z),
220
- inputs=[
221
- values,
222
- threshold,
223
- edge_generated_vert_ind,
224
- face_result_ind,
225
- _get_mc_case_to_tri_range_table(device),
226
- _get_mc_tri_local_inds_table(device),
227
- _get_mc_edge_offset_table(device),
228
- False,
229
- ],
230
- outputs=[
231
- None,
232
- faces_out,
233
- ],
234
- device=device,
235
- )
236
-
237
- return faces_out
238
-
239
-
240
- # NOTE: differentiating this kernel does nothing, since all of its outputs are discrete, but
241
- # Warp issues warnings if we set enable_backward=False
242
- @wp.kernel
243
- def extract_faces_kernel(
244
- values: wp.array3d(dtype=wp.float32),
245
- threshold: wp.float32,
246
- edge_genererated_vert_ind: wp.array(dtype=wp.int32, ndim=4),
247
- face_result_ind: wp.array(dtype=wp.int32),
248
- mc_case_to_tri_range_table: wp.array(dtype=wp.int32),
249
- mc_tri_local_inds_table: wp.array(dtype=wp.int32),
250
- mc_edge_offset_table: wp.array(dtype=wp.int32, ndim=2),
251
- count_only: bool,
252
- thread_output_count: wp.array(dtype=wp.int32),
253
- faces_out: wp.array(dtype=wp.int32),
254
- ):
255
- """
256
- Kernel for face extraction
257
-
258
- This kernel runs in two different "modes", which share much of their logic.
259
- In a first pass when count_only==True, we just count the number of faces that will be
260
- generated. We then cumulative-sum those counts to generate output indices. Then, in a
261
- second pass when count_only==False, we actually generate the faces and write them to
262
- the appropriate output location.
263
- """
264
- ti, tj, tk = wp.tid()
265
- nnode_x, nnode_y, nnode_z = values.shape[0], values.shape[1], values.shape[2]
266
- _ncell_x, ncell_y, ncell_z = nnode_x - 1, nnode_y - 1, nnode_z - 1
267
- ind = ti * ncell_y * ncell_z + tj * ncell_z + tk
268
-
269
- # Check which case we're in
270
- # NOTE: this loop should get unrolled (confirmed it does in Warp 1.4.1)
271
- case_code = 0
272
- for i_c in range(8):
273
- indX = ti + wp.static(mc_cube_corner_offsets[i_c][0])
274
- indY = tj + wp.static(mc_cube_corner_offsets[i_c][1])
275
- indZ = tk + wp.static(mc_cube_corner_offsets[i_c][2])
276
- val = values[indX, indY, indZ]
277
- if val >= threshold:
278
- case_code += wp.static(2**i_c)
279
-
280
- # Gather the range of triangles we will emit
281
- tri_range_start = mc_case_to_tri_range_table[case_code]
282
- tri_range_end = mc_case_to_tri_range_table[case_code + 1]
283
- N_tri = wp.int32(tri_range_end - tri_range_start) // 3
284
-
285
- # If we are just counting, record the number of triangles and move on
286
- if count_only:
287
- thread_output_count[ind] = N_tri
288
- return
289
-
290
- if N_tri == 0:
291
- return
292
-
293
- # Find the output index for this thread's faces
294
- # The indexing logic is slightly awkward here because we use an inclusive sum,
295
- # so we need to check the previous thread's output index, with a special case for
296
- # the first thread. Doing it this way makes it simpler to fetch N_faces in the host
297
- # function.
298
- prev_thread_id = ti * ncell_y * ncell_z + tj * ncell_z + tk - 1
299
- if prev_thread_id < 0:
300
- out_ind = 0
301
- else:
302
- out_ind = face_result_ind[prev_thread_id]
303
-
304
- # Emit triangles
305
- for i_tri in range(N_tri):
306
- for s in range(3):
307
- local_ind = mc_tri_local_inds_table[tri_range_start + 3 * i_tri + s]
308
-
309
- global_ind = edge_genererated_vert_ind[
310
- ti + mc_edge_offset_table[local_ind][0],
311
- tj + mc_edge_offset_table[local_ind][1],
312
- tk + mc_edge_offset_table[local_ind][2],
313
- mc_edge_offset_table[local_ind][3],
314
- ]
315
-
316
- faces_out[3 * (out_ind + i_tri) + s] = global_ind
317
-
318
- return
319
-
320
-
321
- ### Marching Cubes tables
322
-
323
- # cached warp device arrays for the tables below
324
- mc_case_to_tri_range_wpcache = {}
325
- mc_tri_local_inds_wpcache = {}
326
- mc_edge_offset_wpcache = {}
327
-
328
-
329
- def _get_mc_case_to_tri_range_table(device) -> wp.array:
330
- """Lazily loads and caches the MC tri range table on the target device."""
331
- device = str(device)
332
- if device not in mc_case_to_tri_range_wpcache:
333
- mc_case_to_tri_range_wpcache[device] = wp.from_numpy(mc_case_to_tri_range_np, dtype=wp.int32, device=device)
334
-
335
- return mc_case_to_tri_range_wpcache[device]
336
-
337
-
338
- def _get_mc_tri_local_inds_table(device) -> wp.array:
339
- """Lazily loads and caches the MC tri local inds table on the target device."""
340
- device = str(device)
341
- if device not in mc_tri_local_inds_wpcache:
342
- mc_tri_local_inds_wpcache[device] = wp.from_numpy(mc_tri_local_inds, dtype=wp.int32, device=device)
343
-
344
- return mc_tri_local_inds_wpcache[device]
345
-
346
-
347
- def _get_mc_edge_offset_table(device) -> wp.array:
348
- """Lazily loads and caches the MC edge offset table on the target device."""
349
- device = str(device)
350
- if device not in mc_edge_offset_wpcache:
351
- mc_edge_offset_wpcache[device] = wp.from_numpy(mc_edge_offset_np, dtype=wp.int32, device=device)
352
-
353
- return mc_edge_offset_wpcache[device]
354
-
355
-
356
- # fmt: off
357
- mc_case_to_tri_range_np = np.array( [
358
- 0, 0, 3, 6, 12, 15, 21, 27, 36, 39, 45, 51, 60, 66, 75, 84, 90, 93, 99, 105, 114,
359
- 120, 129, 138, 150, 156, 165, 174, 186, 195, 207, 219, 228, 231, 237, 243, 252,
360
- 258, 267, 276, 288, 294, 303, 312, 324, 333, 345, 357, 366, 372, 381, 390, 396,
361
- 405, 417, 429, 438, 447, 459, 471, 480, 492, 507, 522, 528, 531, 537, 543, 552,
362
- 558, 567, 576, 588, 594, 603, 612, 624, 633, 645, 657, 666, 672, 681, 690, 702,
363
- 711, 723, 735, 750, 759, 771, 783, 798, 810, 825, 840, 852, 858, 867, 876, 888,
364
- 897, 909, 915, 924, 933, 945, 957, 972, 984, 999, 1008, 1014, 1023, 1035, 1047,
365
- 1056, 1068, 1083, 1092, 1098, 1110, 1125, 1140, 1152, 1167, 1173, 1185, 1188, 1191,
366
- 1197, 1203, 1212, 1218, 1227, 1236, 1248, 1254, 1263, 1272, 1284, 1293, 1305, 1317,
367
- 1326, 1332, 1341, 1350, 1362, 1371, 1383, 1395, 1410, 1419, 1425, 1437, 1446, 1458,
368
- 1467, 1482, 1488, 1494, 1503, 1512, 1524, 1533, 1545, 1557, 1572, 1581, 1593, 1605,
369
- 1620, 1632, 1647, 1662, 1674, 1683, 1695, 1707, 1716, 1728, 1743, 1758, 1770, 1782,
370
- 1791, 1806, 1812, 1827, 1839, 1845, 1848, 1854, 1863, 1872, 1884, 1893, 1905, 1917,
371
- 1932, 1941, 1953, 1965, 1980, 1986, 1995, 2004, 2010, 2019, 2031, 2043, 2058, 2070,
372
- 2085, 2100, 2106, 2118, 2127, 2142, 2154, 2163, 2169, 2181, 2184, 2193, 2205, 2217,
373
- 2232, 2244, 2259, 2268, 2280, 2292, 2307, 2322, 2328, 2337, 2349, 2355, 2358, 2364,
374
- 2373, 2382, 2388, 2397, 2409, 2415, 2418, 2427, 2433, 2445, 2448, 2454, 2457, 2460,
375
- 2460
376
- ])
377
-
378
- mc_tri_local_inds = np.array([
379
- 0, 8, 3, 0, 1, 9, 1, 8, 3, 9, 8, 1, 1, 2, 10, 0, 8, 3, 1, 2, 10, 9, 2, 10, 0, 2, 9, 2, 8, 3, 2,
380
- 10, 8, 10, 9, 8, 3, 11, 2, 0, 11, 2, 8, 11, 0, 1, 9, 0, 2, 3, 11, 1, 11, 2, 1, 9, 11, 9, 8, 11, 3,
381
- 10, 1, 11, 10, 3, 0, 10, 1, 0, 8, 10, 8, 11, 10, 3, 9, 0, 3, 11, 9, 11, 10, 9, 9, 8, 10, 10, 8, 11, 4,
382
- 7, 8, 4, 3, 0, 7, 3, 4, 0, 1, 9, 8, 4, 7, 4, 1, 9, 4, 7, 1, 7, 3, 1, 1, 2, 10, 8, 4, 7, 3,
383
- 4, 7, 3, 0, 4, 1, 2, 10, 9, 2, 10, 9, 0, 2, 8, 4, 7, 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, 8,
384
- 4, 7, 3, 11, 2, 11, 4, 7, 11, 2, 4, 2, 0, 4, 9, 0, 1, 8, 4, 7, 2, 3, 11, 4, 7, 11, 9, 4, 11, 9,
385
- 11, 2, 9, 2, 1, 3, 10, 1, 3, 11, 10, 7, 8, 4, 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, 4, 7, 8, 9,
386
- 0, 11, 9, 11, 10, 11, 0, 3, 4, 7, 11, 4, 11, 9, 9, 11, 10, 9, 5, 4, 9, 5, 4, 0, 8, 3, 0, 5, 4, 1,
387
- 5, 0, 8, 5, 4, 8, 3, 5, 3, 1, 5, 1, 2, 10, 9, 5, 4, 3, 0, 8, 1, 2, 10, 4, 9, 5, 5, 2, 10, 5,
388
- 4, 2, 4, 0, 2, 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, 9, 5, 4, 2, 3, 11, 0, 11, 2, 0, 8, 11, 4,
389
- 9, 5, 0, 5, 4, 0, 1, 5, 2, 3, 11, 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, 10, 3, 11, 10, 1, 3, 9,
390
- 5, 4, 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, 5, 4, 8, 5,
391
- 8, 10, 10, 8, 11, 9, 7, 8, 5, 7, 9, 9, 3, 0, 9, 5, 3, 5, 7, 3, 0, 7, 8, 0, 1, 7, 1, 5, 7, 1,
392
- 5, 3, 3, 5, 7, 9, 7, 8, 9, 5, 7, 10, 1, 2, 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, 8, 0, 2, 8,
393
- 2, 5, 8, 5, 7, 10, 5, 2, 2, 10, 5, 2, 5, 3, 3, 5, 7, 7, 9, 5, 7, 8, 9, 3, 11, 2, 9, 5, 7, 9,
394
- 7, 2, 9, 2, 0, 2, 7, 11, 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, 11, 2, 1, 11, 1, 7, 7, 1, 5, 9,
395
- 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, 11, 10, 0, 11,
396
- 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, 11, 10, 5, 7, 11, 5, 10, 6, 5, 0, 8, 3, 5, 10, 6, 9, 0, 1, 5,
397
- 10, 6, 1, 8, 3, 1, 9, 8, 5, 10, 6, 1, 6, 5, 2, 6, 1, 1, 6, 5, 1, 2, 6, 3, 0, 8, 9, 6, 5, 9,
398
- 0, 6, 0, 2, 6, 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, 2, 3, 11, 10, 6, 5, 11, 0, 8, 11, 2, 0, 10,
399
- 6, 5, 0, 1, 9, 2, 3, 11, 5, 10, 6, 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, 6, 3, 11, 6, 5, 3, 5,
400
- 1, 3, 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, 6, 5, 9, 6,
401
- 9, 11, 11, 9, 8, 5, 10, 6, 4, 7, 8, 4, 3, 0, 4, 7, 3, 6, 5, 10, 1, 9, 0, 5, 10, 6, 8, 4, 7, 10,
402
- 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, 6, 1, 2, 6, 5, 1, 4, 7, 8, 1, 2, 5, 5, 2, 6, 3, 0, 4, 3,
403
- 4, 7, 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, 3,
404
- 11, 2, 7, 8, 4, 10, 6, 5, 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, 0, 1, 9, 4, 7, 8, 2, 3, 11, 5,
405
- 10, 6, 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, 5,
406
- 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, 6,
407
- 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, 10, 4, 9, 6, 4, 10, 4, 10, 6, 4, 9, 10, 0, 8, 3, 10, 0, 1, 10,
408
- 6, 0, 6, 4, 0, 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, 1, 4, 9, 1, 2, 4, 2, 6, 4, 3, 0, 8, 1,
409
- 2, 9, 2, 4, 9, 2, 6, 4, 0, 2, 4, 4, 2, 6, 8, 3, 2, 8, 2, 4, 4, 2, 6, 10, 4, 9, 10, 6, 4, 11,
410
- 2, 3, 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, 6, 4, 1, 6,
411
- 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, 8, 11, 1, 8, 1, 0, 11,
412
- 6, 1, 9, 1, 4, 6, 4, 1, 3, 11, 6, 3, 6, 0, 0, 6, 4, 6, 4, 8, 11, 6, 8, 7, 10, 6, 7, 8, 10, 8,
413
- 9, 10, 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, 10, 6, 7, 10,
414
- 7, 1, 1, 7, 3, 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7,
415
- 3, 9, 7, 8, 0, 7, 0, 6, 6, 0, 2, 7, 3, 2, 6, 7, 2, 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, 2,
416
- 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, 11,
417
- 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, 0, 9, 1, 11,
418
- 6, 7, 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, 7, 11, 6, 7, 6, 11, 3, 0, 8, 11, 7, 6, 0, 1, 9, 11,
419
- 7, 6, 8, 1, 9, 8, 3, 1, 11, 7, 6, 10, 1, 2, 6, 11, 7, 1, 2, 10, 3, 0, 8, 6, 11, 7, 2, 9, 0, 2,
420
- 10, 9, 6, 11, 7, 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, 7, 2, 3, 6, 2, 7, 7, 0, 8, 7, 6, 0, 6,
421
- 2, 0, 2, 7, 6, 2, 3, 7, 0, 1, 9, 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, 10, 7, 6, 10, 1, 7, 1,
422
- 3, 7, 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, 7, 6, 10, 7,
423
- 10, 8, 8, 10, 9, 6, 8, 4, 11, 8, 6, 3, 6, 11, 3, 0, 6, 0, 4, 6, 8, 6, 11, 8, 4, 6, 9, 0, 1, 9,
424
- 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, 6, 8, 4, 6, 11, 8, 2, 10, 1, 1, 2, 10, 3, 0, 11, 0, 6, 11, 0,
425
- 4, 6, 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, 8,
426
- 2, 3, 8, 4, 2, 4, 6, 2, 0, 4, 2, 4, 6, 2, 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, 1, 9, 4, 1,
427
- 4, 2, 2, 4, 6, 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, 10, 1, 0, 10, 0, 6, 6, 0, 4, 4, 6, 3, 4,
428
- 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, 10, 9, 4, 6, 10, 4, 4, 9, 5, 7, 6, 11, 0, 8, 3, 4, 9, 5, 11,
429
- 7, 6, 5, 0, 1, 5, 4, 0, 7, 6, 11, 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, 9, 5, 4, 10, 1, 2, 7,
430
- 6, 11, 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, 3, 4, 8, 3,
431
- 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, 7, 2, 3, 7, 6, 2, 5, 4, 9, 9, 5, 4, 0, 8, 6, 0, 6, 2, 6,
432
- 8, 7, 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, 9,
433
- 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, 4, 0, 10, 4,
434
- 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, 6, 9, 5, 6, 11, 9, 11,
435
- 8, 9, 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, 6, 11, 3, 6,
436
- 3, 5, 5, 3, 1, 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1,
437
- 2, 10, 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, 5,
438
- 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, 9, 5, 6, 9, 6, 0, 0, 6, 2, 1, 5, 8, 1, 8, 0, 5, 6, 8, 3,
439
- 8, 2, 6, 2, 8, 1, 5, 6, 2, 1, 6, 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, 10, 1, 0, 10,
440
- 0, 6, 9, 5, 0, 5, 6, 0, 0, 3, 8, 5, 6, 10, 10, 5, 6, 11, 5, 10, 7, 5, 11, 11, 5, 10, 11, 7, 5, 8,
441
- 3, 0, 5, 11, 7, 5, 10, 11, 1, 9, 0, 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, 11, 1, 2, 11, 7, 1, 7,
442
- 5, 1, 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, 7, 5, 2, 7,
443
- 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, 2, 5, 10, 2, 3, 5, 3, 7, 5, 8, 2, 0, 8, 5, 2, 8, 7, 5, 10,
444
- 2, 5, 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, 1,
445
- 3, 5, 3, 7, 5, 0, 8, 7, 0, 7, 1, 1, 7, 5, 9, 0, 3, 9, 3, 5, 5, 3, 7, 9, 8, 7, 5, 9, 7, 5,
446
- 8, 4, 5, 10, 8, 10, 11, 8, 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, 0, 1, 9, 8, 4, 10, 8, 10, 11, 10,
447
- 4, 5, 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, 0,
448
- 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, 9,
449
- 4, 5, 2, 11, 3, 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, 5, 10, 2, 5, 2, 4, 4, 2, 0, 3, 10, 2, 3,
450
- 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, 8, 4, 5, 8, 5, 3, 3,
451
- 5, 1, 0, 4, 5, 1, 0, 5, 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, 9, 4, 5, 4, 11, 7, 4, 9, 11, 9,
452
- 10, 11, 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, 3, 1, 4, 3,
453
- 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, 9, 7, 4, 9, 11, 7, 9,
454
- 1, 11, 2, 11, 1, 0, 8, 3, 11, 7, 4, 11, 4, 2, 2, 4, 0, 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, 2,
455
- 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, 3, 7, 10, 3,
456
- 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, 1, 10, 2, 8, 7, 4, 4, 9, 1, 4, 1, 7, 7, 1, 3, 4, 9, 1, 4,
457
- 1, 7, 0, 8, 1, 8, 7, 1, 4, 0, 3, 7, 4, 3, 4, 8, 7, 9, 10, 8, 10, 11, 8, 3, 0, 9, 3, 9, 11, 11,
458
- 9, 10, 0, 1, 10, 0, 10, 8, 8, 10, 11, 3, 1, 10, 11, 3, 10, 1, 2, 11, 1, 11, 9, 9, 11, 8, 3, 0, 9, 3,
459
- 9, 11, 1, 2, 9, 2, 11, 9, 0, 2, 11, 8, 0, 11, 3, 2, 11, 2, 3, 8, 2, 8, 10, 10, 8, 9, 9, 10, 2, 0,
460
- 9, 2, 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, 1, 10, 2, 1, 3, 8, 9, 1, 8, 0, 9, 1, 0, 3, 8
461
- ])
462
-
463
- mc_edge_offset_np = np.array([
464
- [0, 0, 0, 0],
465
- [1, 0, 0, 1],
466
- [0, 1, 0, 0],
467
- [0, 0, 0, 1],
468
-
469
- [0, 0, 1, 0],
470
- [1, 0, 1, 1],
471
- [0, 1, 1, 0],
472
- [0, 0, 1, 1],
473
-
474
- [0, 0, 0, 2],
475
- [1, 0, 0, 2],
476
- [1, 1, 0, 2],
477
- [0, 1, 0, 2]
478
- ])
479
-
480
- mc_cube_corner_offsets = [[0,0,0], [1,0,0], [1,1,0], [0,1,0], [0,0,1], [1,0,1], [1,1,1], [0,1,1]]
481
- # fmt: on
482
-
483
-
484
- class MarchingCubes:
485
- """A reusable context for marching cubes surface extraction.
486
-
487
- This class provides a stateful interface for isosurface extraction. You
488
- can initialize it with a specific grid configuration and then call the
489
- :meth:`~.surface` method multiple times, which is efficient for processing
490
- fields of the same size.
491
-
492
- For a simpler, stateless operation, use the static method
493
- :meth:`~.extract_surface_marching_cubes`.
494
-
495
- Attributes:
496
- nx (int): The number of grid nodes in the x-direction.
497
- ny (int): The number of grid nodes in the y-direction.
498
- nz (int): The number of grid nodes in the z-direction.
499
- domain_bounds_lower_corner (wp.vec3 | tuple | None): The lower bound
500
- for the mesh coordinate scaling. See the documentation in
501
- :meth:`~.extract_surface_marching_cubes` for more details.
502
- domain_bounds_upper_corner (wp.vec3 | tuple | None): The upper bound
503
- for the mesh coordinate scaling. See the documentation in
504
- :meth:`~.extract_surface_marching_cubes` for more details.
505
- verts (warp.array | None): An array of vertex positions of type
506
- :class:`warp.vec3f` for the output mesh.
507
- This is populated by calling the :meth:`~.surface` method.
508
- indices (warp.array | None): An array of triangle indices of type
509
- :class:`warp.int32` for the output mesh.
510
- This is populated by calling the :meth:`~.surface` method.
511
- device (warp.Device): The device on which the context was created. This
512
- attribute is for backward compatibility and is not used by the
513
- class's methods.
514
- """
515
-
516
- def __new__(cls, *args, **kwargs):
517
- instance = super().__new__(cls)
518
- return instance
519
-
520
- def __init__(
521
- self,
522
- nx: int,
523
- ny: int,
524
- nz: int,
525
- max_verts: int = 0,
526
- max_tris: int = 0,
527
- device=None,
528
- domain_bounds_lower_corner=None,
529
- domain_bounds_upper_corner=None,
530
- ):
531
- """Initialize the marching cubes context with a grid configuration.
532
-
533
- Args:
534
- nx: Number of grid nodes in the x-direction.
535
- ny: Number of grid nodes in the y-direction.
536
- nz: Number of grid nodes in the z-direction.
537
- max_verts: (Deprecated) This argument is ignored.
538
- max_tris: (Deprecated) This argument is ignored.
539
- device (Devicelike): (Deprecated) The value is assigned to
540
- `self.device` for backward compatibility but is not used by the
541
- class's methods. It may be removed in a future version.
542
- domain_bounds_lower_corner: See the documentation in
543
- :meth:`~.extract_surface_marching_cubes`.
544
- domain_bounds_upper_corner: See the documentation in
545
- :meth:`~.extract_surface_marching_cubes`.
546
- """
547
- # Input domain sizes, as number of nodes in the grid (note this is 1 more than the number of cubes)
548
- self.nx = nx
549
- self.ny = ny
550
- self.nz = nz
551
-
552
- # Geometry of the extraction domain
553
- # (or None, to implicitly use a domain with integer-coordinate nodes)
554
- self.domain_bounds_lower_corner = domain_bounds_lower_corner
555
- self.domain_bounds_upper_corner = domain_bounds_upper_corner
556
-
557
- # These are unused, but retained for backwards-compatibility for code which might use them
558
- self.max_verts = max_verts
559
- self.max_tris = max_tris
560
-
561
- # Output arrays
562
- self.verts: wp.array(dtype=wp.vec3f) | None = None
563
- self.indices: wp.array(dtype=wp.int32) | None = None
564
-
565
- # These are unused, but retained for backwards-compatibility for code which might use them
566
- self.id = 0
567
- self.runtime = wp.context.runtime
568
- self.device = self.runtime.get_device(device)
569
-
570
- def resize(self, nx: int, ny: int, nz: int, max_verts: int = 0, max_tris: int = 0) -> None:
571
- """Update the grid dimensions for the context.
572
-
573
- This allows the instance to be reused for scalar fields of a different
574
- resolution. The new dimensions take effect on the next call to
575
- :meth:`~.surface`.
576
-
577
- Args:
578
- nx: New number of nodes in the x-direction.
579
- ny: New number of nodes in the y-direction.
580
- nz: New number of nodes in the z-direction.
581
- max_verts: (Deprecated) This argument is ignored.
582
- max_tris: (Deprecated) This argument is ignored.
583
- """
584
- self.nx = nx
585
- self.ny = ny
586
- self.nz = nz
587
-
588
- def surface(self, field: wp.array(dtype=float, ndim=3), threshold: float) -> None:
589
- """Compute a 2D surface mesh of a given isosurface from a 3D scalar field.
590
-
591
- This method is a convenience wrapper that calls the core static method
592
- and stores the resulting mesh data in the :attr:`verts` and
593
- :attr:`indices` attributes.
594
-
595
- Args:
596
- field: A 3D scalar field whose shape must match the grid dimensions
597
- (nx, ny, nz) of the instance.
598
- threshold: The field value defining the isosurface to extract.
599
-
600
- Raises:
601
- ValueError: If the shape of ``field`` does not match the configured
602
- grid dimensions of the instance.
603
- """
604
- # nx, ny, nz is the number of nodes, which should agree with the size of the field
605
- if field.shape != (self.nx, self.ny, self.nz):
606
- raise ValueError(
607
- f"Field shape {field.shape} does not match context grid dimensions {(self.nx, self.ny, self.nz)}."
608
- )
609
-
610
- verts, faces = self.extract_surface_marching_cubes(
611
- field=field,
612
- threshold=wp.float32(threshold),
613
- domain_bounds_lower_corner=self.domain_bounds_lower_corner,
614
- domain_bounds_upper_corner=self.domain_bounds_upper_corner,
615
- )
616
-
617
- self.verts = verts
618
- self.indices = faces
619
-
620
- @staticmethod
621
- def extract_surface_marching_cubes(
622
- field: wp.array3d(dtype=wp.float32),
623
- threshold: float = 0.0,
624
- domain_bounds_lower_corner: wp.vec3 | tuple[float, float, float] | None = None,
625
- domain_bounds_upper_corner: wp.vec3 | tuple[float, float, float] | None = None,
626
- ) -> tuple[wp.array(dtype=wp.vec3), wp.array(dtype=wp.int32)]:
627
- """Extract a triangular mesh from a 3D scalar field.
628
-
629
- This function generates an isosurface by processing the entire input ``field``.
630
- The resolution of the output mesh is determined by the shape of the ``field``
631
- array and may differ along each dimension.
632
-
633
- The coordinates of the mesh can be scaled to a specific bounding box
634
- using the ``domain_bounds_lower_corner`` and
635
- ``domain_bounds_upper_corner`` parameters. If a bound is not provided
636
- (i.e., left as ``None``), it will be assigned a default value that
637
- aligns the mesh with the integer indices of the input grid.
638
-
639
- For example, setting the bounds to ``wp.vec3(0.0, 0.0, 0.0)`` and
640
- ``wp.vec3(1.0, 1.0, 1.0)`` will scale the output mesh to fit
641
- within the unit cube.
642
-
643
- Args:
644
- field: A 3D array representing the scalar values on a regular grid.
645
- threshold: The field value defining the isosurface to extract.
646
- domain_bounds_lower_corner: The 3D coordinate that the grid's corner
647
- at index (0,0,0) maps to. Defaults to ``(0.0, 0.0, 0.0)``
648
- if ``None``.
649
- domain_bounds_upper_corner: The 3D coordinate that the grid's corner
650
- at index (nx-1, ny-1, nz-1) maps to. Defaults to align with the
651
- grid's maximal indices if ``None``.
652
-
653
- Returns:
654
- A tuple ``(vertices, indices)`` containing the output mesh data. The
655
- ``indices`` array is a flat list where each group of three consecutive
656
- integers forms a single triangle by referencing vertices in the
657
- ``vertices`` array.
658
-
659
- Raises:
660
- ValueError: If ``field`` is not a 3D array or is empty.
661
- TypeError: If the ``field`` data type is not ``wp.float32``.
662
- """
663
- # Do some validation
664
- if len(field.shape) != 3:
665
- raise ValueError(f"Expected a 3D array for 'field', but got an array with shape {field.shape}.")
666
-
667
- if field.size == 0:
668
- raise ValueError("The 'field' array cannot be empty.")
669
-
670
- if field.dtype != wp.float32:
671
- raise TypeError(f"Expected a dtype of wp.float32 for 'field', but got {field.dtype}.")
672
-
673
- # Parse out dimensions, being careful to distinguish between nodes and cells
674
- nnode_x, nnode_y, nnode_z = field.shape[0], field.shape[1], field.shape[2]
675
- ncell_x, ncell_y, ncell_z = nnode_x - 1, nnode_y - 1, nnode_z - 1
676
-
677
- # Apply default policies for bounds
678
- if domain_bounds_lower_corner is None:
679
- domain_bounds_lower_corner = wp.vec3((0.0, 0.0, 0.0))
680
- if domain_bounds_upper_corner is None:
681
- # The default convention is to treat the nodes of the grid as having integer coordinates at 0,1,2,...
682
- # This means the upper-rightmost node of the grid has coordinates (nnode_x-1, nnode_y-1, nnode_z-1)
683
- # (which happens to be the same as the number cells, although it may be more confusing to think of it that way)
684
- domain_bounds_upper_corner = wp.vec3((float(nnode_x - 1), float(nnode_y - 1), float(nnode_z - 1)))
685
-
686
- # quietly allow tuples as input too, although this technically violates
687
- # the type hinting
688
- domain_bounds_lower_corner = wp.vec3(domain_bounds_lower_corner)
689
- domain_bounds_upper_corner = wp.vec3(domain_bounds_upper_corner)
690
-
691
- # Compute the grid spacing
692
- domain_width = domain_bounds_upper_corner - domain_bounds_lower_corner
693
- grid_delta = wp.cw_div(domain_width, wp.vec3(ncell_x, ncell_y, ncell_z))
694
-
695
- # Extract the vertices
696
- # The second output of this kernel is an is-boundary flag for each vertex, which
697
- # we currently do not expose. (maybe this should be exposed in the future)
698
- verts, _, edge_generated_vert_ind = marching_cubes_extract_vertices(
699
- field, threshold, domain_bounds_lower_corner, grid_delta
700
- )
701
-
702
- # Extract faces between those vertices
703
- tris = marching_cubes_extract_faces(field, threshold, edge_generated_vert_ind)
704
-
705
- return verts, tris
706
-
707
- def __del__(self):
708
- return
24
+ return get_deprecated_api(_marching_cubes, "wp", name)