warp-lang 1.2.2__py3-none-manylinux2014_x86_64.whl → 1.3.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.
- warp/__init__.py +8 -6
- warp/autograd.py +823 -0
- warp/bin/warp.so +0 -0
- warp/build.py +6 -2
- warp/builtins.py +1410 -886
- 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 +66 -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.0.dist-info}/METADATA +99 -46
- warp_lang-1.3.0.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.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.0.dist-info}/WHEEL +0 -0
- {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
|
+
)
|