warp-lang 1.0.0b2__py3-none-manylinux2014_x86_64.whl → 1.0.0b6__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. docs/conf.py +17 -5
  2. examples/env/env_ant.py +1 -1
  3. examples/env/env_cartpole.py +1 -1
  4. examples/env/env_humanoid.py +1 -1
  5. examples/env/env_usd.py +4 -1
  6. examples/env/environment.py +8 -9
  7. examples/example_dem.py +34 -33
  8. examples/example_diffray.py +364 -337
  9. examples/example_fluid.py +32 -23
  10. examples/example_jacobian_ik.py +97 -93
  11. examples/example_marching_cubes.py +6 -16
  12. examples/example_mesh.py +6 -16
  13. examples/example_mesh_intersect.py +16 -14
  14. examples/example_nvdb.py +14 -16
  15. examples/example_raycast.py +14 -13
  16. examples/example_raymarch.py +16 -23
  17. examples/example_render_opengl.py +19 -10
  18. examples/example_sim_cartpole.py +82 -78
  19. examples/example_sim_cloth.py +45 -48
  20. examples/example_sim_fk_grad.py +51 -44
  21. examples/example_sim_fk_grad_torch.py +47 -40
  22. examples/example_sim_grad_bounce.py +108 -133
  23. examples/example_sim_grad_cloth.py +99 -113
  24. examples/example_sim_granular.py +5 -6
  25. examples/{example_sim_sdf_shape.py → example_sim_granular_collision_sdf.py} +37 -26
  26. examples/example_sim_neo_hookean.py +51 -55
  27. examples/example_sim_particle_chain.py +4 -4
  28. examples/example_sim_quadruped.py +126 -81
  29. examples/example_sim_rigid_chain.py +54 -61
  30. examples/example_sim_rigid_contact.py +66 -70
  31. examples/example_sim_rigid_fem.py +3 -3
  32. examples/example_sim_rigid_force.py +1 -1
  33. examples/example_sim_rigid_gyroscopic.py +3 -4
  34. examples/example_sim_rigid_kinematics.py +28 -39
  35. examples/example_sim_trajopt.py +112 -110
  36. examples/example_sph.py +9 -8
  37. examples/example_wave.py +7 -7
  38. examples/fem/bsr_utils.py +30 -17
  39. examples/fem/example_apic_fluid.py +85 -69
  40. examples/fem/example_convection_diffusion.py +97 -93
  41. examples/fem/example_convection_diffusion_dg.py +142 -149
  42. examples/fem/example_convection_diffusion_dg0.py +141 -136
  43. examples/fem/example_deformed_geometry.py +146 -0
  44. examples/fem/example_diffusion.py +115 -84
  45. examples/fem/example_diffusion_3d.py +116 -86
  46. examples/fem/example_diffusion_mgpu.py +102 -79
  47. examples/fem/example_mixed_elasticity.py +139 -100
  48. examples/fem/example_navier_stokes.py +175 -162
  49. examples/fem/example_stokes.py +143 -111
  50. examples/fem/example_stokes_transfer.py +186 -157
  51. examples/fem/mesh_utils.py +59 -97
  52. examples/fem/plot_utils.py +138 -17
  53. tools/ci/publishing/build_nodes_info.py +54 -0
  54. warp/__init__.py +4 -3
  55. warp/__init__.pyi +1 -0
  56. warp/bin/warp-clang.so +0 -0
  57. warp/bin/warp.so +0 -0
  58. warp/build.py +5 -3
  59. warp/build_dll.py +29 -9
  60. warp/builtins.py +836 -492
  61. warp/codegen.py +864 -553
  62. warp/config.py +3 -1
  63. warp/context.py +389 -172
  64. warp/fem/__init__.py +24 -6
  65. warp/fem/cache.py +318 -25
  66. warp/fem/dirichlet.py +7 -3
  67. warp/fem/domain.py +14 -0
  68. warp/fem/field/__init__.py +30 -38
  69. warp/fem/field/field.py +149 -0
  70. warp/fem/field/nodal_field.py +244 -138
  71. warp/fem/field/restriction.py +8 -6
  72. warp/fem/field/test.py +127 -59
  73. warp/fem/field/trial.py +117 -60
  74. warp/fem/geometry/__init__.py +5 -1
  75. warp/fem/geometry/deformed_geometry.py +271 -0
  76. warp/fem/geometry/element.py +24 -1
  77. warp/fem/geometry/geometry.py +86 -14
  78. warp/fem/geometry/grid_2d.py +112 -54
  79. warp/fem/geometry/grid_3d.py +134 -65
  80. warp/fem/geometry/hexmesh.py +953 -0
  81. warp/fem/geometry/partition.py +85 -33
  82. warp/fem/geometry/quadmesh_2d.py +532 -0
  83. warp/fem/geometry/tetmesh.py +451 -115
  84. warp/fem/geometry/trimesh_2d.py +197 -92
  85. warp/fem/integrate.py +534 -268
  86. warp/fem/operator.py +58 -31
  87. warp/fem/polynomial.py +11 -0
  88. warp/fem/quadrature/__init__.py +1 -1
  89. warp/fem/quadrature/pic_quadrature.py +150 -58
  90. warp/fem/quadrature/quadrature.py +209 -57
  91. warp/fem/space/__init__.py +230 -53
  92. warp/fem/space/basis_space.py +489 -0
  93. warp/fem/space/collocated_function_space.py +105 -0
  94. warp/fem/space/dof_mapper.py +49 -2
  95. warp/fem/space/function_space.py +90 -39
  96. warp/fem/space/grid_2d_function_space.py +149 -496
  97. warp/fem/space/grid_3d_function_space.py +173 -538
  98. warp/fem/space/hexmesh_function_space.py +352 -0
  99. warp/fem/space/partition.py +129 -76
  100. warp/fem/space/quadmesh_2d_function_space.py +369 -0
  101. warp/fem/space/restriction.py +46 -34
  102. warp/fem/space/shape/__init__.py +15 -0
  103. warp/fem/space/shape/cube_shape_function.py +738 -0
  104. warp/fem/space/shape/shape_function.py +103 -0
  105. warp/fem/space/shape/square_shape_function.py +611 -0
  106. warp/fem/space/shape/tet_shape_function.py +567 -0
  107. warp/fem/space/shape/triangle_shape_function.py +429 -0
  108. warp/fem/space/tetmesh_function_space.py +132 -1039
  109. warp/fem/space/topology.py +295 -0
  110. warp/fem/space/trimesh_2d_function_space.py +104 -742
  111. warp/fem/types.py +13 -11
  112. warp/fem/utils.py +335 -60
  113. warp/native/array.h +120 -34
  114. warp/native/builtin.h +101 -72
  115. warp/native/bvh.cpp +73 -325
  116. warp/native/bvh.cu +406 -23
  117. warp/native/bvh.h +22 -40
  118. warp/native/clang/clang.cpp +1 -0
  119. warp/native/crt.h +2 -0
  120. warp/native/cuda_util.cpp +8 -3
  121. warp/native/cuda_util.h +1 -0
  122. warp/native/exports.h +1522 -1243
  123. warp/native/intersect.h +19 -4
  124. warp/native/intersect_adj.h +8 -8
  125. warp/native/mat.h +76 -17
  126. warp/native/mesh.cpp +33 -108
  127. warp/native/mesh.cu +114 -18
  128. warp/native/mesh.h +395 -40
  129. warp/native/noise.h +272 -329
  130. warp/native/quat.h +51 -8
  131. warp/native/rand.h +44 -34
  132. warp/native/reduce.cpp +1 -1
  133. warp/native/sparse.cpp +4 -4
  134. warp/native/sparse.cu +163 -155
  135. warp/native/spatial.h +2 -2
  136. warp/native/temp_buffer.h +18 -14
  137. warp/native/vec.h +103 -21
  138. warp/native/warp.cpp +2 -1
  139. warp/native/warp.cu +28 -3
  140. warp/native/warp.h +4 -3
  141. warp/render/render_opengl.py +261 -109
  142. warp/sim/__init__.py +1 -2
  143. warp/sim/articulation.py +385 -185
  144. warp/sim/import_mjcf.py +59 -48
  145. warp/sim/import_urdf.py +15 -15
  146. warp/sim/import_usd.py +174 -102
  147. warp/sim/inertia.py +17 -18
  148. warp/sim/integrator_xpbd.py +4 -3
  149. warp/sim/model.py +330 -250
  150. warp/sim/render.py +1 -1
  151. warp/sparse.py +625 -152
  152. warp/stubs.py +341 -309
  153. warp/tape.py +9 -6
  154. warp/tests/__main__.py +3 -6
  155. warp/tests/assets/curlnoise_golden.npy +0 -0
  156. warp/tests/assets/pnoise_golden.npy +0 -0
  157. warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
  158. warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
  159. warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
  160. warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
  161. warp/tests/aux_test_unresolved_func.py +14 -0
  162. warp/tests/aux_test_unresolved_symbol.py +14 -0
  163. warp/tests/disabled_kinematics.py +239 -0
  164. warp/tests/run_coverage_serial.py +31 -0
  165. warp/tests/test_adam.py +103 -106
  166. warp/tests/test_arithmetic.py +94 -74
  167. warp/tests/test_array.py +82 -101
  168. warp/tests/test_array_reduce.py +57 -23
  169. warp/tests/test_atomic.py +64 -28
  170. warp/tests/test_bool.py +22 -12
  171. warp/tests/test_builtins_resolution.py +1292 -0
  172. warp/tests/test_bvh.py +18 -18
  173. warp/tests/test_closest_point_edge_edge.py +54 -57
  174. warp/tests/test_codegen.py +165 -134
  175. warp/tests/test_compile_consts.py +28 -20
  176. warp/tests/test_conditional.py +108 -24
  177. warp/tests/test_copy.py +10 -12
  178. warp/tests/test_ctypes.py +112 -88
  179. warp/tests/test_dense.py +21 -14
  180. warp/tests/test_devices.py +98 -0
  181. warp/tests/test_dlpack.py +75 -75
  182. warp/tests/test_examples.py +237 -0
  183. warp/tests/test_fabricarray.py +22 -24
  184. warp/tests/test_fast_math.py +15 -11
  185. warp/tests/test_fem.py +1034 -124
  186. warp/tests/test_fp16.py +23 -16
  187. warp/tests/test_func.py +187 -86
  188. warp/tests/test_generics.py +194 -49
  189. warp/tests/test_grad.py +123 -181
  190. warp/tests/test_grad_customs.py +176 -0
  191. warp/tests/test_hash_grid.py +35 -34
  192. warp/tests/test_import.py +10 -23
  193. warp/tests/test_indexedarray.py +24 -25
  194. warp/tests/test_intersect.py +18 -9
  195. warp/tests/test_large.py +141 -0
  196. warp/tests/test_launch.py +14 -41
  197. warp/tests/test_lerp.py +64 -65
  198. warp/tests/test_lvalue.py +493 -0
  199. warp/tests/test_marching_cubes.py +12 -13
  200. warp/tests/test_mat.py +517 -2898
  201. warp/tests/test_mat_lite.py +115 -0
  202. warp/tests/test_mat_scalar_ops.py +2889 -0
  203. warp/tests/test_math.py +103 -9
  204. warp/tests/test_matmul.py +304 -69
  205. warp/tests/test_matmul_lite.py +410 -0
  206. warp/tests/test_mesh.py +60 -22
  207. warp/tests/test_mesh_query_aabb.py +21 -25
  208. warp/tests/test_mesh_query_point.py +111 -22
  209. warp/tests/test_mesh_query_ray.py +12 -24
  210. warp/tests/test_mlp.py +30 -22
  211. warp/tests/test_model.py +92 -89
  212. warp/tests/test_modules_lite.py +39 -0
  213. warp/tests/test_multigpu.py +88 -114
  214. warp/tests/test_noise.py +12 -11
  215. warp/tests/test_operators.py +16 -20
  216. warp/tests/test_options.py +11 -11
  217. warp/tests/test_pinned.py +17 -18
  218. warp/tests/test_print.py +32 -11
  219. warp/tests/test_quat.py +275 -129
  220. warp/tests/test_rand.py +18 -16
  221. warp/tests/test_reload.py +38 -34
  222. warp/tests/test_rounding.py +50 -43
  223. warp/tests/test_runlength_encode.py +168 -20
  224. warp/tests/test_smoothstep.py +9 -11
  225. warp/tests/test_snippet.py +143 -0
  226. warp/tests/test_sparse.py +261 -63
  227. warp/tests/test_spatial.py +276 -243
  228. warp/tests/test_streams.py +110 -85
  229. warp/tests/test_struct.py +268 -63
  230. warp/tests/test_tape.py +39 -21
  231. warp/tests/test_torch.py +90 -86
  232. warp/tests/test_transient_module.py +10 -12
  233. warp/tests/test_types.py +363 -0
  234. warp/tests/test_utils.py +451 -0
  235. warp/tests/test_vec.py +354 -2050
  236. warp/tests/test_vec_lite.py +73 -0
  237. warp/tests/test_vec_scalar_ops.py +2099 -0
  238. warp/tests/test_volume.py +418 -376
  239. warp/tests/test_volume_write.py +124 -134
  240. warp/tests/unittest_serial.py +35 -0
  241. warp/tests/unittest_suites.py +291 -0
  242. warp/tests/unittest_utils.py +342 -0
  243. warp/tests/{test_misc.py → unused_test_misc.py} +13 -5
  244. warp/tests/{test_debug.py → walkthough_debug.py} +3 -17
  245. warp/thirdparty/appdirs.py +36 -45
  246. warp/thirdparty/unittest_parallel.py +589 -0
  247. warp/types.py +622 -211
  248. warp/utils.py +54 -393
  249. warp_lang-1.0.0b6.dist-info/METADATA +238 -0
  250. warp_lang-1.0.0b6.dist-info/RECORD +409 -0
  251. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/WHEEL +1 -1
  252. examples/example_cache_management.py +0 -40
  253. examples/example_multigpu.py +0 -54
  254. examples/example_struct.py +0 -65
  255. examples/fem/example_stokes_transfer_3d.py +0 -210
  256. warp/fem/field/discrete_field.py +0 -80
  257. warp/fem/space/nodal_function_space.py +0 -233
  258. warp/tests/test_all.py +0 -223
  259. warp/tests/test_array_scan.py +0 -60
  260. warp/tests/test_base.py +0 -208
  261. warp/tests/test_unresolved_func.py +0 -7
  262. warp/tests/test_unresolved_symbol.py +0 -7
  263. warp_lang-1.0.0b2.dist-info/METADATA +0 -26
  264. warp_lang-1.0.0b2.dist-info/RECORD +0 -378
  265. /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
  266. /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
  267. /warp/tests/{test_square.py → aux_test_square.py} +0 -0
  268. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/LICENSE.md +0 -0
  269. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/top_level.txt +0 -0
@@ -1,26 +1,23 @@
1
1
  import os
2
- import math
3
- from typing import Any
4
2
 
5
3
  import warp as wp
6
4
  import numpy as np
7
5
 
8
- import warp.sim.render
9
6
  from warp.sim import Model, State
7
+ import warp.sim.render
8
+
9
+ import warp.fem as fem
10
+
11
+ from warp.fem import integrand, lookup, normal, grad, at_node, div
12
+ from warp.fem import Field, Sample, Domain
10
13
 
11
- from warp.fem.geometry import Grid3D
12
- from warp.fem.domain import Cells, BoundarySides
13
- from warp.fem.space import make_polynomial_space
14
- from warp.fem.quadrature import PicQuadrature
15
- from warp.fem.field import make_test, make_trial
16
- from warp.fem.types import vec3i, Field, Sample, Domain
17
- from warp.fem.integrate import integrate
18
- from warp.fem.operator import integrand, lookup, normal, grad, at_node, div
19
- from warp.fem.dirichlet import normalize_dirichlet_projector
14
+ from warp.sparse import bsr_mv, bsr_copy, bsr_mm, bsr_transposed, bsr_zeros, BsrMatrix
20
15
 
21
- from warp.sparse import bsr_mv, bsr_copy, bsr_mm, bsr_transposed, BsrMatrix
22
16
 
23
- from bsr_utils import bsr_cg
17
+ try:
18
+ from .bsr_utils import bsr_cg
19
+ except ImportError:
20
+ from bsr_utils import bsr_cg
24
21
 
25
22
 
26
23
  @integrand
@@ -67,8 +64,6 @@ def update_particles(
67
64
  pos_proj = domain(lookup(domain, pos_adv))
68
65
  pos[s.qp_index] = pos_proj
69
66
 
70
- return 0.0
71
-
72
67
 
73
68
  @integrand
74
69
  def velocity_boundary_projector_form(s: Sample, domain: Domain, u: Field, v: Field):
@@ -122,12 +117,7 @@ def scale_transposed_divergence_mat(
122
117
  tr_divergence_mat_values[b] = tr_divergence_mat_values[b] * inv_fraction_int[u_i]
123
118
 
124
119
 
125
- def solve_incompressibility(
126
- divergence_mat: BsrMatrix,
127
- inv_volume,
128
- pressure,
129
- velocity,
130
- ):
120
+ def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False):
131
121
  """Solve for divergence-free velocity delta:
132
122
 
133
123
  delta_velocity = inv_volume * transpose(divergence_mat) * pressure
@@ -151,24 +141,26 @@ def solve_incompressibility(
151
141
 
152
142
  rhs = wp.zeros_like(pressure)
153
143
  bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0, beta=0.0)
154
- bsr_cg(schur, b=rhs, x=pressure)
144
+ bsr_cg(schur, b=rhs, x=pressure, quiet=quiet)
155
145
 
156
146
  # Apply pressure to velocity
157
147
  bsr_mv(A=transposed_divergence_mat, x=pressure, y=velocity, alpha=1.0, beta=1.0)
158
148
 
159
149
 
160
150
  class Example:
161
- def __init__(self, stage):
151
+ def __init__(self, stage, num_frames=1000, res=[32, 64, 16], quiet=False):
162
152
  self.frame_dt = 1.0 / 60
163
- self.frame_count = 1000
153
+ self.num_frames = num_frames
154
+ self.current_frame = 0
164
155
 
165
156
  self.sim_substeps = 1
166
157
  self.sim_dt = self.frame_dt / self.sim_substeps
167
- self.sim_steps = self.frame_count * self.sim_substeps
168
- self.sim_time = 0.0
158
+ self.sim_steps = self.num_frames * self.sim_substeps
159
+
160
+ self._quiet = quiet
169
161
 
170
162
  # grid dimensions and particle emission
171
- grid_res = np.array([32, 64, 16], dtype=int)
163
+ grid_res = np.array(res, dtype=int)
172
164
  particle_fill_frac = np.array([0.5, 0.5, 1.0])
173
165
  grid_lo = wp.vec3(0.0)
174
166
  grid_hi = wp.vec3(50, 100, 25)
@@ -177,10 +169,10 @@ class Example:
177
169
  grid_cell_volume = np.prod(grid_cell_size)
178
170
 
179
171
  PARTICLES_PER_CELL_DIM = 3
180
- self.radius = np.max(grid_cell_size) / (2 * PARTICLES_PER_CELL_DIM)
172
+ self.radius = float(np.max(grid_cell_size) / (2 * PARTICLES_PER_CELL_DIM))
181
173
 
182
174
  particle_grid_res = np.array(particle_fill_frac * grid_res * PARTICLES_PER_CELL_DIM, dtype=int)
183
- particle_grid_offset = self.radius * np.ones(3)
175
+ particle_grid_offset = wp.vec3(self.radius, self.radius, self.radius)
184
176
 
185
177
  np.random.seed(0)
186
178
  builder = wp.sim.ModelBuilder()
@@ -191,20 +183,20 @@ class Example:
191
183
  cell_x=self.radius * 2.0,
192
184
  cell_y=self.radius * 2.0,
193
185
  cell_z=self.radius * 2.0,
194
- pos=(0.0, 0.0, 0.0) + particle_grid_offset,
186
+ pos=wp.vec3(0.0, 0.0, 0.0) + particle_grid_offset,
195
187
  rot=wp.quat_identity(),
196
- vel=(0.0, 0.0, 0.0),
188
+ vel=wp.vec3(0.0, 0.0, 0.0),
197
189
  mass=grid_cell_volume / PARTICLES_PER_CELL_DIM**3,
198
190
  jitter=self.radius * 1.0,
199
191
  radius_mean=self.radius,
200
192
  )
201
193
 
202
- self.grid = Grid3D(vec3i(grid_res), grid_lo, grid_hi)
194
+ self.grid = fem.Grid3D(wp.vec3i(grid_res), grid_lo, grid_hi)
203
195
 
204
196
  # Function spaces
205
- self.velocity_space = make_polynomial_space(self.grid, dtype=wp.vec3, degree=1)
206
- self.fraction_space = make_polynomial_space(self.grid, dtype=float, degree=1)
207
- self.strain_space = make_polynomial_space(
197
+ self.velocity_space = fem.make_polynomial_space(self.grid, dtype=wp.vec3, degree=1)
198
+ self.fraction_space = fem.make_polynomial_space(self.grid, dtype=float, degree=1)
199
+ self.strain_space = fem.make_polynomial_space(
208
200
  self.grid,
209
201
  dtype=float,
210
202
  degree=0,
@@ -214,29 +206,39 @@ class Example:
214
206
  self.velocity_field = self.velocity_space.make_field()
215
207
 
216
208
  # Test and trial functions
217
- self.domain = Cells(self.grid)
218
- self.velocity_test = make_test(self.velocity_space, domain=self.domain)
219
- self.velocity_trial = make_trial(self.velocity_space, domain=self.domain)
220
- self.fraction_test = make_test(self.fraction_space, domain=self.domain)
221
- self.strain_test = make_test(self.strain_space, domain=self.domain)
222
- self.strain_trial = make_trial(self.strain_space, domain=self.domain)
209
+ self.domain = fem.Cells(self.grid)
210
+ self.velocity_test = fem.make_test(self.velocity_space, domain=self.domain)
211
+ self.velocity_trial = fem.make_trial(self.velocity_space, domain=self.domain)
212
+ self.fraction_test = fem.make_test(self.fraction_space, domain=self.domain)
213
+ self.strain_test = fem.make_test(self.strain_space, domain=self.domain)
214
+ self.strain_trial = fem.make_trial(self.strain_space, domain=self.domain)
223
215
 
224
216
  # Enforcing the Dirichlet boundary condition the hard way;
225
217
  # build projector for velocity left- and right-hand-sides
226
- boundary = BoundarySides(self.grid)
227
- u_bd_test = make_test(space=self.velocity_space, domain=boundary)
228
- u_bd_trial = make_trial(space=self.velocity_space, domain=boundary)
229
- u_bd_projector = integrate(
218
+ boundary = fem.BoundarySides(self.grid)
219
+ u_bd_test = fem.make_test(space=self.velocity_space, domain=boundary)
220
+ u_bd_trial = fem.make_trial(space=self.velocity_space, domain=boundary)
221
+ u_bd_projector = fem.integrate(
230
222
  velocity_boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True, output_dtype=float
231
223
  )
232
224
 
233
- normalize_dirichlet_projector(u_bd_projector)
225
+ fem.normalize_dirichlet_projector(u_bd_projector)
234
226
  self.vel_bd_projector = u_bd_projector
235
227
 
228
+ # Storage for temporary variables
229
+ self.temporary_store = fem.TemporaryStore()
230
+
231
+ self._divergence_matrix = bsr_zeros(
232
+ self.strain_space.node_count(),
233
+ self.velocity_space.node_count(),
234
+ block_type=wp.mat(shape=(1, 3), dtype=float),
235
+ )
236
+
236
237
  # Warp.sim model
237
238
  self.model: Model = builder.finalize()
238
239
 
239
- print("Particle count:", self.model.particle_count)
240
+ if not self._quiet:
241
+ print("Particle count:", self.model.particle_count)
240
242
 
241
243
  self.state_0: State = self.model.state()
242
244
  self.state_0.particle_qd_grad = wp.zeros(shape=(self.model.particle_count), dtype=wp.mat33)
@@ -244,28 +246,41 @@ class Example:
244
246
  self.state_1: State = self.model.state()
245
247
  self.state_1.particle_qd_grad = wp.zeros(shape=(self.model.particle_count), dtype=wp.mat33)
246
248
 
247
- self.renderer = wp.sim.render.SimRenderer(self.model, stage, scaling=20.0)
249
+ self.renderer = warp.sim.render.SimRenderer(self.model, stage, scaling=20.0)
248
250
 
249
- def update(self, frame_index):
250
- with wp.ScopedTimer(f"simulate frame {frame_index}", active=True):
251
+ def update(self):
252
+ fem.set_default_temporary_store(self.temporary_store)
253
+
254
+ self.current_frame = self.current_frame + 1
255
+ with wp.ScopedTimer(f"simulate frame {self.current_frame}", active=True):
251
256
  for s in range(self.sim_substeps):
252
257
  # Bin particles to grid cells
253
- pic = PicQuadrature(
254
- domain=Cells(self.grid), positions=self.state_0.particle_q, measures=self.model.particle_mass
258
+ pic = fem.PicQuadrature(
259
+ domain=fem.Cells(self.grid), positions=self.state_0.particle_q, measures=self.model.particle_mass
255
260
  )
256
261
 
262
+ # Borrow some temporary arrays for storing integration results
263
+ inv_volume_temporary = fem.borrow_temporary(
264
+ self.temporary_store, shape=(self.fraction_space.node_count()), dtype=float
265
+ )
266
+ velocity_int_temporary = fem.borrow_temporary(
267
+ self.temporary_store, shape=(self.velocity_space.node_count()), dtype=wp.vec3
268
+ )
269
+ inv_volume = inv_volume_temporary.array
270
+ velocity_int = velocity_int_temporary.array
271
+
257
272
  # Inverse volume fraction
258
- fraction_test = make_test(space=self.fraction_space, domain=pic.domain)
259
- inv_volume = integrate(
273
+ fem.integrate(
260
274
  integrate_fraction,
261
275
  quadrature=pic,
262
- fields={"phi": fraction_test},
276
+ fields={"phi": self.fraction_test},
263
277
  accumulate_dtype=float,
278
+ output=inv_volume,
264
279
  )
265
280
  wp.launch(kernel=invert_volume_kernel, dim=inv_volume.shape, inputs=[inv_volume])
266
281
 
267
282
  # Velocity right-hand side
268
- velocity_int = integrate(
283
+ fem.integrate(
269
284
  integrate_velocity,
270
285
  quadrature=pic,
271
286
  fields={"u": self.velocity_test},
@@ -276,7 +291,7 @@ class Example:
276
291
  "gravity": self.model.gravity,
277
292
  },
278
293
  accumulate_dtype=float,
279
- output_dtype=wp.vec3,
294
+ output=velocity_int,
280
295
  )
281
296
 
282
297
  # Compute constraint-free velocity
@@ -292,28 +307,29 @@ class Example:
292
307
  bsr_mv(A=self.vel_bd_projector, x=velocity_int, y=self.velocity_field.dof_values, alpha=-1.0, beta=1.0)
293
308
 
294
309
  # Divergence matrix
295
- divergence_mat = integrate(
310
+ fem.integrate(
296
311
  divergence_form,
297
312
  quadrature=pic,
298
313
  fields={"u": self.velocity_trial, "psi": self.strain_test},
299
314
  accumulate_dtype=float,
300
- output_dtype=float,
315
+ output=self._divergence_matrix,
301
316
  )
302
317
 
303
318
  # Project matrix to enforce boundary conditions
304
- divergence_mat_tmp = bsr_copy(divergence_mat)
305
- bsr_mm(alpha=-1.0, x=divergence_mat_tmp, y=self.vel_bd_projector, z=divergence_mat, beta=1.0)
319
+ divergence_mat_tmp = bsr_copy(self._divergence_matrix)
320
+ bsr_mm(alpha=-1.0, x=divergence_mat_tmp, y=self.vel_bd_projector, z=self._divergence_matrix, beta=1.0)
306
321
 
307
322
  # Solve unilateral incompressibility
308
323
  solve_incompressibility(
309
- divergence_mat,
324
+ self._divergence_matrix,
310
325
  inv_volume,
311
326
  self.pressure_field.dof_values,
312
327
  self.velocity_field.dof_values,
328
+ quiet=self._quiet,
313
329
  )
314
330
 
315
331
  # (A)PIC advection
316
- integrate(
332
+ fem.interpolate(
317
333
  update_particles,
318
334
  quadrature=pic,
319
335
  values={
@@ -328,17 +344,17 @@ class Example:
328
344
 
329
345
  # swap states
330
346
  (self.state_0, self.state_1) = (self.state_1, self.state_0)
347
+
348
+ fem.set_default_temporary_store(None)
331
349
 
332
350
  def render(self, is_live=False):
333
351
  with wp.ScopedTimer("render", active=True):
334
- time = 0.0 if is_live else self.sim_time
352
+ time = self.current_frame * self.frame_dt
335
353
 
336
354
  self.renderer.begin_frame(time)
337
355
  self.renderer.render(self.state_0)
338
356
  self.renderer.end_frame()
339
357
 
340
- self.sim_time += self.frame_dt
341
-
342
358
 
343
359
  if __name__ == "__main__":
344
360
  wp.set_module_options({"enable_backward": False})
@@ -348,8 +364,8 @@ if __name__ == "__main__":
348
364
 
349
365
  example = Example(stage_path)
350
366
 
351
- for i in range(example.frame_count):
352
- example.update(i)
367
+ for i in range(example.num_frames):
368
+ example.update()
353
369
  example.render()
354
370
 
355
371
  example.renderer.save()
@@ -7,28 +7,25 @@ This example simulates a convection-diffusion PDE using semi-Lagrangian advectio
7
7
 
8
8
  import argparse
9
9
 
10
- import warp as wp
11
-
12
- from warp.fem.types import *
13
- from warp.fem.geometry import Grid2D, Trimesh2D
14
- from warp.fem.field import make_test, make_trial
15
- from warp.fem.space import make_polynomial_space
16
- from warp.fem.domain import Cells
17
- from warp.fem.integrate import integrate, interpolate
18
- from warp.fem.operator import grad, integrand, lookup
19
-
20
- from bsr_utils import bsr_to_scipy
21
- from plot_utils import plot_surface
22
- from mesh_utils import gen_trimesh
23
-
24
- from scipy.sparse.linalg import factorized
25
-
26
- import matplotlib.pyplot as plt
27
- import matplotlib.animation as animation
28
-
29
10
 
30
- @integrand
31
- def initial_condition(domain: Domain, s: Sample):
11
+ import warp as wp
12
+ import warp.fem as fem
13
+
14
+ # Import example utilities
15
+ # Make sure that works both when imported as module and run as standalone file
16
+ try:
17
+ from .bsr_utils import bsr_cg
18
+ from .mesh_utils import gen_trimesh
19
+ from .plot_utils import Plot
20
+ except ImportError:
21
+ from bsr_utils import bsr_cg
22
+ from mesh_utils import gen_trimesh
23
+ from plot_utils import Plot
24
+
25
+
26
+ @fem.integrand
27
+ def initial_condition(domain: fem.Domain, s: fem.Sample):
28
+ """Initial condition: 1.0 in ]0.6, 0.4[ x ]0.2, 0.8[, 0.0 elsewhere"""
32
29
  pos = domain(s)
33
30
  if pos[0] > 0.4 and pos[0] < 0.6 and pos[1] > 0.2 and pos[1] < 0.8:
34
31
  return 1.0
@@ -42,13 +39,15 @@ def velocity(pos: wp.vec2, ang_vel: float):
42
39
  return wp.vec2(offset[1], -offset[0]) * ang_vel
43
40
 
44
41
 
45
- @integrand
46
- def inertia_form(s: Sample, phi: Field, psi: Field, dt: float):
42
+ @fem.integrand
43
+ def inertia_form(s: fem.Sample, phi: fem.Field, psi: fem.Field, dt: float):
47
44
  return phi(s) * psi(s) / dt
48
45
 
49
46
 
50
- @integrand
51
- def transported_inertia_form(s: Sample, domain: Domain, phi: Field, psi: Field, ang_vel: float, dt: float):
47
+ @fem.integrand
48
+ def transported_inertia_form(
49
+ s: fem.Sample, domain: fem.Domain, phi: fem.Field, psi: fem.Field, ang_vel: float, dt: float
50
+ ):
52
51
  pos = domain(s)
53
52
  vel = velocity(pos, ang_vel)
54
53
 
@@ -56,100 +55,105 @@ def transported_inertia_form(s: Sample, domain: Domain, phi: Field, psi: Field,
56
55
  conv_pos = pos - vel * dt
57
56
  # lookup opertor constructs a Sample from a world position.
58
57
  # the optional last argument provides a initial guess for the lookup
59
- conv_phi = phi(lookup(domain, conv_pos, s))
58
+ conv_phi = phi(fem.lookup(domain, conv_pos, s))
60
59
 
61
60
  return conv_phi * psi(s) / dt
62
61
 
63
62
 
64
- @integrand
63
+ @fem.integrand
65
64
  def diffusion_form(
66
- s: Sample,
67
- u: Field,
68
- v: Field,
65
+ s: fem.Sample,
66
+ u: fem.Field,
67
+ v: fem.Field,
69
68
  ):
70
69
  return wp.dot(
71
- grad(u, s),
72
- grad(v, s),
70
+ fem.grad(u, s),
71
+ fem.grad(v, s),
73
72
  )
74
73
 
75
74
 
76
- @integrand
77
- def diffusion_and_inertia_form(s: Sample, phi: Field, psi: Field, dt: float, nu: float):
75
+ @fem.integrand
76
+ def diffusion_and_inertia_form(s: fem.Sample, phi: fem.Field, psi: fem.Field, dt: float, nu: float):
78
77
  return inertia_form(s, phi, psi, dt) + nu * diffusion_form(s, phi, psi)
79
78
 
80
79
 
81
- if __name__ == "__main__":
82
- wp.init()
83
- wp.set_module_options({"enable_backward": False})
84
-
80
+ class Example:
85
81
  parser = argparse.ArgumentParser()
86
82
  parser.add_argument("--resolution", type=int, default=50)
87
83
  parser.add_argument("--degree", type=int, default=2)
88
- parser.add_argument("--n_frames", type=int, default=250)
84
+ parser.add_argument("--num_frames", type=int, default=250)
89
85
  parser.add_argument("--viscosity", type=float, default=0.001)
90
86
  parser.add_argument("--ang_vel", type=float, default=1.0)
91
87
  parser.add_argument("--tri_mesh", action="store_true", help="Use a triangular mesh")
92
- args = parser.parse_args()
93
-
94
- res = args.resolution
95
- dt = 1.0 / (args.ang_vel * res)
96
-
97
- if args.tri_mesh:
98
- positions, tri_vidx = gen_trimesh(res=vec2i(res))
99
- geo = Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
100
- else:
101
- geo = Grid2D(res=vec2i(res))
102
-
103
- domain = Cells(geometry=geo)
104
- scalar_space = make_polynomial_space(geo, degree=args.degree)
105
- quadrature = None
106
-
107
- # Initial condition
108
- phi0 = scalar_space.make_field()
109
- interpolate(initial_condition, dest=phi0)
110
-
111
- # Assemble and factorize diffusion and inertia matrix
112
- test = make_test(space=scalar_space, domain=domain)
113
- trial = make_trial(space=scalar_space, domain=domain)
114
- matrix = integrate(
115
- diffusion_and_inertia_form,
116
- quadrature=quadrature,
117
- fields={"phi": trial, "psi": test},
118
- values={"nu": args.viscosity, "dt": dt},
119
- )
120
- matrix_solve = factorized(bsr_to_scipy(matrix))
121
88
 
122
- results = [phi0.dof_values.numpy()]
123
- phik = phi0
89
+ def __init__(self, stage=None, quiet=False, args=None, **kwargs):
90
+ if args is None:
91
+ # Read args from kwargs, add default arg values from parser
92
+ args = argparse.Namespace(**kwargs)
93
+ args = Example.parser.parse_args(args=[], namespace=args)
94
+ self._args = args
95
+ self._quiet = quiet
96
+
97
+ res = args.resolution
98
+ self.sim_dt = 1.0 / (args.ang_vel * res)
99
+ self.current_frame = 0
100
+
101
+ if args.tri_mesh:
102
+ positions, tri_vidx = gen_trimesh(res=wp.vec2i(res))
103
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
104
+ else:
105
+ geo = fem.Grid2D(res=wp.vec2i(res))
106
+
107
+ domain = fem.Cells(geometry=geo)
108
+ scalar_space = fem.make_polynomial_space(geo, degree=args.degree)
109
+
110
+ # Initial condition
111
+ self._phi_field = scalar_space.make_field()
112
+ fem.interpolate(initial_condition, dest=self._phi_field)
113
+
114
+ # Assemble diffusion and inertia matrix
115
+ self._test = fem.make_test(space=scalar_space, domain=domain)
116
+ self._trial = fem.make_trial(space=scalar_space, domain=domain)
117
+ self._matrix = fem.integrate(
118
+ diffusion_and_inertia_form,
119
+ fields={"phi": self._trial, "psi": self._test},
120
+ values={"nu": args.viscosity, "dt": self.sim_dt},
121
+ output_dtype=float,
122
+ )
123
+
124
+ self.renderer = Plot(stage)
125
+ self.renderer.add_surface("phi", self._phi_field)
126
+
127
+ def update(self):
128
+ self.current_frame += 1
124
129
 
125
- for k in range(args.n_frames):
126
130
  # right-hand-side -- advected inertia
127
- rhs = integrate(
131
+ rhs = fem.integrate(
128
132
  transported_inertia_form,
129
- quadrature=quadrature,
130
- fields={"phi": phik, "psi": test},
131
- values={"ang_vel": args.ang_vel, "dt": dt},
133
+ fields={"phi": self._phi_field, "psi": self._test},
134
+ values={"ang_vel": self._args.ang_vel, "dt": self.sim_dt},
135
+ output_dtype=float,
132
136
  )
133
137
 
134
- # Solve using Scipy
135
- x = matrix_solve(rhs.numpy().flatten())
138
+ # Solve linear system
139
+ bsr_cg(self._matrix, x=self._phi_field.dof_values, b=rhs, quiet=self._quiet, tol=1.0e-12)
136
140
 
137
- phik.dof_values = x
138
- results.append(x)
141
+ def render(self):
142
+ self.renderer.begin_frame(time = self.current_frame * self.sim_dt)
143
+ self.renderer.add_surface("phi", self._phi_field)
144
+ self.renderer.end_frame()
139
145
 
140
- colormesh = plot_surface(phi0)
141
- ax = colormesh.axes
142
146
 
143
- def animate(i):
144
- ax.clear()
145
- phik.dof_values = results[i]
146
- return plot_surface(phik, axes=ax)
147
+ if __name__ == "__main__":
148
+ wp.init()
149
+ wp.set_module_options({"enable_backward": False})
147
150
 
148
- anim = animation.FuncAnimation(
149
- ax.figure,
150
- animate,
151
- interval=30,
152
- blit=False,
153
- frames=len(results),
154
- )
155
- plt.show()
151
+ args = Example.parser.parse_args()
152
+
153
+ example = Example(args=args)
154
+ for k in range(args.num_frames):
155
+ print(f"Frame {k}:")
156
+ example.update()
157
+ example.render()
158
+
159
+ example.renderer.plot()