warp-lang 0.11.0__py3-none-manylinux2014_x86_64.whl → 1.0.0__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.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (170) hide show
  1. warp/__init__.py +8 -0
  2. warp/bin/warp-clang.so +0 -0
  3. warp/bin/warp.so +0 -0
  4. warp/build.py +7 -6
  5. warp/build_dll.py +70 -79
  6. warp/builtins.py +10 -6
  7. warp/codegen.py +51 -19
  8. warp/config.py +7 -8
  9. warp/constants.py +3 -0
  10. warp/context.py +948 -245
  11. warp/dlpack.py +198 -113
  12. warp/examples/assets/bunny.usd +0 -0
  13. warp/examples/assets/cartpole.urdf +110 -0
  14. warp/examples/assets/crazyflie.usd +0 -0
  15. warp/examples/assets/cube.usda +42 -0
  16. warp/examples/assets/nv_ant.xml +92 -0
  17. warp/examples/assets/nv_humanoid.xml +183 -0
  18. warp/examples/assets/quadruped.urdf +268 -0
  19. warp/examples/assets/rocks.nvdb +0 -0
  20. warp/examples/assets/rocks.usd +0 -0
  21. warp/examples/assets/sphere.usda +56 -0
  22. warp/examples/assets/torus.usda +105 -0
  23. warp/examples/benchmarks/benchmark_api.py +383 -0
  24. warp/examples/benchmarks/benchmark_cloth.py +279 -0
  25. warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -0
  26. warp/examples/benchmarks/benchmark_cloth_jax.py +100 -0
  27. warp/examples/benchmarks/benchmark_cloth_numba.py +142 -0
  28. warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -0
  29. warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -0
  30. warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -0
  31. warp/examples/benchmarks/benchmark_cloth_warp.py +146 -0
  32. warp/examples/benchmarks/benchmark_launches.py +295 -0
  33. warp/examples/core/example_dem.py +221 -0
  34. warp/examples/core/example_fluid.py +267 -0
  35. warp/examples/core/example_graph_capture.py +129 -0
  36. warp/examples/core/example_marching_cubes.py +177 -0
  37. warp/examples/core/example_mesh.py +154 -0
  38. warp/examples/core/example_mesh_intersect.py +193 -0
  39. warp/examples/core/example_nvdb.py +169 -0
  40. warp/examples/core/example_raycast.py +89 -0
  41. warp/examples/core/example_raymarch.py +178 -0
  42. warp/examples/core/example_render_opengl.py +141 -0
  43. warp/examples/core/example_sph.py +389 -0
  44. warp/examples/core/example_torch.py +181 -0
  45. warp/examples/core/example_wave.py +249 -0
  46. warp/examples/fem/bsr_utils.py +380 -0
  47. warp/examples/fem/example_apic_fluid.py +391 -0
  48. warp/examples/fem/example_convection_diffusion.py +168 -0
  49. warp/examples/fem/example_convection_diffusion_dg.py +209 -0
  50. warp/examples/fem/example_convection_diffusion_dg0.py +194 -0
  51. warp/examples/fem/example_deformed_geometry.py +159 -0
  52. warp/examples/fem/example_diffusion.py +173 -0
  53. warp/examples/fem/example_diffusion_3d.py +152 -0
  54. warp/examples/fem/example_diffusion_mgpu.py +214 -0
  55. warp/examples/fem/example_mixed_elasticity.py +222 -0
  56. warp/examples/fem/example_navier_stokes.py +243 -0
  57. warp/examples/fem/example_stokes.py +192 -0
  58. warp/examples/fem/example_stokes_transfer.py +249 -0
  59. warp/examples/fem/mesh_utils.py +109 -0
  60. warp/examples/fem/plot_utils.py +287 -0
  61. warp/examples/optim/example_bounce.py +248 -0
  62. warp/examples/optim/example_cloth_throw.py +210 -0
  63. warp/examples/optim/example_diffray.py +535 -0
  64. warp/examples/optim/example_drone.py +850 -0
  65. warp/examples/optim/example_inverse_kinematics.py +169 -0
  66. warp/examples/optim/example_inverse_kinematics_torch.py +170 -0
  67. warp/examples/optim/example_spring_cage.py +234 -0
  68. warp/examples/optim/example_trajectory.py +201 -0
  69. warp/examples/sim/example_cartpole.py +128 -0
  70. warp/examples/sim/example_cloth.py +184 -0
  71. warp/examples/sim/example_granular.py +113 -0
  72. warp/examples/sim/example_granular_collision_sdf.py +185 -0
  73. warp/examples/sim/example_jacobian_ik.py +213 -0
  74. warp/examples/sim/example_particle_chain.py +106 -0
  75. warp/examples/sim/example_quadruped.py +179 -0
  76. warp/examples/sim/example_rigid_chain.py +191 -0
  77. warp/examples/sim/example_rigid_contact.py +176 -0
  78. warp/examples/sim/example_rigid_force.py +126 -0
  79. warp/examples/sim/example_rigid_gyroscopic.py +97 -0
  80. warp/examples/sim/example_rigid_soft_contact.py +124 -0
  81. warp/examples/sim/example_soft_body.py +178 -0
  82. warp/fabric.py +29 -20
  83. warp/fem/cache.py +0 -1
  84. warp/fem/dirichlet.py +0 -2
  85. warp/fem/integrate.py +0 -1
  86. warp/jax.py +45 -0
  87. warp/jax_experimental.py +339 -0
  88. warp/native/builtin.h +12 -0
  89. warp/native/bvh.cu +18 -18
  90. warp/native/clang/clang.cpp +8 -3
  91. warp/native/cuda_util.cpp +94 -5
  92. warp/native/cuda_util.h +35 -6
  93. warp/native/cutlass_gemm.cpp +1 -1
  94. warp/native/cutlass_gemm.cu +4 -1
  95. warp/native/error.cpp +66 -0
  96. warp/native/error.h +27 -0
  97. warp/native/mesh.cu +2 -2
  98. warp/native/reduce.cu +4 -4
  99. warp/native/runlength_encode.cu +2 -2
  100. warp/native/scan.cu +2 -2
  101. warp/native/sparse.cu +0 -1
  102. warp/native/temp_buffer.h +2 -2
  103. warp/native/warp.cpp +95 -60
  104. warp/native/warp.cu +1053 -218
  105. warp/native/warp.h +49 -32
  106. warp/optim/linear.py +33 -16
  107. warp/render/render_opengl.py +202 -101
  108. warp/render/render_usd.py +82 -40
  109. warp/sim/__init__.py +13 -4
  110. warp/sim/articulation.py +4 -5
  111. warp/sim/collide.py +320 -175
  112. warp/sim/import_mjcf.py +25 -30
  113. warp/sim/import_urdf.py +94 -63
  114. warp/sim/import_usd.py +51 -36
  115. warp/sim/inertia.py +3 -2
  116. warp/sim/integrator.py +233 -0
  117. warp/sim/integrator_euler.py +447 -469
  118. warp/sim/integrator_featherstone.py +1991 -0
  119. warp/sim/integrator_xpbd.py +1420 -640
  120. warp/sim/model.py +765 -487
  121. warp/sim/particles.py +2 -1
  122. warp/sim/render.py +35 -13
  123. warp/sim/utils.py +222 -11
  124. warp/stubs.py +8 -0
  125. warp/tape.py +16 -1
  126. warp/tests/aux_test_grad_customs.py +23 -0
  127. warp/tests/test_array.py +190 -1
  128. warp/tests/test_async.py +656 -0
  129. warp/tests/test_bool.py +50 -0
  130. warp/tests/test_dlpack.py +164 -11
  131. warp/tests/test_examples.py +166 -74
  132. warp/tests/test_fem.py +8 -1
  133. warp/tests/test_generics.py +15 -5
  134. warp/tests/test_grad.py +1 -1
  135. warp/tests/test_grad_customs.py +172 -12
  136. warp/tests/test_jax.py +254 -0
  137. warp/tests/test_large.py +29 -6
  138. warp/tests/test_launch.py +25 -0
  139. warp/tests/test_linear_solvers.py +20 -3
  140. warp/tests/test_matmul.py +61 -16
  141. warp/tests/test_matmul_lite.py +13 -13
  142. warp/tests/test_mempool.py +186 -0
  143. warp/tests/test_multigpu.py +3 -0
  144. warp/tests/test_options.py +16 -2
  145. warp/tests/test_peer.py +137 -0
  146. warp/tests/test_print.py +3 -1
  147. warp/tests/test_quat.py +23 -0
  148. warp/tests/test_sim_kinematics.py +97 -0
  149. warp/tests/test_snippet.py +126 -3
  150. warp/tests/test_streams.py +108 -79
  151. warp/tests/test_torch.py +16 -8
  152. warp/tests/test_utils.py +32 -27
  153. warp/tests/test_verify_fp.py +65 -0
  154. warp/tests/test_volume.py +1 -1
  155. warp/tests/unittest_serial.py +2 -0
  156. warp/tests/unittest_suites.py +12 -0
  157. warp/tests/unittest_utils.py +14 -7
  158. warp/thirdparty/unittest_parallel.py +15 -3
  159. warp/torch.py +10 -8
  160. warp/types.py +363 -246
  161. warp/utils.py +143 -19
  162. warp_lang-1.0.0.dist-info/LICENSE.md +126 -0
  163. warp_lang-1.0.0.dist-info/METADATA +394 -0
  164. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +167 -86
  165. warp/sim/optimizer.py +0 -138
  166. warp_lang-0.11.0.dist-info/LICENSE.md +0 -36
  167. warp_lang-0.11.0.dist-info/METADATA +0 -238
  168. /warp/tests/{walkthough_debug.py → walkthrough_debug.py} +0 -0
  169. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
  170. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,222 @@
1
+ # Copyright (c) 2022 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 Mixed Elasticity
10
+ #
11
+ # This example illustrates using Mixed FEM to solve a
12
+ # 2D linear elasticity problem:
13
+ #
14
+ # Div[ E: D(u) ] = 0
15
+ #
16
+ # with Dirichlet boundary conditions on horizontal sides,
17
+ # and E the elasticity rank-4 tensor
18
+ ###########################################################################
19
+
20
+ import argparse
21
+
22
+ import warp as wp
23
+ import numpy as np
24
+
25
+ import warp.fem as fem
26
+
27
+ from warp.sparse import bsr_transposed, bsr_mm
28
+
29
+ try:
30
+ from .plot_utils import Plot
31
+ from .bsr_utils import bsr_cg, invert_diagonal_bsr_mass_matrix
32
+ from .mesh_utils import gen_trimesh, gen_quadmesh
33
+ except ImportError:
34
+ from plot_utils import Plot
35
+ from bsr_utils import bsr_cg, invert_diagonal_bsr_mass_matrix
36
+ from mesh_utils import gen_trimesh, gen_quadmesh
37
+
38
+ wp.init()
39
+
40
+
41
+ @wp.func
42
+ def compute_stress(tau: wp.mat22, E: wp.mat33):
43
+ """Strain to stress computation"""
44
+ tau_sym = wp.vec3(tau[0, 0], tau[1, 1], tau[0, 1] + tau[1, 0])
45
+ sig_sym = E * tau_sym
46
+ return wp.mat22(sig_sym[0], 0.5 * sig_sym[2], 0.5 * sig_sym[2], sig_sym[1])
47
+
48
+
49
+ @fem.integrand
50
+ def symmetric_grad_form(
51
+ s: fem.Sample,
52
+ u: fem.Field,
53
+ tau: fem.Field,
54
+ ):
55
+ """D(u) : tau"""
56
+ return wp.ddot(tau(s), fem.D(u, s))
57
+
58
+
59
+ @fem.integrand
60
+ def stress_form(s: fem.Sample, u: fem.Field, tau: fem.Field, E: wp.mat33):
61
+ """(E : D(u)) : tau"""
62
+ return wp.ddot(tau(s), compute_stress(fem.D(u, s), E))
63
+
64
+
65
+ @fem.integrand
66
+ def horizontal_boundary_projector_form(
67
+ s: fem.Sample,
68
+ domain: fem.Domain,
69
+ u: fem.Field,
70
+ v: fem.Field,
71
+ ):
72
+ # non zero on horizontal boundary of domain only
73
+ nor = fem.normal(domain, s)
74
+ return wp.dot(u(s), v(s)) * wp.abs(nor[1])
75
+
76
+
77
+ @fem.integrand
78
+ def horizontal_displacement_form(
79
+ s: fem.Sample,
80
+ domain: fem.Domain,
81
+ v: fem.Field,
82
+ displacement: float,
83
+ ):
84
+ # opposed to normal on horizontal boundary of domain only
85
+ nor = fem.normal(domain, s)
86
+ return -wp.abs(nor[1]) * displacement * wp.dot(nor, v(s))
87
+
88
+
89
+ @fem.integrand
90
+ def tensor_mass_form(
91
+ s: fem.Sample,
92
+ sig: fem.Field,
93
+ tau: fem.Field,
94
+ ):
95
+ return wp.ddot(tau(s), sig(s))
96
+
97
+
98
+ class Example:
99
+ parser = argparse.ArgumentParser()
100
+ parser.add_argument("--resolution", type=int, default=25)
101
+ parser.add_argument("--degree", type=int, default=2)
102
+ parser.add_argument("--displacement", type=float, default=0.1)
103
+ parser.add_argument("--young_modulus", type=float, default=1.0)
104
+ parser.add_argument("--poisson_ratio", type=float, default=0.5)
105
+ parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
106
+ parser.add_argument(
107
+ "--nonconforming_stresses", action="store_true", help="For grid, use non-conforming stresses (Q_d/P_d)"
108
+ )
109
+
110
+ def __init__(self, stage=None, quiet=False, args=None, **kwargs):
111
+ if args is None:
112
+ # Read args from kwargs, add default arg values from parser
113
+ args = argparse.Namespace(**kwargs)
114
+ args = Example.parser.parse_args(args=[], namespace=args)
115
+ self._args = args
116
+ self._quiet = quiet
117
+
118
+ # Grid or triangle mesh geometry
119
+ if args.mesh == "tri":
120
+ positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
121
+ self._geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
122
+ elif args.mesh == "quad":
123
+ positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
124
+ self._geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
125
+ else:
126
+ self._geo = fem.Grid2D(res=wp.vec2i(args.resolution))
127
+
128
+ # Strain-stress matrix
129
+ young = args.young_modulus
130
+ poisson = args.poisson_ratio
131
+ self._elasticity_mat = wp.mat33(
132
+ young
133
+ / (1.0 - poisson * poisson)
134
+ * np.array(
135
+ [
136
+ [1.0, poisson, 0.0],
137
+ [poisson, 1.0, 0.0],
138
+ [0.0, 0.0, (2.0 * (1.0 + poisson)) * (1.0 - poisson * poisson)],
139
+ ]
140
+ )
141
+ )
142
+
143
+ # Function spaces -- S_k for displacement, Q_{k-1}d for stress
144
+ self._u_space = fem.make_polynomial_space(
145
+ self._geo, degree=args.degree, dtype=wp.vec2, element_basis=fem.ElementBasis.SERENDIPITY
146
+ )
147
+
148
+ # Store stress degrees of freedom as symmetric tensors (3 dof) rather than full 2x2 matrices
149
+ tau_basis = (
150
+ fem.ElementBasis.NONCONFORMING_POLYNOMIAL if args.nonconforming_stresses else fem.ElementBasis.LAGRANGE
151
+ )
152
+ self._tau_space = fem.make_polynomial_space(
153
+ self._geo,
154
+ degree=args.degree - 1,
155
+ discontinuous=True,
156
+ element_basis=tau_basis,
157
+ dof_mapper=fem.SymmetricTensorMapper(wp.mat22),
158
+ )
159
+
160
+ self._u_field = self._u_space.make_field()
161
+
162
+ self.renderer = Plot(stage)
163
+
164
+ def step(self):
165
+ boundary = fem.BoundarySides(self._geo)
166
+ domain = fem.Cells(geometry=self._geo)
167
+
168
+ # Displacement boundary conditions
169
+ u_bd_test = fem.make_test(space=self._u_space, domain=boundary)
170
+ u_bd_trial = fem.make_trial(space=self._u_space, domain=boundary)
171
+ u_bd_rhs = fem.integrate(
172
+ horizontal_displacement_form,
173
+ fields={"v": u_bd_test},
174
+ values={"displacement": self._args.displacement},
175
+ nodal=True,
176
+ output_dtype=wp.vec2d,
177
+ )
178
+ u_bd_matrix = fem.integrate(
179
+ horizontal_boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True
180
+ )
181
+
182
+ # Stress/velocity coupling
183
+ u_trial = fem.make_trial(space=self._u_space, domain=domain)
184
+ tau_test = fem.make_test(space=self._tau_space, domain=domain)
185
+ tau_trial = fem.make_trial(space=self._tau_space, domain=domain)
186
+
187
+ sym_grad_matrix = fem.integrate(symmetric_grad_form, fields={"u": u_trial, "tau": tau_test})
188
+ stress_matrix = fem.integrate(
189
+ stress_form, fields={"u": u_trial, "tau": tau_test}, values={"E": self._elasticity_mat}
190
+ )
191
+
192
+ # Compute inverse of the (block-diagonal) tau mass matrix
193
+ tau_inv_mass_matrix = fem.integrate(tensor_mass_form, fields={"sig": tau_trial, "tau": tau_test}, nodal=True)
194
+ invert_diagonal_bsr_mass_matrix(tau_inv_mass_matrix)
195
+
196
+ # Assemble system matrix
197
+ u_matrix = bsr_mm(bsr_transposed(sym_grad_matrix), bsr_mm(tau_inv_mass_matrix, stress_matrix))
198
+
199
+ # Enforce boundary conditions
200
+ u_rhs = wp.zeros_like(u_bd_rhs)
201
+ fem.project_linear_system(u_matrix, u_rhs, u_bd_matrix, u_bd_rhs)
202
+
203
+ x = wp.zeros_like(u_rhs)
204
+ bsr_cg(u_matrix, b=u_rhs, x=x, tol=1.0e-16, quiet=self._quiet)
205
+
206
+ # Extract result
207
+ self._u_field.dof_values = x
208
+
209
+ def render(self):
210
+ self.renderer.add_surface_vector("solution", self._u_field)
211
+
212
+
213
+ if __name__ == "__main__":
214
+ wp.set_module_options({"enable_backward": False})
215
+
216
+ args = Example.parser.parse_args()
217
+
218
+ example = Example(args=args)
219
+ example.step()
220
+ example.render()
221
+
222
+ example.renderer.plot()
@@ -0,0 +1,243 @@
1
+ # Copyright (c) 2022 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 Navier Stokes
10
+ #
11
+ # This example solves a 2D Navier-Stokes flow problem:
12
+ #
13
+ # Du/dt -nu D(u) + grad p = 0
14
+ # Div u = 0
15
+ #
16
+ # with (hard) velocity-Dirichlet boundary conditions
17
+ # and using semi-Lagrangian advection
18
+ ###########################################################################
19
+
20
+ import argparse
21
+
22
+ import warp as wp
23
+ import warp.fem as fem
24
+
25
+ from warp.fem.utils import array_axpy
26
+
27
+ from warp.sparse import bsr_mm, bsr_mv, bsr_copy
28
+
29
+ try:
30
+ from .bsr_utils import bsr_solve_saddle, SaddleSystem
31
+ from .plot_utils import Plot
32
+ from .mesh_utils import gen_trimesh
33
+ except ImportError:
34
+ from bsr_utils import bsr_solve_saddle, SaddleSystem
35
+ from plot_utils import Plot
36
+ from mesh_utils import gen_trimesh
37
+
38
+ wp.init()
39
+
40
+
41
+ @fem.integrand
42
+ def u_boundary_value(s: fem.Sample, domain: fem.Domain, v: fem.Field, top_vel: float):
43
+ # Horizontal velocity on top of domain, zero elsewhere
44
+ if domain(s)[1] == 1.0:
45
+ return wp.dot(wp.vec2f(top_vel, 0.0), v(s))
46
+
47
+ return wp.dot(wp.vec2f(0.0, 0.0), v(s))
48
+
49
+
50
+ @fem.integrand
51
+ def mass_form(
52
+ s: fem.Sample,
53
+ u: fem.Field,
54
+ v: fem.Field,
55
+ ):
56
+ return wp.dot(u(s), v(s))
57
+
58
+
59
+ @fem.integrand
60
+ def inertia_form(s: fem.Sample, u: fem.Field, v: fem.Field, dt: float):
61
+ return mass_form(s, u, v) / dt
62
+
63
+
64
+ @fem.integrand
65
+ def viscosity_form(s: fem.Sample, u: fem.Field, v: fem.Field, nu: float):
66
+ return 2.0 * nu * wp.ddot(fem.D(u, s), fem.D(v, s))
67
+
68
+
69
+ @fem.integrand
70
+ def viscosity_and_inertia_form(s: fem.Sample, u: fem.Field, v: fem.Field, dt: float, nu: float):
71
+ return inertia_form(s, u, v, dt) + viscosity_form(s, u, v, nu)
72
+
73
+
74
+ @fem.integrand
75
+ def transported_inertia_form(s: fem.Sample, domain: fem.Domain, u: fem.Field, v: fem.Field, dt: float):
76
+ pos = domain(s)
77
+ vel = u(s)
78
+
79
+ conv_pos = pos - 0.5 * vel * dt
80
+ conv_s = fem.lookup(domain, conv_pos, s)
81
+ conv_vel = u(conv_s)
82
+
83
+ conv_pos = conv_pos - 0.5 * conv_vel * dt
84
+ conv_vel = u(fem.lookup(domain, conv_pos, conv_s))
85
+
86
+ return wp.dot(conv_vel, v(s)) / dt
87
+
88
+
89
+ @fem.integrand
90
+ def div_form(
91
+ s: fem.Sample,
92
+ u: fem.Field,
93
+ q: fem.Field,
94
+ ):
95
+ return -q(s) * fem.div(u, s)
96
+
97
+
98
+ class Example:
99
+ parser = argparse.ArgumentParser()
100
+ parser.add_argument("--resolution", type=int, default=25)
101
+ parser.add_argument("--degree", type=int, default=2)
102
+ parser.add_argument("--num_frames", type=int, default=1000)
103
+ parser.add_argument("--top_velocity", type=float, default=1.0)
104
+ parser.add_argument("--Re", type=float, default=1000.0)
105
+ parser.add_argument("--tri_mesh", action="store_true", help="Use a triangular mesh")
106
+
107
+ def __init__(self, stage=None, quiet=False, args=None, **kwargs):
108
+ if args is None:
109
+ # Read args from kwargs, add default arg values from parser
110
+ args = argparse.Namespace(**kwargs)
111
+ args = Example.parser.parse_args(args=[], namespace=args)
112
+ self._args = args
113
+ self._quiet = quiet
114
+
115
+ res = args.resolution
116
+ self.sim_dt = 1.0 / args.resolution
117
+ self.current_frame = 0
118
+
119
+ viscosity = args.top_velocity / args.Re
120
+
121
+ if args.tri_mesh:
122
+ positions, tri_vidx = gen_trimesh(res=wp.vec2i(res))
123
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
124
+ else:
125
+ geo = fem.Grid2D(res=wp.vec2i(res))
126
+
127
+ domain = fem.Cells(geometry=geo)
128
+ boundary = fem.BoundarySides(geo)
129
+
130
+ # Functions spaces: Q(d)-Q(d-1)
131
+ u_degree = args.degree
132
+ u_space = fem.make_polynomial_space(geo, degree=u_degree, dtype=wp.vec2)
133
+ p_space = fem.make_polynomial_space(geo, degree=u_degree - 1)
134
+
135
+ # Viscosity and inertia
136
+ u_test = fem.make_test(space=u_space, domain=domain)
137
+ u_trial = fem.make_trial(space=u_space, domain=domain)
138
+
139
+ u_matrix = fem.integrate(
140
+ viscosity_and_inertia_form,
141
+ fields={"u": u_trial, "v": u_test},
142
+ values={"nu": viscosity, "dt": self.sim_dt},
143
+ )
144
+
145
+ # Pressure-velocity coupling
146
+ p_test = fem.make_test(space=p_space, domain=domain)
147
+ div_matrix = fem.integrate(div_form, fields={"u": u_trial, "q": p_test})
148
+
149
+ # Enforcing the Dirichlet boundary condition the hard way;
150
+ # build projector for velocity left- and right-hand-sides
151
+ u_bd_test = fem.make_test(space=u_space, domain=boundary)
152
+ u_bd_trial = fem.make_trial(space=u_space, domain=boundary)
153
+ u_bd_projector = fem.integrate(mass_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True)
154
+ u_bd_value = fem.integrate(
155
+ u_boundary_value,
156
+ fields={"v": u_bd_test},
157
+ values={"top_vel": args.top_velocity},
158
+ nodal=True,
159
+ output_dtype=wp.vec2d,
160
+ )
161
+
162
+ fem.normalize_dirichlet_projector(u_bd_projector, u_bd_value)
163
+
164
+ u_bd_rhs = wp.zeros_like(u_bd_value)
165
+ fem.project_linear_system(u_matrix, u_bd_rhs, u_bd_projector, u_bd_value, normalize_projector=False)
166
+
167
+ # div_bd_rhs = div_matrix * u_bd_rhs
168
+ div_bd_rhs = wp.zeros(shape=(div_matrix.nrow,), dtype=div_matrix.scalar_type)
169
+ bsr_mv(div_matrix, u_bd_value, y=div_bd_rhs, alpha=-1.0)
170
+
171
+ # div_matrix = div_matrix - div_matrix * bd_projector
172
+ bsr_mm(x=bsr_copy(div_matrix), y=u_bd_projector, z=div_matrix, alpha=-1.0, beta=1.0)
173
+
174
+ # Assemble saddle system
175
+ self._saddle_system = SaddleSystem(u_matrix, div_matrix)
176
+
177
+ # Save data for computing time steps rhs
178
+ self._u_bd_projector = u_bd_projector
179
+ self._u_bd_rhs = u_bd_rhs
180
+ self._u_test = u_test
181
+ self._div_bd_rhs = div_bd_rhs
182
+
183
+ # Velocitiy and pressure fields
184
+ self._u_field = u_space.make_field()
185
+ self._p_field = p_space.make_field()
186
+
187
+ self.renderer = Plot(stage)
188
+ self.renderer.add_surface_vector("velocity", self._u_field)
189
+
190
+ def step(self):
191
+ self.current_frame += 1
192
+
193
+ u_rhs = fem.integrate(
194
+ transported_inertia_form,
195
+ fields={"u": self._u_field, "v": self._u_test},
196
+ values={"dt": self.sim_dt},
197
+ output_dtype=wp.vec2d,
198
+ )
199
+
200
+ # Apply boundary conditions
201
+ # u_rhs = (I - P) * u_rhs + u_bd_rhs
202
+ bsr_mv(self._u_bd_projector, x=u_rhs, y=u_rhs, alpha=-1.0, beta=1.0)
203
+ array_axpy(x=self._u_bd_rhs, y=u_rhs, alpha=1.0, beta=1.0)
204
+
205
+ p_rhs = self._div_bd_rhs
206
+
207
+ x_u = wp.empty_like(u_rhs)
208
+ x_p = wp.empty_like(p_rhs)
209
+ wp.utils.array_cast(out_array=x_u, in_array=self._u_field.dof_values)
210
+ wp.utils.array_cast(out_array=x_p, in_array=self._p_field.dof_values)
211
+
212
+ bsr_solve_saddle(
213
+ saddle_system=self._saddle_system,
214
+ tol=1.0e-6,
215
+ x_u=x_u,
216
+ x_p=x_p,
217
+ b_u=u_rhs,
218
+ b_p=p_rhs,
219
+ quiet=self._quiet,
220
+ )
221
+
222
+ wp.utils.array_cast(in_array=x_u, out_array=self._u_field.dof_values)
223
+ wp.utils.array_cast(in_array=x_p, out_array=self._p_field.dof_values)
224
+
225
+ def render(self):
226
+ self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
227
+ self.renderer.add_surface_vector("velocity", self._u_field)
228
+ self.renderer.end_frame()
229
+
230
+
231
+ if __name__ == "__main__":
232
+ wp.set_module_options({"enable_backward": False})
233
+
234
+ args = Example.parser.parse_args()
235
+
236
+ example = Example(args=args)
237
+ for k in range(args.num_frames):
238
+ print(f"Frame {k}:")
239
+ example.step()
240
+ example.render()
241
+
242
+ example.renderer.add_surface_vector("velocity_final", example._u_field)
243
+ example.renderer.plot(streamlines=set(["velocity_final"]))
@@ -0,0 +1,192 @@
1
+ # Copyright (c) 2022 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 Stokes
10
+ #
11
+ # This example solves a 2D Stokes flow problem
12
+ #
13
+ # -nu D(u) + grad p = 0
14
+ # Div u = 0
15
+ #
16
+ # with (soft) velocity-Dirichlet boundary conditions
17
+ ###########################################################################
18
+
19
+ import argparse
20
+
21
+ import warp as wp
22
+
23
+ import warp.fem as fem
24
+ from warp.fem.utils import array_axpy
25
+
26
+ import warp.sparse as sparse
27
+
28
+ try:
29
+ from .plot_utils import Plot
30
+ from .bsr_utils import bsr_solve_saddle, SaddleSystem
31
+ from .mesh_utils import gen_trimesh, gen_quadmesh
32
+ except ImportError:
33
+ from plot_utils import Plot
34
+ from bsr_utils import bsr_solve_saddle, SaddleSystem
35
+ from mesh_utils import gen_trimesh, gen_quadmesh
36
+
37
+ wp.init()
38
+
39
+
40
+ @fem.integrand
41
+ def constant_form(val: wp.vec2):
42
+ return val
43
+
44
+
45
+ @fem.integrand
46
+ def viscosity_form(s: fem.Sample, u: fem.Field, v: fem.Field, nu: float):
47
+ return nu * wp.ddot(fem.D(u, s), fem.D(v, s))
48
+
49
+
50
+ @fem.integrand
51
+ def top_mass_form(
52
+ s: fem.Sample,
53
+ domain: fem.Domain,
54
+ u: fem.Field,
55
+ v: fem.Field,
56
+ ):
57
+ # non zero on top boundary of domain only
58
+ nor = fem.normal(domain, s)
59
+ return wp.dot(u(s), v(s)) * wp.max(0.0, nor[1])
60
+
61
+
62
+ @fem.integrand
63
+ def mass_form(
64
+ s: fem.Sample,
65
+ u: fem.Field,
66
+ v: fem.Field,
67
+ ):
68
+ return wp.dot(u(s), v(s))
69
+
70
+
71
+ @fem.integrand
72
+ def div_form(
73
+ s: fem.Sample,
74
+ u: fem.Field,
75
+ q: fem.Field,
76
+ ):
77
+ return q(s) * fem.div(u, s)
78
+
79
+
80
+ class Example:
81
+ parser = argparse.ArgumentParser()
82
+ parser.add_argument("--resolution", type=int, default=50)
83
+ parser.add_argument("--degree", type=int, default=2)
84
+ parser.add_argument("--top_velocity", type=float, default=1.0)
85
+ parser.add_argument("--viscosity", type=float, default=1.0)
86
+ parser.add_argument("--boundary_strength", type=float, default=100.0)
87
+ parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
88
+ parser.add_argument(
89
+ "--nonconforming_pressures", action="store_true", help="For grid, use non-conforming pressure (Q_d/P_{d-1})"
90
+ )
91
+
92
+ def __init__(self, stage=None, quiet=False, args=None, **kwargs):
93
+ if args is None:
94
+ # Read args from kwargs, add default arg values from parser
95
+ args = argparse.Namespace(**kwargs)
96
+ args = Example.parser.parse_args(args=[], namespace=args)
97
+ self._args = args
98
+ self._quiet = quiet
99
+
100
+ # Grid or triangle mesh geometry
101
+ if args.mesh == "tri":
102
+ positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
103
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
104
+ elif args.mesh == "quad":
105
+ positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
106
+ geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
107
+ else:
108
+ geo = fem.Grid2D(res=wp.vec2i(args.resolution))
109
+
110
+ # Function spaces -- Q_d for vel, P_{d-1} for pressure
111
+ u_space = fem.make_polynomial_space(geo, degree=args.degree, dtype=wp.vec2)
112
+ if args.mesh != "tri" and args.nonconforming_pressures:
113
+ p_space = fem.make_polynomial_space(
114
+ geo, degree=args.degree - 1, element_basis=fem.ElementBasis.NONCONFORMING_POLYNOMIAL
115
+ )
116
+ else:
117
+ p_space = fem.make_polynomial_space(geo, degree=args.degree - 1)
118
+
119
+ # Vector and scalar fields
120
+ self._u_field = u_space.make_field()
121
+ self._p_field = p_space.make_field()
122
+
123
+ # Interpolate initial condition on boundary (for example purposes)
124
+ self._bd_field = u_space.make_field()
125
+ f_boundary = fem.make_restriction(self._bd_field, domain=fem.BoundarySides(geo))
126
+ top_velocity = wp.vec2(args.top_velocity, 0.0)
127
+ fem.interpolate(constant_form, dest=f_boundary, values={"val": top_velocity})
128
+
129
+ self.renderer = Plot(stage)
130
+
131
+ def step(self):
132
+ args = self._args
133
+ u_space = self._u_field.space
134
+ p_space = self._p_field.space
135
+ geo = u_space.geometry
136
+
137
+ domain = fem.Cells(geometry=geo)
138
+ boundary = fem.BoundarySides(geo)
139
+
140
+ # Viscosity
141
+ u_test = fem.make_test(space=u_space, domain=domain)
142
+ u_trial = fem.make_trial(space=u_space, domain=domain)
143
+
144
+ u_visc_matrix = fem.integrate(
145
+ viscosity_form,
146
+ fields={"u": u_trial, "v": u_test},
147
+ values={"nu": args.viscosity},
148
+ )
149
+
150
+ # Weak velocity boundary conditions
151
+ u_bd_test = fem.make_test(space=u_space, domain=boundary)
152
+ u_bd_trial = fem.make_trial(space=u_space, domain=boundary)
153
+ u_rhs = fem.integrate(
154
+ top_mass_form, fields={"u": self._bd_field.trace(), "v": u_bd_test}, output_dtype=wp.vec2d
155
+ )
156
+ u_bd_matrix = fem.integrate(mass_form, fields={"u": u_bd_trial, "v": u_bd_test})
157
+
158
+ # Pressure-velocity coupling
159
+ p_test = fem.make_test(space=p_space, domain=domain)
160
+ div_matrix = fem.integrate(div_form, fields={"u": u_trial, "q": p_test})
161
+
162
+ # Define and solve the saddle-point system
163
+ u_matrix = u_visc_matrix
164
+ sparse.bsr_axpy(x=u_bd_matrix, y=u_matrix, alpha=args.boundary_strength, beta=1.0)
165
+ array_axpy(x=u_rhs, y=u_rhs, alpha=0.0, beta=args.boundary_strength)
166
+
167
+ p_rhs = wp.zeros(p_space.node_count(), dtype=wp.float64)
168
+ x_u = wp.zeros_like(u_rhs)
169
+ x_p = wp.zeros_like(p_rhs)
170
+
171
+ bsr_solve_saddle(
172
+ 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
173
+ )
174
+
175
+ wp.utils.array_cast(in_array=x_u, out_array=self._u_field.dof_values)
176
+ wp.utils.array_cast(in_array=x_p, out_array=self._p_field.dof_values)
177
+
178
+ def render(self):
179
+ self.renderer.add_surface("pressure", self._p_field)
180
+ self.renderer.add_surface_vector("velocity", self._u_field)
181
+
182
+
183
+ if __name__ == "__main__":
184
+ wp.set_module_options({"enable_backward": False})
185
+
186
+ args = Example.parser.parse_args()
187
+
188
+ example = Example(args=args)
189
+ example.step()
190
+ example.render()
191
+
192
+ example.renderer.plot()