warp-lang 1.2.2__py3-none-macosx_10_13_universal2.whl → 1.3.0__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 (193) hide show
  1. warp/__init__.py +8 -6
  2. warp/autograd.py +823 -0
  3. warp/bin/libwarp.dylib +0 -0
  4. warp/build.py +6 -2
  5. warp/builtins.py +1410 -886
  6. warp/codegen.py +503 -166
  7. warp/config.py +48 -18
  8. warp/context.py +400 -198
  9. warp/dlpack.py +8 -0
  10. warp/examples/assets/bunny.usd +0 -0
  11. warp/examples/benchmarks/benchmark_cloth_warp.py +1 -1
  12. warp/examples/benchmarks/benchmark_interop_torch.py +158 -0
  13. warp/examples/benchmarks/benchmark_launches.py +1 -1
  14. warp/examples/core/example_cupy.py +78 -0
  15. warp/examples/fem/example_apic_fluid.py +17 -36
  16. warp/examples/fem/example_burgers.py +9 -18
  17. warp/examples/fem/example_convection_diffusion.py +7 -17
  18. warp/examples/fem/example_convection_diffusion_dg.py +27 -47
  19. warp/examples/fem/example_deformed_geometry.py +11 -22
  20. warp/examples/fem/example_diffusion.py +7 -18
  21. warp/examples/fem/example_diffusion_3d.py +24 -28
  22. warp/examples/fem/example_diffusion_mgpu.py +7 -14
  23. warp/examples/fem/example_magnetostatics.py +190 -0
  24. warp/examples/fem/example_mixed_elasticity.py +111 -80
  25. warp/examples/fem/example_navier_stokes.py +30 -34
  26. warp/examples/fem/example_nonconforming_contact.py +290 -0
  27. warp/examples/fem/example_stokes.py +17 -32
  28. warp/examples/fem/example_stokes_transfer.py +12 -21
  29. warp/examples/fem/example_streamlines.py +350 -0
  30. warp/examples/fem/utils.py +936 -0
  31. warp/fabric.py +5 -2
  32. warp/fem/__init__.py +13 -3
  33. warp/fem/cache.py +161 -11
  34. warp/fem/dirichlet.py +37 -28
  35. warp/fem/domain.py +105 -14
  36. warp/fem/field/__init__.py +14 -3
  37. warp/fem/field/field.py +454 -11
  38. warp/fem/field/nodal_field.py +33 -18
  39. warp/fem/geometry/deformed_geometry.py +50 -15
  40. warp/fem/geometry/hexmesh.py +12 -24
  41. warp/fem/geometry/nanogrid.py +106 -31
  42. warp/fem/geometry/quadmesh_2d.py +6 -11
  43. warp/fem/geometry/tetmesh.py +103 -61
  44. warp/fem/geometry/trimesh_2d.py +98 -47
  45. warp/fem/integrate.py +231 -186
  46. warp/fem/operator.py +14 -9
  47. warp/fem/quadrature/pic_quadrature.py +35 -9
  48. warp/fem/quadrature/quadrature.py +119 -32
  49. warp/fem/space/basis_space.py +98 -22
  50. warp/fem/space/collocated_function_space.py +3 -1
  51. warp/fem/space/function_space.py +7 -2
  52. warp/fem/space/grid_2d_function_space.py +3 -3
  53. warp/fem/space/grid_3d_function_space.py +4 -4
  54. warp/fem/space/hexmesh_function_space.py +3 -2
  55. warp/fem/space/nanogrid_function_space.py +12 -14
  56. warp/fem/space/partition.py +45 -47
  57. warp/fem/space/restriction.py +19 -16
  58. warp/fem/space/shape/cube_shape_function.py +91 -3
  59. warp/fem/space/shape/shape_function.py +7 -0
  60. warp/fem/space/shape/square_shape_function.py +32 -0
  61. warp/fem/space/shape/tet_shape_function.py +11 -7
  62. warp/fem/space/shape/triangle_shape_function.py +10 -1
  63. warp/fem/space/topology.py +116 -42
  64. warp/fem/types.py +8 -1
  65. warp/fem/utils.py +301 -83
  66. warp/native/array.h +16 -0
  67. warp/native/builtin.h +0 -15
  68. warp/native/cuda_util.cpp +14 -6
  69. warp/native/exports.h +1348 -1308
  70. warp/native/quat.h +79 -0
  71. warp/native/rand.h +27 -4
  72. warp/native/sparse.cpp +83 -81
  73. warp/native/sparse.cu +381 -453
  74. warp/native/vec.h +64 -0
  75. warp/native/volume.cpp +40 -49
  76. warp/native/volume_builder.cu +2 -3
  77. warp/native/volume_builder.h +12 -17
  78. warp/native/warp.cu +3 -3
  79. warp/native/warp.h +69 -59
  80. warp/render/render_opengl.py +17 -9
  81. warp/sim/articulation.py +117 -17
  82. warp/sim/collide.py +35 -29
  83. warp/sim/model.py +123 -18
  84. warp/sim/render.py +3 -1
  85. warp/sparse.py +867 -203
  86. warp/stubs.py +312 -541
  87. warp/tape.py +29 -1
  88. warp/tests/disabled_kinematics.py +1 -1
  89. warp/tests/test_adam.py +1 -1
  90. warp/tests/test_arithmetic.py +1 -1
  91. warp/tests/test_array.py +58 -1
  92. warp/tests/test_array_reduce.py +1 -1
  93. warp/tests/test_async.py +1 -1
  94. warp/tests/test_atomic.py +1 -1
  95. warp/tests/test_bool.py +1 -1
  96. warp/tests/test_builtins_resolution.py +1 -1
  97. warp/tests/test_bvh.py +6 -1
  98. warp/tests/test_closest_point_edge_edge.py +1 -1
  99. warp/tests/test_codegen.py +66 -1
  100. warp/tests/test_compile_consts.py +1 -1
  101. warp/tests/test_conditional.py +1 -1
  102. warp/tests/test_copy.py +1 -1
  103. warp/tests/test_ctypes.py +1 -1
  104. warp/tests/test_dense.py +1 -1
  105. warp/tests/test_devices.py +1 -1
  106. warp/tests/test_dlpack.py +1 -1
  107. warp/tests/test_examples.py +33 -4
  108. warp/tests/test_fabricarray.py +5 -2
  109. warp/tests/test_fast_math.py +1 -1
  110. warp/tests/test_fem.py +213 -6
  111. warp/tests/test_fp16.py +1 -1
  112. warp/tests/test_func.py +1 -1
  113. warp/tests/test_future_annotations.py +90 -0
  114. warp/tests/test_generics.py +1 -1
  115. warp/tests/test_grad.py +1 -1
  116. warp/tests/test_grad_customs.py +1 -1
  117. warp/tests/test_grad_debug.py +247 -0
  118. warp/tests/test_hash_grid.py +6 -1
  119. warp/tests/test_implicit_init.py +354 -0
  120. warp/tests/test_import.py +1 -1
  121. warp/tests/test_indexedarray.py +1 -1
  122. warp/tests/test_intersect.py +1 -1
  123. warp/tests/test_jax.py +1 -1
  124. warp/tests/test_large.py +1 -1
  125. warp/tests/test_launch.py +1 -1
  126. warp/tests/test_lerp.py +1 -1
  127. warp/tests/test_linear_solvers.py +1 -1
  128. warp/tests/test_lvalue.py +1 -1
  129. warp/tests/test_marching_cubes.py +5 -2
  130. warp/tests/test_mat.py +34 -35
  131. warp/tests/test_mat_lite.py +2 -1
  132. warp/tests/test_mat_scalar_ops.py +1 -1
  133. warp/tests/test_math.py +1 -1
  134. warp/tests/test_matmul.py +20 -16
  135. warp/tests/test_matmul_lite.py +1 -1
  136. warp/tests/test_mempool.py +1 -1
  137. warp/tests/test_mesh.py +5 -2
  138. warp/tests/test_mesh_query_aabb.py +1 -1
  139. warp/tests/test_mesh_query_point.py +1 -1
  140. warp/tests/test_mesh_query_ray.py +1 -1
  141. warp/tests/test_mlp.py +1 -1
  142. warp/tests/test_model.py +1 -1
  143. warp/tests/test_module_hashing.py +77 -1
  144. warp/tests/test_modules_lite.py +1 -1
  145. warp/tests/test_multigpu.py +1 -1
  146. warp/tests/test_noise.py +1 -1
  147. warp/tests/test_operators.py +1 -1
  148. warp/tests/test_options.py +1 -1
  149. warp/tests/test_overwrite.py +542 -0
  150. warp/tests/test_peer.py +1 -1
  151. warp/tests/test_pinned.py +1 -1
  152. warp/tests/test_print.py +1 -1
  153. warp/tests/test_quat.py +15 -1
  154. warp/tests/test_rand.py +1 -1
  155. warp/tests/test_reload.py +1 -1
  156. warp/tests/test_rounding.py +1 -1
  157. warp/tests/test_runlength_encode.py +1 -1
  158. warp/tests/test_scalar_ops.py +95 -0
  159. warp/tests/test_sim_grad.py +1 -1
  160. warp/tests/test_sim_kinematics.py +1 -1
  161. warp/tests/test_smoothstep.py +1 -1
  162. warp/tests/test_sparse.py +82 -15
  163. warp/tests/test_spatial.py +1 -1
  164. warp/tests/test_special_values.py +2 -11
  165. warp/tests/test_streams.py +11 -1
  166. warp/tests/test_struct.py +1 -1
  167. warp/tests/test_tape.py +1 -1
  168. warp/tests/test_torch.py +194 -1
  169. warp/tests/test_transient_module.py +1 -1
  170. warp/tests/test_types.py +1 -1
  171. warp/tests/test_utils.py +1 -1
  172. warp/tests/test_vec.py +15 -63
  173. warp/tests/test_vec_lite.py +2 -1
  174. warp/tests/test_vec_scalar_ops.py +65 -1
  175. warp/tests/test_verify_fp.py +1 -1
  176. warp/tests/test_volume.py +28 -2
  177. warp/tests/test_volume_write.py +1 -1
  178. warp/tests/unittest_serial.py +1 -1
  179. warp/tests/unittest_suites.py +9 -1
  180. warp/tests/walkthrough_debug.py +1 -1
  181. warp/thirdparty/unittest_parallel.py +2 -5
  182. warp/torch.py +103 -41
  183. warp/types.py +341 -224
  184. warp/utils.py +11 -2
  185. {warp_lang-1.2.2.dist-info → warp_lang-1.3.0.dist-info}/METADATA +99 -46
  186. warp_lang-1.3.0.dist-info/RECORD +368 -0
  187. warp/examples/fem/bsr_utils.py +0 -378
  188. warp/examples/fem/mesh_utils.py +0 -133
  189. warp/examples/fem/plot_utils.py +0 -292
  190. warp_lang-1.2.2.dist-info/RECORD +0 -359
  191. {warp_lang-1.2.2.dist-info → warp_lang-1.3.0.dist-info}/LICENSE.md +0 -0
  192. {warp_lang-1.2.2.dist-info → warp_lang-1.3.0.dist-info}/WHEEL +0 -0
  193. {warp_lang-1.2.2.dist-info → warp_lang-1.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,350 @@
1
+ # Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ ###########################################################################
9
+ # Example Streamlines
10
+ #
11
+ # Shows how to generate 3D streamlines by tracing through a velocity field
12
+ # using the `warp.fem.lookup` operator.
13
+ # Also illustrates using `warp.fem.Subdomain` to define subsets of elements.
14
+ #
15
+ ###########################################################################
16
+
17
+ import numpy as np
18
+
19
+ import warp as wp
20
+ import warp.examples.fem.utils as fem_example_utils
21
+ import warp.fem as fem
22
+ from warp.examples.fem.example_apic_fluid import divergence_form, solve_incompressibility
23
+
24
+
25
+ @fem.integrand
26
+ def classify_boundary_sides(
27
+ s: fem.Sample,
28
+ domain: fem.Domain,
29
+ outflow: wp.array(dtype=int),
30
+ freeslip: wp.array(dtype=int),
31
+ inflow: wp.array(dtype=int),
32
+ ):
33
+ x = fem.position(domain, s)
34
+ n = fem.normal(domain, s)
35
+
36
+ if n[0] < -0.5:
37
+ # left side
38
+ inflow[s.qp_index] = 1
39
+ elif n[0] > 0.5:
40
+ if x[1] > 0.33 or x[2] < 0.33:
41
+ # right side, top
42
+ freeslip[s.qp_index] = 1
43
+ else:
44
+ # right side, bottom
45
+ outflow[s.qp_index] = 1
46
+ else:
47
+ freeslip[s.qp_index] = 1
48
+
49
+
50
+ @fem.integrand
51
+ def inflow_velocity(
52
+ s: fem.Sample,
53
+ domain: fem.Domain,
54
+ ):
55
+ n = fem.normal(domain, s)
56
+ return -n
57
+
58
+
59
+ @fem.integrand
60
+ def noslip_projector_form(
61
+ s: fem.Sample,
62
+ u: fem.Field,
63
+ v: fem.Field,
64
+ ):
65
+ return wp.dot(u(s), v(s))
66
+
67
+
68
+ @fem.integrand
69
+ def freeslip_projector_form(
70
+ s: fem.Sample,
71
+ domain: fem.Domain,
72
+ u: fem.Field,
73
+ v: fem.Field,
74
+ ):
75
+ n = fem.normal(domain, s)
76
+ return wp.dot(u(s), n) * wp.dot(n, v(s))
77
+
78
+
79
+ @fem.integrand
80
+ def mass_form(
81
+ s: fem.Sample,
82
+ u: fem.Field,
83
+ v: fem.Field,
84
+ ):
85
+ return u(s) * v(s)
86
+
87
+
88
+ @fem.integrand
89
+ def spawn_streamlines(s: fem.Sample, domain: fem.Domain, jitter: float):
90
+ rng = wp.rand_init(s.qp_index)
91
+ random_offset = wp.vec3(wp.randf(rng), wp.randf(rng), wp.randf(rng)) - wp.vec3(0.5)
92
+
93
+ # remove jistter along normal
94
+ n = fem.normal(domain, s)
95
+ random_offset -= wp.dot(random_offset, n) * n
96
+
97
+ return domain(s) + jitter * random_offset
98
+
99
+
100
+ @fem.integrand
101
+ def gen_streamlines(
102
+ s: fem.Sample,
103
+ domain: fem.Domain,
104
+ u: fem.Field,
105
+ spawn_points: wp.array(dtype=wp.vec3),
106
+ point_count: int,
107
+ dx: float,
108
+ pos: wp.array2d(dtype=wp.vec3),
109
+ speed: wp.array2d(dtype=float),
110
+ ):
111
+ idx = s.qp_index
112
+
113
+ p = spawn_points[idx]
114
+ s = fem.lookup(domain, p)
115
+ for k in range(point_count):
116
+ v = u(s)
117
+ pos[idx, k] = p
118
+ speed[idx, k] = wp.length(v)
119
+
120
+ flow_dir = wp.normalize(v)
121
+ adv_p = p + flow_dir * dx
122
+ adv_s = fem.lookup(domain, adv_p, s)
123
+
124
+ if adv_s.element_index != fem.NULL_ELEMENT_INDEX:
125
+ # if the lookup result position is different from adv_p,
126
+ # it means we have been projected back onto the domain;
127
+ # align back with flow and terminate streamline
128
+ new_p = domain(adv_s)
129
+ if wp.length_sq(new_p - adv_p) > 0.000001:
130
+ p = p + wp.dot(new_p - p, flow_dir) * flow_dir
131
+ s = fem.lookup(domain, p, s)
132
+ dx = 0.0
133
+ else:
134
+ s = adv_s
135
+ p = new_p
136
+
137
+
138
+ class Example:
139
+ def __init__(self, quiet=False, degree=2, resolution=16, mesh="grid", headless: bool = False):
140
+ self._quiet = quiet
141
+ self._degree = degree
142
+
143
+ self._streamline_dx = 0.5 / resolution
144
+ self._streamline_point_count = 4 * resolution
145
+
146
+ res = wp.vec3i(resolution)
147
+
148
+ if mesh == "tet":
149
+ pos, tet_vtx_indices = fem_example_utils.gen_tetmesh(
150
+ res=res,
151
+ )
152
+ self._geo = fem.Tetmesh(tet_vtx_indices, pos, build_bvh=True)
153
+ elif mesh == "nano":
154
+ volume = fem_example_utils.gen_volume(
155
+ res=res,
156
+ )
157
+ self._geo = fem.Nanogrid(volume)
158
+ else:
159
+ self._geo = fem.Grid3D(
160
+ res=res,
161
+ )
162
+
163
+ # Mark sides with boundary conditions that should apply
164
+ boundary = fem.BoundarySides(self._geo)
165
+ inflow_mask = wp.zeros(shape=boundary.element_count(), dtype=int)
166
+ freeslip_mask = wp.zeros(shape=boundary.element_count(), dtype=int)
167
+ outflow_mask = wp.zeros(shape=boundary.element_count(), dtype=int)
168
+
169
+ fem.interpolate(
170
+ classify_boundary_sides,
171
+ quadrature=fem.RegularQuadrature(boundary, order=0),
172
+ values={"outflow": outflow_mask, "freeslip": freeslip_mask, "inflow": inflow_mask},
173
+ )
174
+
175
+ self._inflow = fem.Subdomain(boundary, element_mask=inflow_mask)
176
+ self._freeslip = fem.Subdomain(boundary, element_mask=freeslip_mask)
177
+ self._outflow = fem.Subdomain(boundary, element_mask=outflow_mask)
178
+
179
+ self.plot = fem_example_utils.Plot()
180
+
181
+ self.renderer = None
182
+ if not headless:
183
+ try:
184
+ self.renderer = wp.render.OpenGLRenderer(
185
+ camera_pos=(2.0, 0.5, 3.0),
186
+ camera_front=(-0.66, 0.0, -1.0),
187
+ draw_axis=False,
188
+ )
189
+ except Exception as err:
190
+ wp.utils.warn(f"Could not initialize OpenGL renderer: {err}")
191
+ pass
192
+
193
+ def step(self):
194
+ self._generate_incompressible_flow()
195
+
196
+ # first generate spawn points for the streamlines
197
+ # we do this by regularly sampling the inflow boundary with a small amount of jitter
198
+ streamline_spawn = fem.RegularQuadrature(
199
+ domain=self._inflow, order=self._degree, family=fem.Polynomial.GAUSS_LEGENDRE
200
+ )
201
+ n_streamlines = streamline_spawn.total_point_count()
202
+ spawn_points = wp.array(dtype=wp.vec3, shape=n_streamlines)
203
+
204
+ jitter_amount = self._streamline_dx / self._degree
205
+ fem.interpolate(
206
+ spawn_streamlines, dest=spawn_points, quadrature=streamline_spawn, values={"jitter": jitter_amount}
207
+ )
208
+
209
+ # now forward-trace the velocity field to generate the streamlines
210
+ # here we use a fixed number of points per streamline, otherwise we would need to
211
+ # do a first pass to count points, then array_scan the offsets, then a second pass
212
+ # to populate the per-point data
213
+
214
+ point_count = self._streamline_point_count
215
+ points = wp.array(dtype=wp.vec3, shape=(n_streamlines, point_count))
216
+ speed = wp.array(dtype=float, shape=(n_streamlines, point_count))
217
+
218
+ fem.interpolate(
219
+ gen_streamlines,
220
+ domain=fem.Cells(self._geo),
221
+ dim=n_streamlines,
222
+ fields={"u": self.velocity_field},
223
+ values={
224
+ "spawn_points": spawn_points,
225
+ "point_count": self._streamline_point_count,
226
+ "dx": self._streamline_dx,
227
+ "pos": points,
228
+ "speed": speed,
229
+ },
230
+ )
231
+
232
+ self._points = points
233
+ self._speed = speed
234
+
235
+ def render(self):
236
+ # self.renderer.add_field("solution", self.pressure_field)
237
+ self.plot.add_field("pressure", self.pressure_field)
238
+ self.plot.add_field("velocity", self.velocity_field)
239
+
240
+ if self.renderer is not None:
241
+ streamline_count = self._points.shape[0]
242
+ point_count = self._streamline_point_count
243
+
244
+ vertices = self._points.flatten().numpy()
245
+
246
+ line_offsets = np.arange(streamline_count) * point_count
247
+ indices_beg = np.arange(point_count - 1)[np.newaxis, :] + line_offsets[:, np.newaxis]
248
+ indices_end = indices_beg + 1
249
+ indices = np.vstack((indices_beg.flatten(), indices_end.flatten())).T.flatten()
250
+
251
+ colors = self._speed.numpy()[:, :-1].flatten()
252
+ colors = [wp.render.bourke_color_map(0.0, 3.0, c) for c in colors]
253
+
254
+ self.renderer.begin_frame(0)
255
+ self.renderer.render_line_list("streamlines", vertices, indices)
256
+ self.renderer.render_line_list("streamlines", vertices, indices, colors)
257
+
258
+ self.renderer.end_frame()
259
+
260
+ def _generate_incompressible_flow(self):
261
+ # Function spaces for velocity, scalars and pressure (Pk / Pk / Pk-1)
262
+ u_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree, dtype=wp.vec3)
263
+ s_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree, dtype=float)
264
+ p_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree - 1, dtype=float)
265
+
266
+ self.pressure_field = p_space.make_field()
267
+ self.velocity_field = u_space.make_field()
268
+
269
+ # Boundary condition projector and matrices
270
+ inflow_test = fem.make_test(u_space, domain=self._inflow)
271
+ inflow_trial = fem.make_trial(u_space, domain=self._inflow)
272
+ dirichlet_projector = fem.integrate(
273
+ noslip_projector_form, fields={"u": inflow_test, "v": inflow_trial}, nodal=True, output_dtype=float
274
+ )
275
+
276
+ freeslip_test = fem.make_test(u_space, domain=self._freeslip)
277
+ freeslip_trial = fem.make_trial(u_space, domain=self._freeslip)
278
+ dirichlet_projector += fem.integrate(
279
+ freeslip_projector_form,
280
+ fields={"u": freeslip_test, "v": freeslip_trial},
281
+ nodal=True,
282
+ output_dtype=float,
283
+ )
284
+ fem.normalize_dirichlet_projector(dirichlet_projector)
285
+
286
+ # Initialize velocity field with BC
287
+ fem.interpolate(inflow_velocity, dest=fem.make_restriction(self.velocity_field, domain=self._inflow))
288
+
289
+ # (Diagonal) mass matrix
290
+ rho_test = fem.make_test(s_space)
291
+ rho_trial = fem.make_trial(s_space)
292
+ inv_mass_matrix = fem.integrate(
293
+ mass_form, fields={"u": rho_trial, "v": rho_test}, nodal=True, output_dtype=float
294
+ )
295
+ fem_example_utils.invert_diagonal_bsr_matrix(inv_mass_matrix)
296
+
297
+ # Assemble divergence operator matrix
298
+ p_test = fem.make_test(p_space)
299
+ u_trial = fem.make_trial(u_space)
300
+ divergence_matrix = fem.integrate(
301
+ divergence_form,
302
+ fields={"u": u_trial, "psi": p_test},
303
+ output_dtype=float,
304
+ )
305
+
306
+ # Solve incompressibility
307
+ solve_incompressibility(
308
+ divergence_matrix,
309
+ dirichlet_projector,
310
+ inv_mass_matrix.values,
311
+ self.pressure_field.dof_values,
312
+ self.velocity_field.dof_values,
313
+ quiet=self._quiet,
314
+ )
315
+
316
+
317
+ if __name__ == "__main__":
318
+ import argparse
319
+
320
+ wp.set_module_options({"enable_backward": False})
321
+
322
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
323
+ parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
324
+ parser.add_argument("--resolution", type=int, default=8, help="Grid resolution.")
325
+ parser.add_argument("--degree", type=int, default=2, help="Polynomial degree of shape functions.")
326
+ parser.add_argument("--mesh", choices=("grid", "tet", "hex", "nano"), default="grid", help="Mesh type.")
327
+ parser.add_argument(
328
+ "--headless",
329
+ action="store_true",
330
+ help="Run in headless mode, suppressing the opening of any graphical windows.",
331
+ )
332
+ parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
333
+
334
+ args = parser.parse_known_args()[0]
335
+
336
+ with wp.ScopedDevice(args.device):
337
+ example = Example(
338
+ quiet=args.quiet, degree=args.degree, resolution=args.resolution, mesh=args.mesh, headless=args.headless
339
+ )
340
+
341
+ example.step()
342
+ example.render()
343
+
344
+ if not args.headless:
345
+ example.plot.plot(
346
+ {
347
+ "velocity": {"streamlines": {"density": 2}},
348
+ "pressure": {"contours": {}},
349
+ }
350
+ )