warp-lang 1.2.1__py3-none-win_amd64.whl → 1.3.0__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 (194) hide show
  1. warp/__init__.py +8 -6
  2. warp/autograd.py +823 -0
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +6 -2
  6. warp/builtins.py +1410 -886
  7. warp/codegen.py +503 -166
  8. warp/config.py +48 -18
  9. warp/context.py +401 -199
  10. warp/dlpack.py +8 -0
  11. warp/examples/assets/bunny.usd +0 -0
  12. warp/examples/benchmarks/benchmark_cloth_warp.py +1 -1
  13. warp/examples/benchmarks/benchmark_interop_torch.py +158 -0
  14. warp/examples/benchmarks/benchmark_launches.py +1 -1
  15. warp/examples/core/example_cupy.py +78 -0
  16. warp/examples/fem/example_apic_fluid.py +17 -36
  17. warp/examples/fem/example_burgers.py +9 -18
  18. warp/examples/fem/example_convection_diffusion.py +7 -17
  19. warp/examples/fem/example_convection_diffusion_dg.py +27 -47
  20. warp/examples/fem/example_deformed_geometry.py +11 -22
  21. warp/examples/fem/example_diffusion.py +7 -18
  22. warp/examples/fem/example_diffusion_3d.py +24 -28
  23. warp/examples/fem/example_diffusion_mgpu.py +7 -14
  24. warp/examples/fem/example_magnetostatics.py +190 -0
  25. warp/examples/fem/example_mixed_elasticity.py +111 -80
  26. warp/examples/fem/example_navier_stokes.py +30 -34
  27. warp/examples/fem/example_nonconforming_contact.py +290 -0
  28. warp/examples/fem/example_stokes.py +17 -32
  29. warp/examples/fem/example_stokes_transfer.py +12 -21
  30. warp/examples/fem/example_streamlines.py +350 -0
  31. warp/examples/fem/utils.py +936 -0
  32. warp/fabric.py +5 -2
  33. warp/fem/__init__.py +13 -3
  34. warp/fem/cache.py +161 -11
  35. warp/fem/dirichlet.py +37 -28
  36. warp/fem/domain.py +105 -14
  37. warp/fem/field/__init__.py +14 -3
  38. warp/fem/field/field.py +454 -11
  39. warp/fem/field/nodal_field.py +33 -18
  40. warp/fem/geometry/deformed_geometry.py +50 -15
  41. warp/fem/geometry/hexmesh.py +12 -24
  42. warp/fem/geometry/nanogrid.py +106 -31
  43. warp/fem/geometry/quadmesh_2d.py +6 -11
  44. warp/fem/geometry/tetmesh.py +103 -61
  45. warp/fem/geometry/trimesh_2d.py +98 -47
  46. warp/fem/integrate.py +231 -186
  47. warp/fem/operator.py +14 -9
  48. warp/fem/quadrature/pic_quadrature.py +35 -9
  49. warp/fem/quadrature/quadrature.py +119 -32
  50. warp/fem/space/basis_space.py +98 -22
  51. warp/fem/space/collocated_function_space.py +3 -1
  52. warp/fem/space/function_space.py +7 -2
  53. warp/fem/space/grid_2d_function_space.py +3 -3
  54. warp/fem/space/grid_3d_function_space.py +4 -4
  55. warp/fem/space/hexmesh_function_space.py +3 -2
  56. warp/fem/space/nanogrid_function_space.py +12 -14
  57. warp/fem/space/partition.py +45 -47
  58. warp/fem/space/restriction.py +19 -16
  59. warp/fem/space/shape/cube_shape_function.py +91 -3
  60. warp/fem/space/shape/shape_function.py +7 -0
  61. warp/fem/space/shape/square_shape_function.py +32 -0
  62. warp/fem/space/shape/tet_shape_function.py +11 -7
  63. warp/fem/space/shape/triangle_shape_function.py +10 -1
  64. warp/fem/space/topology.py +116 -42
  65. warp/fem/types.py +8 -1
  66. warp/fem/utils.py +301 -83
  67. warp/native/array.h +16 -0
  68. warp/native/builtin.h +0 -15
  69. warp/native/cuda_util.cpp +14 -6
  70. warp/native/exports.h +1348 -1308
  71. warp/native/quat.h +79 -0
  72. warp/native/rand.h +27 -4
  73. warp/native/sparse.cpp +83 -81
  74. warp/native/sparse.cu +381 -453
  75. warp/native/vec.h +64 -0
  76. warp/native/volume.cpp +40 -49
  77. warp/native/volume_builder.cu +2 -3
  78. warp/native/volume_builder.h +12 -17
  79. warp/native/warp.cu +3 -3
  80. warp/native/warp.h +69 -59
  81. warp/render/render_opengl.py +17 -9
  82. warp/sim/articulation.py +117 -17
  83. warp/sim/collide.py +35 -29
  84. warp/sim/model.py +123 -18
  85. warp/sim/render.py +3 -1
  86. warp/sparse.py +867 -203
  87. warp/stubs.py +312 -541
  88. warp/tape.py +29 -1
  89. warp/tests/disabled_kinematics.py +1 -1
  90. warp/tests/test_adam.py +1 -1
  91. warp/tests/test_arithmetic.py +1 -1
  92. warp/tests/test_array.py +58 -1
  93. warp/tests/test_array_reduce.py +1 -1
  94. warp/tests/test_async.py +1 -1
  95. warp/tests/test_atomic.py +1 -1
  96. warp/tests/test_bool.py +1 -1
  97. warp/tests/test_builtins_resolution.py +1 -1
  98. warp/tests/test_bvh.py +6 -1
  99. warp/tests/test_closest_point_edge_edge.py +1 -1
  100. warp/tests/test_codegen.py +66 -1
  101. warp/tests/test_compile_consts.py +1 -1
  102. warp/tests/test_conditional.py +1 -1
  103. warp/tests/test_copy.py +1 -1
  104. warp/tests/test_ctypes.py +1 -1
  105. warp/tests/test_dense.py +1 -1
  106. warp/tests/test_devices.py +1 -1
  107. warp/tests/test_dlpack.py +1 -1
  108. warp/tests/test_examples.py +33 -4
  109. warp/tests/test_fabricarray.py +5 -2
  110. warp/tests/test_fast_math.py +1 -1
  111. warp/tests/test_fem.py +213 -6
  112. warp/tests/test_fp16.py +1 -1
  113. warp/tests/test_func.py +1 -1
  114. warp/tests/test_future_annotations.py +90 -0
  115. warp/tests/test_generics.py +1 -1
  116. warp/tests/test_grad.py +1 -1
  117. warp/tests/test_grad_customs.py +1 -1
  118. warp/tests/test_grad_debug.py +247 -0
  119. warp/tests/test_hash_grid.py +6 -1
  120. warp/tests/test_implicit_init.py +354 -0
  121. warp/tests/test_import.py +1 -1
  122. warp/tests/test_indexedarray.py +1 -1
  123. warp/tests/test_intersect.py +1 -1
  124. warp/tests/test_jax.py +1 -1
  125. warp/tests/test_large.py +1 -1
  126. warp/tests/test_launch.py +1 -1
  127. warp/tests/test_lerp.py +1 -1
  128. warp/tests/test_linear_solvers.py +1 -1
  129. warp/tests/test_lvalue.py +1 -1
  130. warp/tests/test_marching_cubes.py +5 -2
  131. warp/tests/test_mat.py +34 -35
  132. warp/tests/test_mat_lite.py +2 -1
  133. warp/tests/test_mat_scalar_ops.py +1 -1
  134. warp/tests/test_math.py +1 -1
  135. warp/tests/test_matmul.py +20 -16
  136. warp/tests/test_matmul_lite.py +1 -1
  137. warp/tests/test_mempool.py +1 -1
  138. warp/tests/test_mesh.py +5 -2
  139. warp/tests/test_mesh_query_aabb.py +1 -1
  140. warp/tests/test_mesh_query_point.py +1 -1
  141. warp/tests/test_mesh_query_ray.py +1 -1
  142. warp/tests/test_mlp.py +1 -1
  143. warp/tests/test_model.py +1 -1
  144. warp/tests/test_module_hashing.py +77 -1
  145. warp/tests/test_modules_lite.py +1 -1
  146. warp/tests/test_multigpu.py +1 -1
  147. warp/tests/test_noise.py +1 -1
  148. warp/tests/test_operators.py +1 -1
  149. warp/tests/test_options.py +1 -1
  150. warp/tests/test_overwrite.py +542 -0
  151. warp/tests/test_peer.py +1 -1
  152. warp/tests/test_pinned.py +1 -1
  153. warp/tests/test_print.py +1 -1
  154. warp/tests/test_quat.py +15 -1
  155. warp/tests/test_rand.py +1 -1
  156. warp/tests/test_reload.py +1 -1
  157. warp/tests/test_rounding.py +1 -1
  158. warp/tests/test_runlength_encode.py +1 -1
  159. warp/tests/test_scalar_ops.py +95 -0
  160. warp/tests/test_sim_grad.py +1 -1
  161. warp/tests/test_sim_kinematics.py +1 -1
  162. warp/tests/test_smoothstep.py +1 -1
  163. warp/tests/test_sparse.py +82 -15
  164. warp/tests/test_spatial.py +1 -1
  165. warp/tests/test_special_values.py +2 -11
  166. warp/tests/test_streams.py +11 -1
  167. warp/tests/test_struct.py +1 -1
  168. warp/tests/test_tape.py +1 -1
  169. warp/tests/test_torch.py +194 -1
  170. warp/tests/test_transient_module.py +1 -1
  171. warp/tests/test_types.py +1 -1
  172. warp/tests/test_utils.py +1 -1
  173. warp/tests/test_vec.py +15 -63
  174. warp/tests/test_vec_lite.py +2 -1
  175. warp/tests/test_vec_scalar_ops.py +122 -39
  176. warp/tests/test_verify_fp.py +1 -1
  177. warp/tests/test_volume.py +28 -2
  178. warp/tests/test_volume_write.py +1 -1
  179. warp/tests/unittest_serial.py +1 -1
  180. warp/tests/unittest_suites.py +9 -1
  181. warp/tests/walkthrough_debug.py +1 -1
  182. warp/thirdparty/unittest_parallel.py +2 -5
  183. warp/torch.py +103 -41
  184. warp/types.py +344 -227
  185. warp/utils.py +11 -2
  186. {warp_lang-1.2.1.dist-info → warp_lang-1.3.0.dist-info}/METADATA +99 -46
  187. warp_lang-1.3.0.dist-info/RECORD +368 -0
  188. warp/examples/fem/bsr_utils.py +0 -378
  189. warp/examples/fem/mesh_utils.py +0 -133
  190. warp/examples/fem/plot_utils.py +0 -292
  191. warp_lang-1.2.1.dist-info/RECORD +0 -359
  192. {warp_lang-1.2.1.dist-info → warp_lang-1.3.0.dist-info}/LICENSE.md +0 -0
  193. {warp_lang-1.2.1.dist-info → warp_lang-1.3.0.dist-info}/WHEEL +0 -0
  194. {warp_lang-1.2.1.dist-info → warp_lang-1.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,290 @@
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 Nonconforming Contact
10
+ #
11
+ # This example demonstrates using nonconforming fields (warp.fem.NonconformingField)
12
+ # to solve a no-slip contact problem between two elastic bodies discretized separately.
13
+ #
14
+ # Div[ E: D(u) ] = g over each body
15
+ # u_top = u_bottom along the contact surface (top body bottom boundary)
16
+ # u_bottom = 0 along the bottom boundary of the bottom body
17
+ #
18
+ # with E the rank-4 elasticity tensor
19
+ #
20
+ # Below we use a simple staggered scheme for solving bodies iteratively,
21
+ # but more robust methods could be considered (e.g. Augmented Lagrangian)
22
+ ###########################################################################
23
+
24
+ import numpy as np
25
+
26
+ import warp as wp
27
+ import warp.examples.fem.utils as fem_example_utils
28
+ import warp.fem as fem
29
+
30
+
31
+ @wp.func
32
+ def compute_stress(tau: wp.mat22, E: wp.mat33):
33
+ """Strain to stress computation (using Voigt notation to drop tensor order)"""
34
+ tau_sym = wp.vec3(tau[0, 0], tau[1, 1], tau[0, 1] + tau[1, 0])
35
+ sig_sym = E * tau_sym
36
+ return wp.mat22(sig_sym[0], 0.5 * sig_sym[2], 0.5 * sig_sym[2], sig_sym[1])
37
+
38
+
39
+ @fem.integrand
40
+ def stress_form(s: fem.Sample, u: fem.Field, tau: fem.Field, E: wp.mat33):
41
+ """Stress inside body: (E : D(u)) : tau"""
42
+ return wp.ddot(tau(s), compute_stress(fem.D(u, s), E))
43
+
44
+
45
+ @fem.integrand
46
+ def boundary_stress_form(
47
+ s: fem.Sample,
48
+ domain: fem.Domain,
49
+ u: fem.Field,
50
+ tau: fem.Field,
51
+ ):
52
+ """Stress on boundary: u' tau n"""
53
+ return wp.dot(tau(s) * fem.normal(domain, s), u(s))
54
+
55
+
56
+ @fem.integrand
57
+ def symmetric_grad_form(
58
+ s: fem.Sample,
59
+ u: fem.Field,
60
+ tau: fem.Field,
61
+ ):
62
+ """Symmetric part of gradient of displacement: D(u) : tau"""
63
+ return wp.ddot(tau(s), fem.D(u, s))
64
+
65
+
66
+ @fem.integrand
67
+ def gravity_form(
68
+ s: fem.Sample,
69
+ v: fem.Field,
70
+ gravity: float,
71
+ ):
72
+ return -gravity * v(s)[1]
73
+
74
+
75
+ @fem.integrand
76
+ def bottom_boundary_projector_form(
77
+ s: fem.Sample,
78
+ domain: fem.Domain,
79
+ u: fem.Field,
80
+ v: fem.Field,
81
+ ):
82
+ # non zero on bottom boundary only
83
+ nor = fem.normal(domain, s)
84
+ return wp.dot(u(s), v(s)) * wp.max(0.0, -nor[1])
85
+
86
+
87
+ @fem.integrand
88
+ def tensor_mass_form(
89
+ s: fem.Sample,
90
+ sig: fem.Field,
91
+ tau: fem.Field,
92
+ ):
93
+ return wp.ddot(tau(s), sig(s))
94
+
95
+
96
+ class Example:
97
+ def __init__(
98
+ self,
99
+ degree=2,
100
+ resolution=16,
101
+ young_modulus=1.0,
102
+ poisson_ratio=0.5,
103
+ nonconforming_stresses=False,
104
+ ):
105
+ self._geo1 = fem.Grid2D(bounds_hi=wp.vec2(1.0, 0.5), res=wp.vec2i(resolution))
106
+ self._geo2 = fem.Grid2D(bounds_lo=(0.33, 0.5), bounds_hi=(0.67, 0.5 + 0.33), res=wp.vec2i(resolution))
107
+
108
+ # Strain-stress matrix
109
+ young = young_modulus
110
+ poisson = poisson_ratio
111
+ self._elasticity_mat = wp.mat33(
112
+ young
113
+ / (1.0 - poisson * poisson)
114
+ * np.array(
115
+ [
116
+ [1.0, poisson, 0.0],
117
+ [poisson, 1.0, 0.0],
118
+ [0.0, 0.0, (2.0 * (1.0 + poisson)) * (1.0 - poisson * poisson)],
119
+ ]
120
+ )
121
+ )
122
+
123
+ # Displacement spaces and fields -- S_k
124
+ self._u1_space = fem.make_polynomial_space(
125
+ self._geo1, degree=degree, dtype=wp.vec2, element_basis=fem.ElementBasis.SERENDIPITY
126
+ )
127
+ self._u2_space = fem.make_polynomial_space(
128
+ self._geo2, degree=degree, dtype=wp.vec2, element_basis=fem.ElementBasis.SERENDIPITY
129
+ )
130
+ self._u1_field = self._u1_space.make_field()
131
+ self._u2_field = self._u2_space.make_field()
132
+
133
+ # Stress spaces and fields -- Q_{k-1}d
134
+ # Store stress degrees of freedom as symmetric tensors (3 dof) rather than full 2x2 matrices
135
+ self._tau1_space = fem.make_polynomial_space(
136
+ self._geo1,
137
+ degree=degree - 1,
138
+ discontinuous=True,
139
+ element_basis=fem.ElementBasis.LAGRANGE,
140
+ dof_mapper=fem.SymmetricTensorMapper(wp.mat22),
141
+ )
142
+ self._tau2_space = fem.make_polynomial_space(
143
+ self._geo2,
144
+ degree=degree - 1,
145
+ discontinuous=True,
146
+ element_basis=fem.ElementBasis.LAGRANGE,
147
+ dof_mapper=fem.SymmetricTensorMapper(wp.mat22),
148
+ )
149
+
150
+ self._sig1_field = self._tau1_space.make_field()
151
+ self._sig2_field = self._tau2_space.make_field()
152
+ self._sig2_field_new = self._tau2_space.make_field()
153
+
154
+ self.renderer = fem_example_utils.Plot()
155
+
156
+ def step(self):
157
+ # Solve for the two bodies separately
158
+ # Body (top) is 25x more dense and 5x stiffer than top body
159
+ # Body 1 affects body 2 through bottom displacement dirichlet BC
160
+ # Body 2 affects body 1 through applied strain on top
161
+ self.solve_solid(self._u1_field, self._sig1_field, self._u2_field, self._sig2_field, gravity=1.0, stiffness=1.0)
162
+ self.solve_solid(
163
+ self._u2_field, self._sig2_field_new, self._u1_field, self._sig1_field, gravity=25.0, stiffness=5.0
164
+ )
165
+
166
+ # Damped update of coupling stress (for stability)
167
+ alpha = 0.1
168
+ fem.utils.array_axpy(
169
+ x=self._sig2_field_new.dof_values, y=self._sig2_field.dof_values, alpha=alpha, beta=1.0 - alpha
170
+ )
171
+
172
+ def solve_solid(
173
+ self,
174
+ u_field,
175
+ stress_field,
176
+ other_u_field,
177
+ other_stress_field,
178
+ gravity: float,
179
+ stiffness: float,
180
+ ):
181
+ u_space = u_field.space
182
+ stress_space = stress_field.space
183
+ geo = u_field.space.geometry
184
+
185
+ domain = fem.Cells(geometry=geo)
186
+ boundary = fem.BoundarySides(geometry=geo)
187
+
188
+ u_test = fem.make_test(space=u_space, domain=domain)
189
+ u_trial = fem.make_trial(space=u_space, domain=domain)
190
+ tau_test = fem.make_test(space=stress_space, domain=domain)
191
+ tau_trial = fem.make_trial(space=stress_space, domain=domain)
192
+
193
+ u_bd_test = fem.make_test(space=u_space, domain=boundary)
194
+ u_bd_trial = fem.make_trial(space=u_space, domain=boundary)
195
+
196
+ # Assemble stiffness matrix
197
+ # (Note: this is constant per body, this could be precomputed)
198
+ sym_grad_matrix = fem.integrate(symmetric_grad_form, fields={"u": u_trial, "tau": tau_test})
199
+
200
+ tau_inv_mass_matrix = fem.integrate(tensor_mass_form, fields={"sig": tau_trial, "tau": tau_test}, nodal=True)
201
+ fem_example_utils.invert_diagonal_bsr_matrix(tau_inv_mass_matrix)
202
+
203
+ stress_matrix = tau_inv_mass_matrix @ fem.integrate(
204
+ stress_form, fields={"u": u_trial, "tau": tau_test}, values={"E": self._elasticity_mat * stiffness}
205
+ )
206
+ stiffness_matrix = sym_grad_matrix.transpose() @ stress_matrix
207
+
208
+ # Right-hand-side
209
+ u_rhs = fem.integrate(gravity_form, fields={"v": u_test}, values={"gravity": gravity}, output_dtype=wp.vec2d)
210
+
211
+ # Add boundary stress from other solid field
212
+ other_stress_field = fem.field.field.NonconformingField(boundary, other_stress_field)
213
+ fem.utils.array_axpy(
214
+ y=u_rhs,
215
+ x=fem.integrate(
216
+ boundary_stress_form, fields={"u": u_bd_test, "tau": other_stress_field}, output_dtype=wp.vec2d
217
+ ),
218
+ )
219
+
220
+ # Enforce boundary conditions
221
+ u_bd_matrix = fem.integrate(
222
+ bottom_boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True
223
+ )
224
+
225
+ # read displacement from other body set create bottom boundary Dirichlet BC
226
+ other_u_field = fem.field.field.NonconformingField(boundary, other_u_field)
227
+ u_bd_rhs = fem.integrate(
228
+ bottom_boundary_projector_form, fields={"u": other_u_field, "v": u_bd_test}, nodal=True
229
+ )
230
+
231
+ fem.project_linear_system(stiffness_matrix, u_rhs, u_bd_matrix, u_bd_rhs)
232
+
233
+ # solve
234
+ x = wp.zeros_like(u_rhs)
235
+ wp.utils.array_cast(in_array=u_field.dof_values, out_array=x)
236
+ fem_example_utils.bsr_cg(stiffness_matrix, b=u_rhs, x=x, tol=1.0e-6, quiet=True)
237
+
238
+ # Extract result
239
+ stress = stress_matrix @ x
240
+ wp.utils.array_cast(in_array=x, out_array=u_field.dof_values)
241
+ wp.utils.array_cast(in_array=stress, out_array=stress_field.dof_values)
242
+
243
+ def render(self):
244
+ self.renderer.add_field("u1", self._u1_field)
245
+ self.renderer.add_field("u2", self._u2_field)
246
+ self.renderer.add_field("sig1", self._sig1_field)
247
+ self.renderer.add_field("sig2", self._sig2_field)
248
+
249
+
250
+ if __name__ == "__main__":
251
+ import argparse
252
+
253
+ wp.set_module_options({"enable_backward": False})
254
+
255
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
256
+ parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
257
+ parser.add_argument("--resolution", type=int, default=32, help="Grid resolution.")
258
+ parser.add_argument("--degree", type=int, default=2, help="Polynomial degree of shape functions.")
259
+ parser.add_argument("--young_modulus", type=float, default=10.0)
260
+ parser.add_argument("--poisson_ratio", type=float, default=0.9)
261
+ parser.add_argument("--num_steps", type=int, default=50)
262
+ parser.add_argument(
263
+ "--headless",
264
+ action="store_true",
265
+ help="Run in headless mode, suppressing the opening of any graphical windows.",
266
+ )
267
+
268
+ args = parser.parse_known_args()[0]
269
+
270
+ with wp.ScopedDevice(args.device):
271
+ example = Example(
272
+ degree=args.degree,
273
+ resolution=args.resolution,
274
+ young_modulus=args.young_modulus,
275
+ poisson_ratio=args.poisson_ratio,
276
+ )
277
+
278
+ for i in range(args.num_steps):
279
+ print("Step", i)
280
+ example.step()
281
+ example.render()
282
+
283
+ if not args.headless:
284
+ example.renderer.plot(
285
+ {
286
+ "rows": 2,
287
+ "u1": {"displacement": {}},
288
+ "u2": {"displacement": {}},
289
+ },
290
+ )
@@ -17,24 +17,10 @@
17
17
  ###########################################################################
18
18
 
19
19
  import warp as wp
20
+ import warp.examples.fem.utils as fem_example_utils
20
21
  import warp.fem as fem
21
- import warp.sparse as sparse
22
22
  from warp.fem.utils import array_axpy
23
23
 
24
- try:
25
- from .bsr_utils import SaddleSystem, bsr_solve_saddle
26
- from .mesh_utils import gen_quadmesh, gen_trimesh
27
- from .plot_utils import Plot
28
- except ImportError:
29
- from bsr_utils import SaddleSystem, bsr_solve_saddle
30
- from mesh_utils import gen_quadmesh, gen_trimesh
31
- from plot_utils import Plot
32
-
33
-
34
- @fem.integrand
35
- def constant_form(val: wp.vec2):
36
- return val
37
-
38
24
 
39
25
  @fem.integrand
40
26
  def viscosity_form(s: fem.Sample, u: fem.Field, v: fem.Field, nu: float):
@@ -90,10 +76,10 @@ class Example:
90
76
 
91
77
  # Grid or triangle mesh geometry
92
78
  if mesh == "tri":
93
- positions, tri_vidx = gen_trimesh(res=wp.vec2i(resolution))
79
+ positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(resolution))
94
80
  geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
95
81
  elif mesh == "quad":
96
- positions, quad_vidx = gen_quadmesh(res=wp.vec2i(resolution))
82
+ positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
97
83
  geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
98
84
  else:
99
85
  geo = fem.Grid2D(res=wp.vec2i(resolution))
@@ -111,13 +97,9 @@ class Example:
111
97
  self._u_field = u_space.make_field()
112
98
  self._p_field = p_space.make_field()
113
99
 
114
- # Interpolate initial condition on boundary (for example purposes)
115
- self._bd_field = u_space.make_field()
116
- f_boundary = fem.make_restriction(self._bd_field, domain=fem.BoundarySides(geo))
117
- top_velocity = wp.vec2(top_velocity, 0.0)
118
- fem.interpolate(constant_form, dest=f_boundary, values={"val": top_velocity})
100
+ self._bd_field = fem.UniformField(domain=fem.BoundarySides(geo), value=wp.vec2(top_velocity, 0.0))
119
101
 
120
- self.renderer = Plot()
102
+ self.renderer = fem_example_utils.Plot()
121
103
 
122
104
  def step(self):
123
105
  u_space = self._u_field.space
@@ -140,9 +122,7 @@ class Example:
140
122
  # Weak velocity boundary conditions
141
123
  u_bd_test = fem.make_test(space=u_space, domain=boundary)
142
124
  u_bd_trial = fem.make_trial(space=u_space, domain=boundary)
143
- u_rhs = fem.integrate(
144
- top_mass_form, fields={"u": self._bd_field.trace(), "v": u_bd_test}, output_dtype=wp.vec2d
145
- )
125
+ u_rhs = fem.integrate(top_mass_form, fields={"u": self._bd_field, "v": u_bd_test}, output_dtype=wp.vec2d)
146
126
  u_bd_matrix = fem.integrate(mass_form, fields={"u": u_bd_trial, "v": u_bd_test})
147
127
 
148
128
  # Pressure-velocity coupling
@@ -151,23 +131,28 @@ class Example:
151
131
 
152
132
  # Define and solve the saddle-point system
153
133
  u_matrix = u_visc_matrix
154
- sparse.bsr_axpy(x=u_bd_matrix, y=u_matrix, alpha=self.boundary_strength, beta=1.0)
134
+ u_matrix += self.boundary_strength * u_bd_matrix
155
135
  array_axpy(x=u_rhs, y=u_rhs, alpha=0.0, beta=self.boundary_strength)
156
136
 
157
137
  p_rhs = wp.zeros(p_space.node_count(), dtype=wp.float64)
158
138
  x_u = wp.zeros_like(u_rhs)
159
139
  x_p = wp.zeros_like(p_rhs)
160
140
 
161
- bsr_solve_saddle(
162
- SaddleSystem(A=u_matrix, B=div_matrix), x_u=x_u, x_p=x_p, b_u=u_rhs, b_p=p_rhs, quiet=self._quiet
141
+ fem_example_utils.bsr_solve_saddle(
142
+ fem_example_utils.SaddleSystem(A=u_matrix, B=div_matrix),
143
+ x_u=x_u,
144
+ x_p=x_p,
145
+ b_u=u_rhs,
146
+ b_p=p_rhs,
147
+ quiet=self._quiet,
163
148
  )
164
149
 
165
150
  wp.utils.array_cast(in_array=x_u, out_array=self._u_field.dof_values)
166
151
  wp.utils.array_cast(in_array=x_p, out_array=self._p_field.dof_values)
167
152
 
168
153
  def render(self):
169
- self.renderer.add_surface("pressure", self._p_field)
170
- self.renderer.add_surface_vector("velocity", self._u_field)
154
+ self.renderer.add_field("pressure", self._p_field)
155
+ self.renderer.add_field("velocity", self._u_field)
171
156
 
172
157
 
173
158
  if __name__ == "__main__":
@@ -215,4 +200,4 @@ if __name__ == "__main__":
215
200
  example.render()
216
201
 
217
202
  if not args.headless:
218
- example.renderer.plot()
203
+ example.renderer.plot(options={"velocity": {"streamlines": {}}, "pressure": {"contours": {}}})
@@ -19,20 +19,11 @@ import math
19
19
  import numpy as np
20
20
 
21
21
  import warp as wp
22
+ import warp.examples.fem.utils as fem_example_utils
22
23
  import warp.fem as fem
23
24
  from warp.fem.utils import array_axpy
24
- from warp.sparse import bsr_axpy, bsr_mm, bsr_mv, bsr_transposed
25
25
  from warp.utils import array_cast
26
26
 
27
- # Import example utilities
28
- # Make sure that works both when imported as module and run as standalone file
29
- try:
30
- from .bsr_utils import bsr_cg
31
- from .plot_utils import Plot
32
- except ImportError:
33
- from bsr_utils import bsr_cg
34
- from plot_utils import Plot
35
-
36
27
 
37
28
  @fem.integrand
38
29
  def vel_from_particles_form(s: fem.Sample, particle_vel: wp.array(dtype=wp.vec2), v: fem.Field):
@@ -141,7 +132,7 @@ class Example:
141
132
  self._pic_quadrature = fem.PicQuadrature(domain, particles, particle_areas)
142
133
  self._particle_velocities = particle_velocities
143
134
 
144
- self.renderer = Plot()
135
+ self.renderer = fem_example_utils.Plot()
145
136
 
146
137
  def step(self):
147
138
  u_space = self._u_field.space
@@ -182,21 +173,21 @@ class Example:
182
173
 
183
174
  # Assemble linear system
184
175
  u_matrix = u_visc_matrix
185
- bsr_axpy(u_bd_matrix, u_matrix, alpha=self.bd_strength)
176
+ u_matrix += u_bd_matrix * self.bd_strength
186
177
 
187
- div_matrix_t = bsr_transposed(div_matrix)
188
- gradient_matrix = bsr_mm(div_matrix_t, inv_p_mass_matrix)
189
- bsr_mm(gradient_matrix, div_matrix, u_matrix, alpha=1.0 / self.compliance, beta=1.0)
178
+ gradient_matrix = div_matrix.transpose() @ inv_p_mass_matrix
179
+ u_matrix += gradient_matrix @ div_matrix / self.compliance
190
180
 
181
+ # scale u_rhs
191
182
  array_axpy(u_rhs, u_rhs, alpha=0.0, beta=self.bd_strength)
192
183
 
193
184
  # Solve for displacement
194
185
  u_res = wp.zeros_like(u_rhs)
195
- bsr_cg(u_matrix, x=u_res, b=u_rhs, quiet=self._quiet)
186
+ fem_example_utils.bsr_cg(u_matrix, x=u_res, b=u_rhs, quiet=self._quiet)
196
187
 
197
188
  # Compute pressure from displacement
198
- div_u = bsr_mv(A=div_matrix, x=u_res)
199
- p_res = bsr_mv(A=inv_p_mass_matrix, x=div_u, alpha=-1)
189
+ div_u = div_matrix @ u_res
190
+ p_res = -inv_p_mass_matrix @ div_u
200
191
 
201
192
  # Copy to fields
202
193
  u_nodes = wp.indexedarray(self._u_field.dof_values, indices=self._active_space_partition.space_node_indices())
@@ -206,8 +197,8 @@ class Example:
206
197
  array_cast(in_array=p_res, out_array=p_nodes)
207
198
 
208
199
  def render(self):
209
- self.renderer.add_surface("pressure", self._p_field)
210
- self.renderer.add_surface_vector("velocity", self._u_field)
200
+ self.renderer.add_field("pressure", self._p_field)
201
+ self.renderer.add_field("velocity", self._u_field)
211
202
 
212
203
  def _gen_particles(self, circle_radius, c1_center, c2_center):
213
204
  """Generate some particles along two circles defining velocity boundary conditions"""
@@ -260,4 +251,4 @@ if __name__ == "__main__":
260
251
  example.render()
261
252
 
262
253
  if not args.headless:
263
- example.renderer.plot(streamlines=["velocity"])
254
+ example.renderer.plot(options={"velocity": {"streamlines": {}}})