warp-lang 1.1.0__py3-none-macosx_10_13_universal2.whl → 1.2.1__py3-none-macosx_10_13_universal2.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/libwarp-clang.dylib +0 -0
  2. warp/bin/libwarp.dylib +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 +422 -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 +526 -85
  211. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/METADATA +61 -31
  212. warp_lang-1.2.1.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.1.dist-info}/LICENSE.md +0 -0
  217. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/WHEEL +0 -0
  218. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/top_level.txt +0 -0
@@ -32,8 +32,6 @@ def inc_kernel(a: wp.array(dtype=float)):
32
32
  a[tid] = a[tid] + 1.0
33
33
 
34
34
 
35
- wp.init()
36
-
37
35
  # configure devices
38
36
  for target_device in wp.get_cuda_devices():
39
37
  try:
@@ -7,7 +7,6 @@
7
7
 
8
8
  import warp as wp
9
9
 
10
- wp.init()
11
10
  wp.build.clear_kernel_cache()
12
11
 
13
12
 
@@ -128,8 +128,6 @@ def ksz(s: Sz):
128
128
  tid = wp.tid() # noqa: F841
129
129
 
130
130
 
131
- wp.init()
132
-
133
131
  wp.build.clear_kernel_cache()
134
132
 
135
133
  devices = wp.get_devices()
@@ -19,8 +19,6 @@ import numpy as np
19
19
  import warp as wp
20
20
  import warp.render
21
21
 
22
- wp.init()
23
-
24
22
 
25
23
  @wp.func
26
24
  def contact_force(n: wp.vec3, v: wp.vec3, c: float, k_n: float, k_d: float, k_f: float, k_mu: float):
@@ -18,8 +18,6 @@ import math
18
18
  import warp as wp
19
19
  import warp.render
20
20
 
21
- wp.init()
22
-
23
21
  grid_width = wp.constant(256)
24
22
  grid_height = wp.constant(128)
25
23
 
@@ -16,8 +16,6 @@ import numpy as np
16
16
 
17
17
  import warp as wp
18
18
 
19
- wp.init()
20
-
21
19
 
22
20
  @wp.kernel
23
21
  def fbm(
@@ -17,8 +17,6 @@
17
17
  import warp as wp
18
18
  import warp.render
19
19
 
20
- wp.init()
21
-
22
20
 
23
21
  @wp.func
24
22
  def sdf_create_box(pos: wp.vec3, size: wp.vec3):
@@ -24,8 +24,6 @@ import warp as wp
24
24
  import warp.examples
25
25
  import warp.render
26
26
 
27
- wp.init()
28
-
29
27
 
30
28
  @wp.kernel
31
29
  def deform(positions: wp.array(dtype=wp.vec3), t: float):
@@ -21,8 +21,6 @@ import warp as wp
21
21
  import warp.examples
22
22
  import warp.render
23
23
 
24
- wp.init()
25
-
26
24
 
27
25
  @wp.func
28
26
  def cw_min(a: wp.vec3, b: wp.vec3):
@@ -23,8 +23,6 @@ import warp as wp
23
23
  import warp.examples
24
24
  import warp.render
25
25
 
26
- wp.init()
27
-
28
26
 
29
27
  @wp.func
30
28
  def volume_grad(volume: wp.uint64, p: wp.vec3):
@@ -21,8 +21,6 @@ from pxr import Usd, UsdGeom
21
21
  import warp as wp
22
22
  import warp.examples
23
23
 
24
- wp.init()
25
-
26
24
 
27
25
  @wp.kernel
28
26
  def draw(mesh: wp.uint64, cam_pos: wp.vec3, width: int, height: int, pixels: wp.array(dtype=wp.vec3)):
@@ -16,8 +16,6 @@
16
16
 
17
17
  import warp as wp
18
18
 
19
- wp.init()
20
-
21
19
 
22
20
  @wp.func
23
21
  def sdf_sphere(p: wp.vec3, r: float):
@@ -18,8 +18,6 @@ import numpy as np
18
18
  import warp as wp
19
19
  import warp.render
20
20
 
21
- wp.init()
22
-
23
21
 
24
22
  class Example:
25
23
  def __init__(self, num_tiles=4, custom_tile_arrangement=False):
@@ -25,8 +25,6 @@ import numpy as np
25
25
  import warp as wp
26
26
  import warp.render
27
27
 
28
- wp.init()
29
-
30
28
 
31
29
  @wp.func
32
30
  def square(x: float):
@@ -23,9 +23,6 @@ import torch
23
23
 
24
24
  import warp as wp
25
25
 
26
- wp.init()
27
-
28
-
29
26
  pvec2 = wp.types.vector(length=2, dtype=wp.float32)
30
27
 
31
28
 
@@ -18,8 +18,6 @@ import math
18
18
  import warp as wp
19
19
  import warp.render
20
20
 
21
- wp.init()
22
-
23
21
 
24
22
  @wp.func
25
23
  def sample(f: wp.array(dtype=float), x: int, y: int, width: int, height: int):
@@ -8,7 +8,8 @@
8
8
  ###########################################################################
9
9
  # Example APIC Fluid Simulation
10
10
  #
11
- # Shows how to implement a apic fluid simulation.
11
+ # Shows how to implement a minimalist APIC fluid simulation using a NanoVDB
12
+ # grid and the PicQuadrature class.
12
13
  ###########################################################################
13
14
 
14
15
  import numpy as np
@@ -16,16 +17,22 @@ import numpy as np
16
17
  import warp as wp
17
18
  import warp.fem as fem
18
19
  import warp.sim.render
19
- from warp.fem import Domain, Field, Sample, at_node, div, grad, integrand, lookup, normal
20
+ from warp.fem import Domain, Field, Sample, at_node, div, grad, integrand
20
21
  from warp.sim import Model, State
21
- from warp.sparse import BsrMatrix, bsr_copy, bsr_mm, bsr_mv, bsr_transposed, bsr_zeros
22
+ from warp.sparse import BsrMatrix, bsr_mm, bsr_mv, bsr_transposed
22
23
 
23
24
  try:
24
25
  from .bsr_utils import bsr_cg
25
26
  except ImportError:
26
27
  from bsr_utils import bsr_cg
27
28
 
28
- wp.init()
29
+
30
+ @wp.func
31
+ def collision_sdf(x: wp.vec3):
32
+ # Arbitrary sdf representing collision geometry
33
+ # Here an inverted half-ball of radius 10
34
+ x[1] = wp.min(x[1], 0.0)
35
+ return 10.0 - wp.length(x), -wp.normalize(x)
29
36
 
30
37
 
31
38
  @integrand
@@ -48,6 +55,13 @@ def integrate_velocity(
48
55
  vel_apic = velocities[s.qp_index] + velocity_gradients[s.qp_index] * node_offset
49
56
 
50
57
  vel_adv = vel_apic + dt * gravity
58
+
59
+ # if inside collider, remove normal velocity
60
+ sdf, sdf_gradient = collision_sdf(domain(s))
61
+ if sdf <= 0:
62
+ v_n = wp.dot(vel_adv, sdf_gradient)
63
+ vel_adv -= wp.max(v_n, 0.0) * sdf_gradient
64
+
51
65
  return wp.dot(u(s), vel_adv)
52
66
 
53
67
 
@@ -63,31 +77,33 @@ def update_particles(
63
77
  vel_grad: wp.array(dtype=wp.mat33),
64
78
  ):
65
79
  """Read particle velocity from grid and advect positions"""
66
- vel[s.qp_index] = grid_vel(s)
80
+ p_vel = grid_vel(s)
67
81
  vel_grad[s.qp_index] = grad(grid_vel, s)
68
82
 
69
- pos_adv = pos_prev[s.qp_index] + dt * vel[s.qp_index]
83
+ pos_adv = pos_prev[s.qp_index] + dt * p_vel
70
84
 
71
- # Project onto domain
72
- pos_proj = domain(lookup(domain, pos_adv))
73
- pos[s.qp_index] = pos_proj
85
+ pos[s.qp_index] = pos_adv
86
+ vel[s.qp_index] = p_vel
74
87
 
75
88
 
76
89
  @integrand
77
90
  def velocity_boundary_projector_form(s: Sample, domain: Domain, u: Field, v: Field):
78
91
  """Projector for velocity-Dirichlet boundary conditions"""
79
92
 
80
- n = normal(domain, s)
81
- if n[1] > 0.0:
82
- # Neuman on top
93
+ x = domain(s)
94
+ sdf, sdf_normal = collision_sdf(x)
95
+
96
+ if sdf > 0.0:
97
+ # Neuman
83
98
  return 0.0
84
99
 
85
- # Free-slip on other sides
86
- return wp.dot(u(s), n) * wp.dot(v(s), n)
100
+ # Free-slip on boundary
101
+ return wp.dot(u(s), sdf_normal) * wp.dot(v(s), sdf_normal)
87
102
 
88
103
 
89
104
  @integrand
90
- def divergence_form(s: Sample, u: Field, psi: Field):
105
+ def divergence_form(s: Sample, domain: Domain, u: Field, psi: Field):
106
+ # Divergence bilinear form
91
107
  return div(u, s) * psi(s)
92
108
 
93
109
 
@@ -95,10 +111,7 @@ def divergence_form(s: Sample, u: Field, psi: Field):
95
111
  def invert_volume_kernel(values: wp.array(dtype=float)):
96
112
  i = wp.tid()
97
113
  m = values[i]
98
- if m <= 1.0e-8:
99
- values[i] = 0.0
100
- else:
101
- values[i] = 1.0 / m
114
+ values[i] = wp.select(m == 0.0, 1.0 / m, 0.0)
102
115
 
103
116
 
104
117
  @wp.kernel
@@ -117,6 +130,8 @@ def scale_transposed_divergence_mat(
117
130
  tr_divergence_mat_values: wp.array(dtype=wp.mat(shape=(3, 1), dtype=float)),
118
131
  inv_fraction_int: wp.array(dtype=float),
119
132
  ):
133
+ # In-place scaling of gradient operator rows wiht inverse mass
134
+
120
135
  u_i = wp.tid()
121
136
  block_beg = tr_divergence_mat_offsets[u_i]
122
137
  block_end = tr_divergence_mat_offsets[u_i + 1]
@@ -125,6 +140,15 @@ def scale_transposed_divergence_mat(
125
140
  tr_divergence_mat_values[b] = tr_divergence_mat_values[b] * inv_fraction_int[u_i]
126
141
 
127
142
 
143
+ @wp.kernel
144
+ def compute_particle_ijk(positions: wp.array(dtype=wp.vec3), voxel_size: float, ijks: wp.array(dtype=wp.vec3i)):
145
+ # Index-space coordinates of grid cell containing each particle
146
+
147
+ p = wp.tid()
148
+ pos = positions[p] / voxel_size
149
+ ijks[p] = wp.vec3i(int(wp.floor(pos[0])), int(wp.floor(pos[1])), int(wp.floor(pos[2])))
150
+
151
+
128
152
  def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False):
129
153
  """Solve for divergence-free velocity delta:
130
154
 
@@ -144,43 +168,45 @@ def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, vel
144
168
  ],
145
169
  )
146
170
 
147
- # For simplicity, assemble schur complement and solve with CG
171
+ # For simplicity, assemble Schur complement and solve with CG
148
172
  schur = bsr_mm(divergence_mat, transposed_divergence_mat)
149
173
 
150
174
  rhs = wp.zeros_like(pressure)
151
175
  bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0, beta=0.0)
152
- bsr_cg(schur, b=rhs, x=pressure, quiet=quiet)
176
+ bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6)
153
177
 
154
178
  # Apply pressure to velocity
155
179
  bsr_mv(A=transposed_divergence_mat, x=pressure, y=velocity, alpha=1.0, beta=1.0)
156
180
 
157
181
 
158
182
  class Example:
159
- def __init__(self, quiet=False, stage_path="example_apic_fluid.usd", res=(32, 64, 16)):
183
+ def __init__(self, quiet=False, stage_path="example_apic_fluid.usd", voxel_size=1.0):
160
184
  fps = 60
161
185
  self.frame_dt = 1.0 / fps
162
186
  self.current_frame = 0
163
187
 
164
188
  self.sim_substeps = 1
165
189
  self.sim_dt = self.frame_dt / self.sim_substeps
190
+ self.voxel_size = voxel_size
166
191
 
167
192
  self._quiet = quiet
168
193
 
169
- # grid dimensions and particle emission
170
- grid_res = np.array(res, dtype=int)
171
- particle_fill_frac = np.array([0.5, 0.5, 1.0])
172
- grid_lo = wp.vec3(0.0)
173
- grid_hi = wp.vec3(50, 100, 25)
194
+ # particle emission
195
+ particle_grid_lo = wp.vec3(-5)
196
+ particle_grid_hi = wp.vec3(5)
174
197
 
175
- grid_cell_size = np.array(grid_hi - grid_lo) / grid_res
198
+ grid_cell_size = voxel_size
176
199
  grid_cell_volume = np.prod(grid_cell_size)
177
200
 
178
- PARTICLES_PER_CELL_DIM = 3
201
+ PARTICLES_PER_CELL_DIM = 2
179
202
  self.radius = float(np.max(grid_cell_size) / (2 * PARTICLES_PER_CELL_DIM))
180
203
 
181
- particle_grid_res = np.array(particle_fill_frac * grid_res * PARTICLES_PER_CELL_DIM, dtype=int)
204
+ particle_grid_res = (
205
+ np.array((particle_grid_hi - particle_grid_lo) / voxel_size, dtype=int) * PARTICLES_PER_CELL_DIM
206
+ )
182
207
  particle_grid_offset = wp.vec3(self.radius, self.radius, self.radius)
183
208
 
209
+ # Initialize warp.sim model, spawn particles
184
210
  np.random.seed(0)
185
211
  builder = wp.sim.ModelBuilder()
186
212
  builder.add_particle_grid(
@@ -190,60 +216,17 @@ class Example:
190
216
  cell_x=self.radius * 2.0,
191
217
  cell_y=self.radius * 2.0,
192
218
  cell_z=self.radius * 2.0,
193
- pos=wp.vec3(0.0, 0.0, 0.0) + particle_grid_offset,
219
+ pos=particle_grid_lo + particle_grid_offset,
194
220
  rot=wp.quat_identity(),
195
221
  vel=wp.vec3(0.0, 0.0, 0.0),
196
222
  mass=grid_cell_volume / PARTICLES_PER_CELL_DIM**3,
197
223
  jitter=self.radius * 1.0,
198
- radius_mean=self.radius,
199
- )
200
-
201
- self.grid = fem.Grid3D(wp.vec3i(grid_res), grid_lo, grid_hi)
202
-
203
- # Function spaces
204
- self.velocity_space = fem.make_polynomial_space(self.grid, dtype=wp.vec3, degree=1)
205
- self.fraction_space = fem.make_polynomial_space(self.grid, dtype=float, degree=1)
206
- self.strain_space = fem.make_polynomial_space(
207
- self.grid,
208
- dtype=float,
209
- degree=0,
210
224
  )
211
-
212
- self.pressure_field = self.strain_space.make_field()
213
- self.velocity_field = self.velocity_space.make_field()
214
-
215
- # Test and trial functions
216
- self.domain = fem.Cells(self.grid)
217
- self.velocity_test = fem.make_test(self.velocity_space, domain=self.domain)
218
- self.velocity_trial = fem.make_trial(self.velocity_space, domain=self.domain)
219
- self.fraction_test = fem.make_test(self.fraction_space, domain=self.domain)
220
- self.strain_test = fem.make_test(self.strain_space, domain=self.domain)
221
- self.strain_trial = fem.make_trial(self.strain_space, domain=self.domain)
222
-
223
- # Enforcing the Dirichlet boundary condition the hard way;
224
- # build projector for velocity left- and right-hand-sides
225
- boundary = fem.BoundarySides(self.grid)
226
- u_bd_test = fem.make_test(space=self.velocity_space, domain=boundary)
227
- u_bd_trial = fem.make_trial(space=self.velocity_space, domain=boundary)
228
- u_bd_projector = fem.integrate(
229
- velocity_boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True, output_dtype=float
230
- )
231
-
232
- fem.normalize_dirichlet_projector(u_bd_projector)
233
- self.vel_bd_projector = u_bd_projector
225
+ self.model: Model = builder.finalize()
234
226
 
235
227
  # Storage for temporary variables
236
228
  self.temporary_store = fem.TemporaryStore()
237
229
 
238
- self._divergence_matrix = bsr_zeros(
239
- self.strain_space.node_count(),
240
- self.velocity_space.node_count(),
241
- block_type=wp.mat(shape=(1, 3), dtype=float),
242
- )
243
-
244
- # Warp.sim model
245
- self.model: Model = builder.finalize()
246
-
247
230
  if not self._quiet:
248
231
  print("Particle count:", self.model.particle_count)
249
232
 
@@ -265,79 +248,122 @@ class Example:
265
248
  fem.set_default_temporary_store(self.temporary_store)
266
249
 
267
250
  self.current_frame = self.current_frame + 1
251
+
252
+ particle_ijk = wp.empty(self.state_0.particle_count, dtype=wp.vec3i)
253
+
268
254
  with wp.ScopedTimer(f"simulate frame {self.current_frame}", active=True):
269
255
  for _s in range(self.sim_substeps):
270
- # Bin particles to grid cells
271
- pic = fem.PicQuadrature(
272
- domain=fem.Cells(self.grid), positions=self.state_0.particle_q, measures=self.model.particle_mass
256
+ # Compute the voxel coordinates for each particle.
257
+ # `Volume.allocate_by_voxels` accepts world positions, but allocates
258
+ # the voxels with the closest origin rather than the enclosing ones
259
+ # (i.e, it "round"s the positions, while here we eant to "floor" it)
260
+ wp.launch(
261
+ compute_particle_ijk,
262
+ dim=particle_ijk.shape,
263
+ inputs=[self.state_0.particle_q, self.voxel_size, particle_ijk],
264
+ )
265
+
266
+ # Allocate the voxels and create the warp.fem geometry
267
+ volume = wp.Volume.allocate_by_voxels(
268
+ voxel_points=particle_ijk,
269
+ voxel_size=self.voxel_size,
270
+ )
271
+ grid = fem.Nanogrid(volume)
272
+
273
+ # Define function spaces: linear (Q1) for velocity and volume fraction,
274
+ # piecewise-constant for pressure
275
+ linear_basis_space = fem.make_polynomial_basis_space(grid, degree=1)
276
+ velocity_space = fem.make_collocated_function_space(linear_basis_space, dtype=wp.vec3)
277
+ fraction_space = fem.make_collocated_function_space(linear_basis_space, dtype=float)
278
+ strain_space = fem.make_polynomial_space(
279
+ grid,
280
+ dtype=float,
281
+ degree=0,
282
+ discontinuous=True,
273
283
  )
274
284
 
275
- # Borrow some temporary arrays for storing integration results
276
- inv_volume_temporary = fem.borrow_temporary(
277
- self.temporary_store, shape=(self.fraction_space.node_count()), dtype=float
285
+ pressure_field = strain_space.make_field()
286
+ velocity_field = velocity_space.make_field()
287
+
288
+ # Define test and trial functions and integrating linear and bilinear forms
289
+ domain = fem.Cells(grid)
290
+ velocity_test = fem.make_test(velocity_space, domain=domain)
291
+ velocity_trial = fem.make_trial(velocity_space, domain=domain)
292
+ fraction_test = fem.make_test(fraction_space, domain=domain)
293
+ strain_test = fem.make_test(strain_space, domain=domain)
294
+
295
+ # Build projector for Dirichlet boundary conditions
296
+ vel_projector = fem.integrate(
297
+ velocity_boundary_projector_form,
298
+ fields={"u": velocity_trial, "v": velocity_test},
299
+ nodal=True,
300
+ output_dtype=float,
278
301
  )
279
- velocity_int_temporary = fem.borrow_temporary(
280
- self.temporary_store, shape=(self.velocity_space.node_count()), dtype=wp.vec3
302
+ fem.normalize_dirichlet_projector(vel_projector)
303
+
304
+ # Bin particles to grid cells
305
+ pic = fem.PicQuadrature(
306
+ domain=domain, positions=self.state_0.particle_q, measures=self.model.particle_mass
281
307
  )
282
- inv_volume = inv_volume_temporary.array
283
- velocity_int = velocity_int_temporary.array
284
308
 
285
- # Inverse volume fraction
286
- fem.integrate(
309
+ # Compute inverse particle volume for each grid node
310
+ inv_volume = fem.integrate(
287
311
  integrate_fraction,
288
312
  quadrature=pic,
289
- fields={"phi": self.fraction_test},
290
- accumulate_dtype=float,
291
- output=inv_volume,
313
+ fields={"phi": fraction_test},
314
+ output_dtype=float,
292
315
  )
293
316
  wp.launch(kernel=invert_volume_kernel, dim=inv_volume.shape, inputs=[inv_volume])
294
317
 
295
318
  # Velocity right-hand side
296
- fem.integrate(
319
+ velocity_int = fem.integrate(
297
320
  integrate_velocity,
298
321
  quadrature=pic,
299
- fields={"u": self.velocity_test},
322
+ fields={"u": velocity_test},
300
323
  values={
301
324
  "velocities": self.state_0.particle_qd,
302
325
  "velocity_gradients": self.state_0.particle_qd_grad,
303
326
  "dt": self.sim_dt,
304
327
  "gravity": self.model.gravity,
305
328
  },
306
- accumulate_dtype=float,
307
- output=velocity_int,
329
+ output_dtype=wp.vec3,
308
330
  )
309
331
 
310
332
  # Compute constraint-free velocity
311
333
  wp.launch(
312
334
  kernel=scalar_vector_multiply,
313
335
  dim=inv_volume.shape[0],
314
- inputs=[inv_volume, velocity_int, self.velocity_field.dof_values],
336
+ inputs=[inv_volume, velocity_int, velocity_field.dof_values],
315
337
  )
316
338
 
317
339
  # Apply velocity boundary conditions:
318
- # velocity -= vel_bd_projector * velocity
319
- wp.copy(src=self.velocity_field.dof_values, dest=velocity_int)
320
- bsr_mv(A=self.vel_bd_projector, x=velocity_int, y=self.velocity_field.dof_values, alpha=-1.0, beta=1.0)
340
+ # velocity -= vel_projector * velocity
341
+ bsr_mv(
342
+ A=vel_projector,
343
+ x=velocity_field.dof_values,
344
+ y=velocity_field.dof_values,
345
+ alpha=-1.0,
346
+ beta=1.0,
347
+ )
321
348
 
322
- # Divergence matrix
323
- fem.integrate(
349
+ # Assemble divergence operator matrix
350
+ divergence_matrix = fem.integrate(
324
351
  divergence_form,
325
352
  quadrature=pic,
326
- fields={"u": self.velocity_trial, "psi": self.strain_test},
327
- accumulate_dtype=float,
328
- output=self._divergence_matrix,
353
+ fields={"u": velocity_trial, "psi": strain_test},
354
+ output_dtype=float,
329
355
  )
330
356
 
331
357
  # Project matrix to enforce boundary conditions
332
- divergence_mat_tmp = bsr_copy(self._divergence_matrix)
333
- bsr_mm(alpha=-1.0, x=divergence_mat_tmp, y=self.vel_bd_projector, z=self._divergence_matrix, beta=1.0)
358
+ # divergence_matrix -= divergence_matrix * vel_projector
359
+ bsr_mm(alpha=-1.0, x=divergence_matrix, y=vel_projector, z=divergence_matrix, beta=1.0)
334
360
 
335
361
  # Solve unilateral incompressibility
336
362
  solve_incompressibility(
337
- self._divergence_matrix,
363
+ divergence_matrix,
338
364
  inv_volume,
339
- self.pressure_field.dof_values,
340
- self.velocity_field.dof_values,
365
+ pressure_field.dof_values,
366
+ velocity_field.dof_values,
341
367
  quiet=self._quiet,
342
368
  )
343
369
 
@@ -352,7 +378,7 @@ class Example:
352
378
  "vel_grad": self.state_1.particle_qd_grad,
353
379
  "dt": self.sim_dt,
354
380
  },
355
- fields={"grid_vel": self.velocity_field},
381
+ fields={"grid_vel": velocity_field},
356
382
  )
357
383
 
358
384
  # swap states
@@ -385,19 +411,18 @@ if __name__ == "__main__":
385
411
  default="example_apic_fluid.usd",
386
412
  help="Path to the output USD file.",
387
413
  )
388
- parser.add_argument("--num_frames", type=int, default=1000, help="Total number of frames.")
414
+ parser.add_argument("--num_frames", type=int, default=250, help="Total number of frames.")
389
415
  parser.add_argument("--quiet", action="store_true")
390
416
  parser.add_argument(
391
- "--res",
392
- type=lambda s: [int(item) for item in s.split(",")],
393
- default="32,64,16",
394
- help="Delimited list specifying resolution in x, y, and z.",
417
+ "--voxel_size",
418
+ type=float,
419
+ default=0.25,
395
420
  )
396
421
 
397
422
  args = parser.parse_known_args()[0]
398
423
 
399
424
  with wp.ScopedDevice(args.device):
400
- example = Example(quiet=args.quiet, stage_path=args.stage_path, res=args.res)
425
+ example = Example(quiet=args.quiet, stage_path=args.stage_path, voxel_size=args.voxel_size)
401
426
 
402
427
  for _ in range(args.num_frames):
403
428
  example.step()