warp-lang 1.2.2__py3-none-macosx_10_13_universal2.whl → 1.3.1__py3-none-macosx_10_13_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- warp/__init__.py +8 -6
- warp/autograd.py +823 -0
- warp/bin/libwarp.dylib +0 -0
- warp/build.py +6 -2
- warp/builtins.py +1412 -888
- warp/codegen.py +503 -166
- warp/config.py +48 -18
- warp/context.py +400 -198
- warp/dlpack.py +8 -0
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/benchmarks/benchmark_cloth_warp.py +1 -1
- warp/examples/benchmarks/benchmark_interop_torch.py +158 -0
- warp/examples/benchmarks/benchmark_launches.py +1 -1
- warp/examples/core/example_cupy.py +78 -0
- warp/examples/fem/example_apic_fluid.py +17 -36
- warp/examples/fem/example_burgers.py +9 -18
- warp/examples/fem/example_convection_diffusion.py +7 -17
- warp/examples/fem/example_convection_diffusion_dg.py +27 -47
- warp/examples/fem/example_deformed_geometry.py +11 -22
- warp/examples/fem/example_diffusion.py +7 -18
- warp/examples/fem/example_diffusion_3d.py +24 -28
- warp/examples/fem/example_diffusion_mgpu.py +7 -14
- warp/examples/fem/example_magnetostatics.py +190 -0
- warp/examples/fem/example_mixed_elasticity.py +111 -80
- warp/examples/fem/example_navier_stokes.py +30 -34
- warp/examples/fem/example_nonconforming_contact.py +290 -0
- warp/examples/fem/example_stokes.py +17 -32
- warp/examples/fem/example_stokes_transfer.py +12 -21
- warp/examples/fem/example_streamlines.py +350 -0
- warp/examples/fem/utils.py +936 -0
- warp/fabric.py +5 -2
- warp/fem/__init__.py +13 -3
- warp/fem/cache.py +161 -11
- warp/fem/dirichlet.py +37 -28
- warp/fem/domain.py +105 -14
- warp/fem/field/__init__.py +14 -3
- warp/fem/field/field.py +454 -11
- warp/fem/field/nodal_field.py +33 -18
- warp/fem/geometry/deformed_geometry.py +50 -15
- warp/fem/geometry/hexmesh.py +12 -24
- warp/fem/geometry/nanogrid.py +106 -31
- warp/fem/geometry/quadmesh_2d.py +6 -11
- warp/fem/geometry/tetmesh.py +103 -61
- warp/fem/geometry/trimesh_2d.py +98 -47
- warp/fem/integrate.py +231 -186
- warp/fem/operator.py +14 -9
- warp/fem/quadrature/pic_quadrature.py +35 -9
- warp/fem/quadrature/quadrature.py +119 -32
- warp/fem/space/basis_space.py +98 -22
- warp/fem/space/collocated_function_space.py +3 -1
- warp/fem/space/function_space.py +7 -2
- warp/fem/space/grid_2d_function_space.py +3 -3
- warp/fem/space/grid_3d_function_space.py +4 -4
- warp/fem/space/hexmesh_function_space.py +3 -2
- warp/fem/space/nanogrid_function_space.py +12 -14
- warp/fem/space/partition.py +45 -47
- warp/fem/space/restriction.py +19 -16
- warp/fem/space/shape/cube_shape_function.py +91 -3
- warp/fem/space/shape/shape_function.py +7 -0
- warp/fem/space/shape/square_shape_function.py +32 -0
- warp/fem/space/shape/tet_shape_function.py +11 -7
- warp/fem/space/shape/triangle_shape_function.py +10 -1
- warp/fem/space/topology.py +116 -42
- warp/fem/types.py +8 -1
- warp/fem/utils.py +301 -83
- warp/native/array.h +16 -0
- warp/native/builtin.h +0 -15
- warp/native/cuda_util.cpp +14 -6
- warp/native/exports.h +1348 -1308
- warp/native/quat.h +79 -0
- warp/native/rand.h +27 -4
- warp/native/sparse.cpp +83 -81
- warp/native/sparse.cu +381 -453
- warp/native/vec.h +64 -0
- warp/native/volume.cpp +40 -49
- warp/native/volume_builder.cu +2 -3
- warp/native/volume_builder.h +12 -17
- warp/native/warp.cu +3 -3
- warp/native/warp.h +69 -59
- warp/render/render_opengl.py +17 -9
- warp/sim/articulation.py +117 -17
- warp/sim/collide.py +35 -29
- warp/sim/model.py +123 -18
- warp/sim/render.py +3 -1
- warp/sparse.py +867 -203
- warp/stubs.py +312 -541
- warp/tape.py +29 -1
- warp/tests/disabled_kinematics.py +1 -1
- warp/tests/test_adam.py +1 -1
- warp/tests/test_arithmetic.py +1 -1
- warp/tests/test_array.py +58 -1
- warp/tests/test_array_reduce.py +1 -1
- warp/tests/test_async.py +1 -1
- warp/tests/test_atomic.py +1 -1
- warp/tests/test_bool.py +1 -1
- warp/tests/test_builtins_resolution.py +1 -1
- warp/tests/test_bvh.py +6 -1
- warp/tests/test_closest_point_edge_edge.py +1 -1
- warp/tests/test_codegen.py +91 -1
- warp/tests/test_compile_consts.py +1 -1
- warp/tests/test_conditional.py +1 -1
- warp/tests/test_copy.py +1 -1
- warp/tests/test_ctypes.py +1 -1
- warp/tests/test_dense.py +1 -1
- warp/tests/test_devices.py +1 -1
- warp/tests/test_dlpack.py +1 -1
- warp/tests/test_examples.py +33 -4
- warp/tests/test_fabricarray.py +5 -2
- warp/tests/test_fast_math.py +1 -1
- warp/tests/test_fem.py +213 -6
- warp/tests/test_fp16.py +1 -1
- warp/tests/test_func.py +1 -1
- warp/tests/test_future_annotations.py +90 -0
- warp/tests/test_generics.py +1 -1
- warp/tests/test_grad.py +1 -1
- warp/tests/test_grad_customs.py +1 -1
- warp/tests/test_grad_debug.py +247 -0
- warp/tests/test_hash_grid.py +6 -1
- warp/tests/test_implicit_init.py +354 -0
- warp/tests/test_import.py +1 -1
- warp/tests/test_indexedarray.py +1 -1
- warp/tests/test_intersect.py +1 -1
- warp/tests/test_jax.py +1 -1
- warp/tests/test_large.py +1 -1
- warp/tests/test_launch.py +1 -1
- warp/tests/test_lerp.py +1 -1
- warp/tests/test_linear_solvers.py +1 -1
- warp/tests/test_lvalue.py +1 -1
- warp/tests/test_marching_cubes.py +5 -2
- warp/tests/test_mat.py +34 -35
- warp/tests/test_mat_lite.py +2 -1
- warp/tests/test_mat_scalar_ops.py +1 -1
- warp/tests/test_math.py +1 -1
- warp/tests/test_matmul.py +20 -16
- warp/tests/test_matmul_lite.py +1 -1
- warp/tests/test_mempool.py +1 -1
- warp/tests/test_mesh.py +5 -2
- warp/tests/test_mesh_query_aabb.py +1 -1
- warp/tests/test_mesh_query_point.py +1 -1
- warp/tests/test_mesh_query_ray.py +1 -1
- warp/tests/test_mlp.py +1 -1
- warp/tests/test_model.py +1 -1
- warp/tests/test_module_hashing.py +77 -1
- warp/tests/test_modules_lite.py +1 -1
- warp/tests/test_multigpu.py +1 -1
- warp/tests/test_noise.py +1 -1
- warp/tests/test_operators.py +1 -1
- warp/tests/test_options.py +1 -1
- warp/tests/test_overwrite.py +542 -0
- warp/tests/test_peer.py +1 -1
- warp/tests/test_pinned.py +1 -1
- warp/tests/test_print.py +1 -1
- warp/tests/test_quat.py +15 -1
- warp/tests/test_rand.py +1 -1
- warp/tests/test_reload.py +1 -1
- warp/tests/test_rounding.py +1 -1
- warp/tests/test_runlength_encode.py +1 -1
- warp/tests/test_scalar_ops.py +95 -0
- warp/tests/test_sim_grad.py +1 -1
- warp/tests/test_sim_kinematics.py +1 -1
- warp/tests/test_smoothstep.py +1 -1
- warp/tests/test_sparse.py +82 -15
- warp/tests/test_spatial.py +1 -1
- warp/tests/test_special_values.py +2 -11
- warp/tests/test_streams.py +11 -1
- warp/tests/test_struct.py +1 -1
- warp/tests/test_tape.py +1 -1
- warp/tests/test_torch.py +194 -1
- warp/tests/test_transient_module.py +1 -1
- warp/tests/test_types.py +1 -1
- warp/tests/test_utils.py +1 -1
- warp/tests/test_vec.py +15 -63
- warp/tests/test_vec_lite.py +2 -1
- warp/tests/test_vec_scalar_ops.py +65 -1
- warp/tests/test_verify_fp.py +1 -1
- warp/tests/test_volume.py +28 -2
- warp/tests/test_volume_write.py +1 -1
- warp/tests/unittest_serial.py +1 -1
- warp/tests/unittest_suites.py +9 -1
- warp/tests/walkthrough_debug.py +1 -1
- warp/thirdparty/unittest_parallel.py +2 -5
- warp/torch.py +103 -41
- warp/types.py +341 -224
- warp/utils.py +11 -2
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/METADATA +99 -46
- warp_lang-1.3.1.dist-info/RECORD +368 -0
- warp/examples/fem/bsr_utils.py +0 -378
- warp/examples/fem/mesh_utils.py +0 -133
- warp/examples/fem/plot_utils.py +0 -292
- warp_lang-1.2.2.dist-info/RECORD +0 -359
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/WHEEL +0 -0
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.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
|
-
|
|
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
|
-
|
|
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),
|
|
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.
|
|
170
|
-
self.renderer.
|
|
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
|
-
|
|
176
|
+
u_matrix += u_bd_matrix * self.bd_strength
|
|
186
177
|
|
|
187
|
-
|
|
188
|
-
gradient_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 =
|
|
199
|
-
p_res =
|
|
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.
|
|
210
|
-
self.renderer.
|
|
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(
|
|
254
|
+
example.renderer.plot(options={"velocity": {"streamlines": {}}})
|