warp-lang 1.3.3__py3-none-manylinux2014_aarch64.whl → 1.4.0__py3-none-manylinux2014_aarch64.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 +6 -0
- warp/autograd.py +59 -6
- warp/bin/warp.so +0 -0
- warp/build_dll.py +8 -10
- warp/builtins.py +126 -4
- warp/codegen.py +435 -53
- warp/config.py +1 -1
- warp/context.py +678 -403
- warp/dlpack.py +2 -0
- warp/examples/benchmarks/benchmark_cloth.py +10 -0
- warp/examples/core/example_render_opengl.py +12 -10
- warp/examples/fem/example_adaptive_grid.py +251 -0
- warp/examples/fem/example_apic_fluid.py +1 -1
- warp/examples/fem/example_diffusion_3d.py +2 -2
- warp/examples/fem/example_magnetostatics.py +1 -1
- warp/examples/fem/example_streamlines.py +1 -0
- warp/examples/fem/utils.py +23 -4
- warp/examples/sim/example_cloth.py +50 -6
- warp/fem/__init__.py +2 -0
- warp/fem/adaptivity.py +493 -0
- warp/fem/field/field.py +2 -1
- warp/fem/field/nodal_field.py +18 -26
- warp/fem/field/test.py +4 -4
- warp/fem/field/trial.py +4 -4
- warp/fem/geometry/__init__.py +1 -0
- warp/fem/geometry/adaptive_nanogrid.py +843 -0
- warp/fem/geometry/nanogrid.py +55 -28
- warp/fem/space/__init__.py +1 -1
- warp/fem/space/nanogrid_function_space.py +69 -35
- warp/fem/utils.py +113 -107
- warp/jax_experimental.py +28 -15
- warp/native/array.h +0 -1
- warp/native/builtin.h +103 -6
- warp/native/bvh.cu +2 -0
- warp/native/cuda_util.cpp +14 -0
- warp/native/cuda_util.h +2 -0
- warp/native/error.cpp +4 -2
- warp/native/exports.h +99 -17
- warp/native/mat.h +97 -0
- warp/native/mesh.cpp +36 -0
- warp/native/mesh.cu +51 -0
- warp/native/mesh.h +1 -0
- warp/native/quat.h +43 -0
- warp/native/spatial.h +6 -0
- warp/native/vec.h +74 -0
- warp/native/warp.cpp +2 -1
- warp/native/warp.cu +10 -3
- warp/native/warp.h +8 -1
- warp/paddle.py +382 -0
- warp/sim/__init__.py +1 -0
- warp/sim/collide.py +519 -0
- warp/sim/integrator_euler.py +18 -5
- warp/sim/integrator_featherstone.py +5 -5
- warp/sim/integrator_vbd.py +1026 -0
- warp/sim/model.py +49 -23
- warp/stubs.py +459 -0
- warp/tape.py +2 -0
- warp/tests/aux_test_dependent.py +1 -0
- warp/tests/aux_test_name_clash1.py +32 -0
- warp/tests/aux_test_name_clash2.py +32 -0
- warp/tests/aux_test_square.py +1 -0
- warp/tests/test_array.py +188 -0
- warp/tests/test_async.py +3 -3
- warp/tests/test_atomic.py +6 -0
- warp/tests/test_closest_point_edge_edge.py +93 -1
- warp/tests/test_codegen.py +62 -15
- warp/tests/test_codegen_instancing.py +1457 -0
- warp/tests/test_collision.py +486 -0
- warp/tests/test_compile_consts.py +3 -28
- warp/tests/test_dlpack.py +170 -0
- warp/tests/test_examples.py +22 -8
- warp/tests/test_fast_math.py +10 -4
- warp/tests/test_fem.py +64 -0
- warp/tests/test_func.py +46 -0
- warp/tests/test_implicit_init.py +49 -0
- warp/tests/test_jax.py +58 -0
- warp/tests/test_mat.py +84 -0
- warp/tests/test_mesh_query_point.py +188 -0
- warp/tests/test_module_hashing.py +40 -0
- warp/tests/test_multigpu.py +3 -3
- warp/tests/test_overwrite.py +8 -0
- warp/tests/test_paddle.py +852 -0
- warp/tests/test_print.py +89 -0
- warp/tests/test_quat.py +111 -0
- warp/tests/test_reload.py +31 -1
- warp/tests/test_scalar_ops.py +2 -0
- warp/tests/test_static.py +412 -0
- warp/tests/test_streams.py +64 -3
- warp/tests/test_struct.py +4 -4
- warp/tests/test_torch.py +24 -0
- warp/tests/test_triangle_closest_point.py +137 -0
- warp/tests/test_types.py +1 -1
- warp/tests/test_vbd.py +386 -0
- warp/tests/test_vec.py +143 -0
- warp/tests/test_vec_scalar_ops.py +139 -0
- warp/tests/unittest_suites.py +12 -0
- warp/tests/unittest_utils.py +9 -5
- warp/thirdparty/dlpack.py +3 -1
- warp/types.py +150 -28
- warp/utils.py +37 -14
- {warp_lang-1.3.3.dist-info → warp_lang-1.4.0.dist-info}/METADATA +10 -8
- {warp_lang-1.3.3.dist-info → warp_lang-1.4.0.dist-info}/RECORD +105 -93
- warp/tests/test_point_triangle_closest_point.py +0 -143
- {warp_lang-1.3.3.dist-info → warp_lang-1.4.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.3.3.dist-info → warp_lang-1.4.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.3.3.dist-info → warp_lang-1.4.0.dist-info}/top_level.txt +0 -0
warp/dlpack.py
CHANGED
|
@@ -124,6 +124,8 @@ def device_to_dlpack(wp_device) -> DLDevice:
|
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
def dtype_to_dlpack(wp_dtype) -> DLDataType:
|
|
127
|
+
if wp_dtype == warp.bool:
|
|
128
|
+
return (DLDataTypeCode.kDLBool, 8, 1)
|
|
127
129
|
if wp_dtype == warp.int8:
|
|
128
130
|
return (DLDataTypeCode.kDLInt, 8, 1)
|
|
129
131
|
elif wp_dtype == warp.uint8:
|
|
@@ -219,6 +219,16 @@ def run_benchmark(mode, dim, timers, render=False):
|
|
|
219
219
|
|
|
220
220
|
integrator = benchmark_cloth_jax.JxIntegrator(cloth)
|
|
221
221
|
|
|
222
|
+
elif mode == "paddle_cpu":
|
|
223
|
+
import benchmark_cloth_paddle
|
|
224
|
+
|
|
225
|
+
integrator = benchmark_cloth_paddle.TrIntegrator(cloth, "cpu")
|
|
226
|
+
|
|
227
|
+
elif mode == "paddle_gpu":
|
|
228
|
+
import benchmark_cloth_paddle
|
|
229
|
+
|
|
230
|
+
integrator = benchmark_cloth_paddle.TrIntegrator(cloth, "gpu")
|
|
231
|
+
|
|
222
232
|
else:
|
|
223
233
|
raise RuntimeError("Unknown simulation backend")
|
|
224
234
|
|
|
@@ -21,6 +21,9 @@ import warp.render
|
|
|
21
21
|
|
|
22
22
|
class Example:
|
|
23
23
|
def __init__(self, num_tiles=4, custom_tile_arrangement=False):
|
|
24
|
+
if num_tiles < 1:
|
|
25
|
+
raise ValueError("num_tiles must be greater than or equal to 1.")
|
|
26
|
+
|
|
24
27
|
self.renderer = wp.render.OpenGLRenderer(vsync=False)
|
|
25
28
|
instance_ids = []
|
|
26
29
|
|
|
@@ -31,16 +34,15 @@ class Example:
|
|
|
31
34
|
positions = None
|
|
32
35
|
sizes = None
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
for
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
self.renderer.setup_tiled_rendering(instance_ids, tile_positions=positions, tile_sizes=sizes)
|
|
37
|
+
# set up instances to hide one of the capsules in each tile
|
|
38
|
+
for i in range(num_tiles):
|
|
39
|
+
instances = [j for j in np.arange(13) if j != i + 2]
|
|
40
|
+
instance_ids.append(instances)
|
|
41
|
+
if custom_tile_arrangement:
|
|
42
|
+
angle = np.pi * 2.0 / num_tiles * i
|
|
43
|
+
positions.append((int(np.cos(angle) * 150 + 250), int(np.sin(angle) * 150 + 250)))
|
|
44
|
+
sizes.append((150, 150))
|
|
45
|
+
self.renderer.setup_tiled_rendering(instance_ids, tile_positions=positions, tile_sizes=sizes)
|
|
44
46
|
|
|
45
47
|
self.renderer.render_ground()
|
|
46
48
|
|
|
@@ -0,0 +1,251 @@
|
|
|
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 Adaptive Grid
|
|
10
|
+
#
|
|
11
|
+
# Demonstrates using an adaptive grid to increase the simulation resolition
|
|
12
|
+
# near a collider boundary.
|
|
13
|
+
#
|
|
14
|
+
###########################################################################
|
|
15
|
+
import os.path
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
import warp as wp
|
|
20
|
+
import warp.examples
|
|
21
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
22
|
+
import warp.fem as fem
|
|
23
|
+
from warp.examples.fem.example_apic_fluid import divergence_form, solve_incompressibility
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@fem.integrand
|
|
27
|
+
def inflow_velocity(
|
|
28
|
+
s: fem.Sample,
|
|
29
|
+
domain: fem.Domain,
|
|
30
|
+
bounds_lo: wp.vec3,
|
|
31
|
+
bounds_hi: wp.vec3,
|
|
32
|
+
):
|
|
33
|
+
x = fem.position(domain, s)
|
|
34
|
+
|
|
35
|
+
if x[1] <= bounds_lo[1] or x[2] <= bounds_lo[2] or x[1] >= bounds_hi[1] or x[2] >= bounds_hi[2]:
|
|
36
|
+
return wp.vec3(0.0)
|
|
37
|
+
|
|
38
|
+
if x[0] <= bounds_lo[0] or x[0] >= bounds_hi[0]:
|
|
39
|
+
return wp.vec3(1.0, 0.0, 0.0)
|
|
40
|
+
|
|
41
|
+
return wp.vec3(0.0)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@fem.integrand
|
|
45
|
+
def noslip_projector_form(
|
|
46
|
+
s: fem.Sample,
|
|
47
|
+
u: fem.Field,
|
|
48
|
+
v: fem.Field,
|
|
49
|
+
):
|
|
50
|
+
return wp.dot(u(s), v(s))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@fem.integrand
|
|
54
|
+
def mass_form(
|
|
55
|
+
s: fem.Sample,
|
|
56
|
+
u: fem.Field,
|
|
57
|
+
v: fem.Field,
|
|
58
|
+
):
|
|
59
|
+
return u(s) * v(s)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@fem.integrand
|
|
63
|
+
def side_divergence_form(s: fem.Sample, domain: fem.Domain, u: fem.Field, psi: fem.Field):
|
|
64
|
+
# normal velocity jump (non-zero at resolution boundaries)
|
|
65
|
+
return -wp.dot(fem.jump(u, s), fem.normal(domain, s)) * psi(s)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@wp.func
|
|
69
|
+
def refinement_field(xyz: wp.vec3, volume: wp.uint64):
|
|
70
|
+
# use distance to collider as refinement function
|
|
71
|
+
uvw = wp.volume_world_to_index(volume, xyz)
|
|
72
|
+
sdf = wp.volume_sample_f(volume, uvw, wp.Volume.LINEAR)
|
|
73
|
+
|
|
74
|
+
if sdf < 0.0:
|
|
75
|
+
return sdf
|
|
76
|
+
|
|
77
|
+
# combine with heuristical distance to keep coarsening past nvdb narrowband
|
|
78
|
+
return 0.5 * wp.max(wp.length(xyz) - 20.0, sdf)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@fem.integrand
|
|
82
|
+
def pressure_anomaly_field(s: fem.Sample, domain: fem.Domain, pressure: fem.Field):
|
|
83
|
+
# for visualization, deduce affine part such that grad P = u_x
|
|
84
|
+
x = domain(s)
|
|
85
|
+
return pressure(s) + x[0]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Example:
|
|
89
|
+
def __init__(self, quiet=False, degree=2, base_resolution=8, level_count=4, headless: bool = False):
|
|
90
|
+
self._quiet = quiet
|
|
91
|
+
self._degree = degree
|
|
92
|
+
|
|
93
|
+
# Start from a coarse, dense grid
|
|
94
|
+
res = wp.vec3i(2 * base_resolution, base_resolution // 2, base_resolution)
|
|
95
|
+
bounds_lo = wp.vec3(-50.0, 0.0, -17.5)
|
|
96
|
+
bounds_hi = wp.vec3(50.0, 12.5, 17.5)
|
|
97
|
+
sim_vol = fem_example_utils.gen_volume(res=res, bounds_lo=bounds_lo, bounds_hi=bounds_hi)
|
|
98
|
+
|
|
99
|
+
# load collision volume
|
|
100
|
+
collider_path = os.path.join(warp.examples.get_asset_directory(), "rocks.nvdb")
|
|
101
|
+
with open(collider_path, "rb") as file:
|
|
102
|
+
# create Volume object
|
|
103
|
+
collider = wp.Volume.load_from_nvdb(file)
|
|
104
|
+
|
|
105
|
+
# Make adaptive grid from coarse base and refinement field
|
|
106
|
+
refinement = fem.ImplicitField(
|
|
107
|
+
domain=fem.Cells(fem.Nanogrid(sim_vol)), func=refinement_field, values={"volume": collider.id}
|
|
108
|
+
)
|
|
109
|
+
self._geo = fem.adaptivity.adaptive_nanogrid_from_field(
|
|
110
|
+
sim_vol, level_count, refinement_field=refinement, grading="face"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Function spaces for velocity, scalars and pressure (Pk / Pk / Pk-1)
|
|
114
|
+
self._u_basis = fem.make_polynomial_basis_space(geo=self._geo, degree=self._degree)
|
|
115
|
+
u_space = fem.make_collocated_function_space(self._u_basis, dtype=wp.vec3)
|
|
116
|
+
p_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree - 1, dtype=float)
|
|
117
|
+
|
|
118
|
+
self.pressure_field = p_space.make_field()
|
|
119
|
+
self.pressure_anomaly_field = p_space.make_field()
|
|
120
|
+
self.velocity_field = u_space.make_field()
|
|
121
|
+
|
|
122
|
+
# Initialize velocity field with BC
|
|
123
|
+
bounds_scale = 0.9999 # account for difference between bounds and actual grid extents
|
|
124
|
+
bounds_center = 0.5 * (bounds_hi + bounds_lo)
|
|
125
|
+
bounds_extent = 0.5 * (bounds_hi - bounds_lo)
|
|
126
|
+
fem.interpolate(
|
|
127
|
+
inflow_velocity,
|
|
128
|
+
dest=fem.make_restriction(self.velocity_field, domain=fem.BoundarySides(self._geo)),
|
|
129
|
+
values={
|
|
130
|
+
"bounds_lo": bounds_center - bounds_scale * bounds_extent,
|
|
131
|
+
"bounds_hi": bounds_center + bounds_scale * bounds_extent,
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
self.plot = fem_example_utils.Plot()
|
|
136
|
+
|
|
137
|
+
def render(self):
|
|
138
|
+
# self.renderer.add_field("solution", self.pressure_field)
|
|
139
|
+
self.plot.add_field("pressure_anomaly", self.pressure_anomaly_field)
|
|
140
|
+
self.plot.add_field("velocity", self.velocity_field)
|
|
141
|
+
|
|
142
|
+
def step(self):
|
|
143
|
+
u_space = self.velocity_field.space
|
|
144
|
+
p_space = self.pressure_field.space
|
|
145
|
+
|
|
146
|
+
# Boundary condition projector and matrices
|
|
147
|
+
boundary = fem.BoundarySides(self._geo)
|
|
148
|
+
bd_test = fem.make_test(u_space, domain=boundary)
|
|
149
|
+
bd_trial = fem.make_trial(u_space, domain=boundary)
|
|
150
|
+
dirichlet_projector = fem.integrate(
|
|
151
|
+
noslip_projector_form, fields={"u": bd_test, "v": bd_trial}, nodal=True, output_dtype=float
|
|
152
|
+
)
|
|
153
|
+
fem.normalize_dirichlet_projector(dirichlet_projector)
|
|
154
|
+
|
|
155
|
+
# (Diagonal) mass matrix
|
|
156
|
+
s_space = fem.make_collocated_function_space(self._u_basis, dtype=float)
|
|
157
|
+
rho_test = fem.make_test(s_space)
|
|
158
|
+
rho_trial = fem.make_trial(s_space)
|
|
159
|
+
inv_mass_matrix = fem.integrate(
|
|
160
|
+
mass_form, fields={"u": rho_trial, "v": rho_test}, nodal=True, output_dtype=float
|
|
161
|
+
)
|
|
162
|
+
fem_example_utils.invert_diagonal_bsr_matrix(inv_mass_matrix)
|
|
163
|
+
|
|
164
|
+
# Assemble divergence operator matrix
|
|
165
|
+
p_test = fem.make_test(p_space)
|
|
166
|
+
u_trial = fem.make_trial(u_space)
|
|
167
|
+
divergence_matrix = fem.integrate(
|
|
168
|
+
divergence_form,
|
|
169
|
+
fields={"u": u_trial, "psi": p_test},
|
|
170
|
+
output_dtype=float,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# need to account for discontinuities at resolution boundaries (t-junctions)
|
|
174
|
+
p_side_test = fem.make_test(p_space, domain=fem.Sides(self._geo))
|
|
175
|
+
u_side_trial = fem.make_trial(u_space, domain=fem.Sides(self._geo))
|
|
176
|
+
divergence_matrix += fem.integrate(
|
|
177
|
+
side_divergence_form,
|
|
178
|
+
fields={"u": u_side_trial, "psi": p_side_test},
|
|
179
|
+
output_dtype=float,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Solve incompressibility
|
|
183
|
+
solve_incompressibility(
|
|
184
|
+
divergence_matrix,
|
|
185
|
+
dirichlet_projector,
|
|
186
|
+
inv_mass_matrix.values,
|
|
187
|
+
self.pressure_field.dof_values,
|
|
188
|
+
self.velocity_field.dof_values,
|
|
189
|
+
quiet=self._quiet,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
fem.interpolate(
|
|
193
|
+
pressure_anomaly_field,
|
|
194
|
+
dest=self.pressure_anomaly_field,
|
|
195
|
+
fields={"pressure": self.pressure_field},
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
if __name__ == "__main__":
|
|
200
|
+
import argparse
|
|
201
|
+
|
|
202
|
+
wp.set_module_options({"enable_backward": False})
|
|
203
|
+
|
|
204
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
205
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
206
|
+
parser.add_argument("--resolution", type=int, default=8, help="Grid resolution.")
|
|
207
|
+
parser.add_argument("--degree", type=int, default=2, help="Polynomial degree of shape functions.")
|
|
208
|
+
parser.add_argument("--level_count", type=int, default=4, help="Number of refinement levels.")
|
|
209
|
+
parser.add_argument(
|
|
210
|
+
"--headless",
|
|
211
|
+
action="store_true",
|
|
212
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
213
|
+
)
|
|
214
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
215
|
+
|
|
216
|
+
args = parser.parse_known_args()[0]
|
|
217
|
+
|
|
218
|
+
with wp.ScopedDevice(args.device):
|
|
219
|
+
example = Example(
|
|
220
|
+
quiet=args.quiet,
|
|
221
|
+
degree=args.degree,
|
|
222
|
+
base_resolution=args.resolution,
|
|
223
|
+
level_count=args.level_count,
|
|
224
|
+
headless=args.headless,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
example.step()
|
|
228
|
+
example.render()
|
|
229
|
+
|
|
230
|
+
if not args.headless:
|
|
231
|
+
ref_geom = None
|
|
232
|
+
try:
|
|
233
|
+
from pxr import Usd, UsdGeom
|
|
234
|
+
|
|
235
|
+
stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "rocks.usd"))
|
|
236
|
+
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/rocks"))
|
|
237
|
+
points = np.array((mesh.GetPointsAttr().Get()))
|
|
238
|
+
counts = np.array((mesh.GetFaceVertexCountsAttr().Get()))
|
|
239
|
+
indices = np.array(mesh.GetFaceVertexIndicesAttr().Get())
|
|
240
|
+
ref_geom = (points, counts, indices)
|
|
241
|
+
except Exception:
|
|
242
|
+
pass
|
|
243
|
+
|
|
244
|
+
example.plot.plot(
|
|
245
|
+
{
|
|
246
|
+
"rows": 2,
|
|
247
|
+
"ref_geom": ref_geom,
|
|
248
|
+
"velocity": {"streamlines": {"density": 25, "glyph_scale": 0.01}},
|
|
249
|
+
"pressure_anomaly": {},
|
|
250
|
+
}
|
|
251
|
+
)
|
|
@@ -169,7 +169,7 @@ def solve_incompressibility(
|
|
|
169
169
|
# For simplicity, assemble Schur complement and solve with CG
|
|
170
170
|
schur = bsr_mm(divergence_mat, transposed_divergence_mat)
|
|
171
171
|
|
|
172
|
-
fem_example_utils.bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6)
|
|
172
|
+
fem_example_utils.bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6, method="cr", max_iters=1000)
|
|
173
173
|
|
|
174
174
|
# Apply pressure to velocity
|
|
175
175
|
bsr_mv(A=transposed_divergence_mat, x=pressure, y=velocity, alpha=1.0, beta=1.0)
|
|
@@ -146,7 +146,7 @@ if __name__ == "__main__":
|
|
|
146
146
|
parser.add_argument(
|
|
147
147
|
"--boundary_compliance", type=float, default=0.0, help="Dirichlet boundary condition compliance."
|
|
148
148
|
)
|
|
149
|
-
parser.add_argument("--mesh", choices=("grid", "tet", "hex", "nano"), default="grid", help="Mesh type.")
|
|
149
|
+
parser.add_argument("--mesh", choices=("grid", "tet", "hex", "nano", "anano"), default="grid", help="Mesh type.")
|
|
150
150
|
parser.add_argument(
|
|
151
151
|
"--headless",
|
|
152
152
|
action="store_true",
|
|
@@ -171,4 +171,4 @@ if __name__ == "__main__":
|
|
|
171
171
|
example.render()
|
|
172
172
|
|
|
173
173
|
if not args.headless:
|
|
174
|
-
example.renderer.plot()
|
|
174
|
+
example.renderer.plot(backend="matplotlib")
|
|
@@ -150,7 +150,7 @@ class Example:
|
|
|
150
150
|
x = wp.zeros_like(rhs)
|
|
151
151
|
fem_example_utils.bsr_cg(lhs, b=rhs, x=x, tol=1.0e-8, quiet=False)
|
|
152
152
|
|
|
153
|
-
# make sure result is exactly zero
|
|
153
|
+
# make sure result is exactly zero outside of circle
|
|
154
154
|
wp.sparse.bsr_mv(dirichlet_bd_proj, x=x, y=x, alpha=-1.0, beta=1.0)
|
|
155
155
|
wp.utils.array_cast(in_array=x, out_array=self.A_field.dof_values)
|
|
156
156
|
|
|
@@ -255,6 +255,7 @@ class Example:
|
|
|
255
255
|
self.renderer.render_line_list("streamlines", vertices, indices)
|
|
256
256
|
self.renderer.render_line_list("streamlines", vertices, indices, colors)
|
|
257
257
|
|
|
258
|
+
self.renderer.paused = True
|
|
258
259
|
self.renderer.end_frame()
|
|
259
260
|
|
|
260
261
|
def _generate_incompressible_flow(self):
|
warp/examples/fem/utils.py
CHANGED
|
@@ -177,7 +177,9 @@ def gen_volume(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp.
|
|
|
177
177
|
|
|
178
178
|
ijk = np.transpose(np.meshgrid(x, y, z), axes=(1, 2, 3, 0)).reshape(-1, 3)
|
|
179
179
|
ijk = wp.array(ijk, dtype=wp.vec3i, device=device)
|
|
180
|
-
return wp.Volume.allocate_by_voxels(
|
|
180
|
+
return wp.Volume.allocate_by_voxels(
|
|
181
|
+
ijk, voxel_size=voxel_size, translation=bounds_lo + 0.5 * voxel_size, device=device
|
|
182
|
+
)
|
|
181
183
|
|
|
182
184
|
|
|
183
185
|
#
|
|
@@ -579,6 +581,19 @@ class Plot:
|
|
|
579
581
|
|
|
580
582
|
animate = False
|
|
581
583
|
|
|
584
|
+
ref_geom = options.get("ref_geom", None)
|
|
585
|
+
if ref_geom is not None:
|
|
586
|
+
if isinstance(ref_geom, tuple):
|
|
587
|
+
vertices, counts, indices = ref_geom
|
|
588
|
+
offsets = np.cumsum(counts)
|
|
589
|
+
ranges = np.array([offsets - counts, offsets]).T
|
|
590
|
+
faces = np.concatenate(
|
|
591
|
+
[[count] + list(indices[beg:end]) for (count, (beg, end)) in zip(counts, ranges)]
|
|
592
|
+
)
|
|
593
|
+
ref_geom = pyvista.PolyData(vertices, faces)
|
|
594
|
+
else:
|
|
595
|
+
ref_geom = pyvista.PolyData(ref_geom)
|
|
596
|
+
|
|
582
597
|
for name, (field, values) in self._fields.items():
|
|
583
598
|
cells, types = field.space.vtk_cells()
|
|
584
599
|
node_pos = field.space.node_positions().numpy()
|
|
@@ -667,7 +682,7 @@ class Plot:
|
|
|
667
682
|
density = field_args["streamlines"].get("density", 1.0)
|
|
668
683
|
cell_size = 1.0 / np.sqrt(field.space.geometry.cell_count())
|
|
669
684
|
lines = grid.streamlines(vectors=name, n_points=int(100 * density))
|
|
670
|
-
marker = lines.tube(radius=0.0025 * grid_scale / density)
|
|
685
|
+
marker = lines.tube(radius=0.0025 * grid_scale / np.sqrt(density))
|
|
671
686
|
elif "displacement" in field_args:
|
|
672
687
|
grid.points = field.space.node_positions().numpy() + v
|
|
673
688
|
|
|
@@ -700,11 +715,15 @@ class Plot:
|
|
|
700
715
|
plotter.add_mesh(grid, opacity=0.25, clim=value_range)
|
|
701
716
|
plotter.view_xy()
|
|
702
717
|
else:
|
|
703
|
-
plotter.add_mesh(marker
|
|
718
|
+
plotter.add_mesh(marker)
|
|
704
719
|
elif field.space.dimension == 3:
|
|
705
|
-
plotter.add_mesh_clip_plane(grid, show_edges=True, clim=value_range)
|
|
720
|
+
plotter.add_mesh_clip_plane(grid, show_edges=True, clim=value_range, assign_to_axis="z")
|
|
706
721
|
else:
|
|
707
722
|
plotter.add_mesh(grid, show_edges=True, clim=value_range)
|
|
723
|
+
|
|
724
|
+
if ref_geom:
|
|
725
|
+
plotter.add_mesh(ref_geom)
|
|
726
|
+
|
|
708
727
|
plotter.show(interactive_update=animate)
|
|
709
728
|
|
|
710
729
|
frame = 0
|
|
@@ -26,9 +26,33 @@ import warp.sim
|
|
|
26
26
|
import warp.sim.render
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def color_lattice_grid(num_x, num_y):
|
|
30
|
+
colors = []
|
|
31
|
+
for _i in range(4):
|
|
32
|
+
colors.append([])
|
|
33
|
+
|
|
34
|
+
for xi in range(num_x + 1):
|
|
35
|
+
for yi in range(num_y + 1):
|
|
36
|
+
vId = xi * (num_y + 1) + yi
|
|
37
|
+
|
|
38
|
+
a = 1 if xi % 2 else 0
|
|
39
|
+
b = 1 if yi % 2 else 0
|
|
40
|
+
|
|
41
|
+
c = a * 2 + b
|
|
42
|
+
|
|
43
|
+
colors[c].append(vId)
|
|
44
|
+
|
|
45
|
+
colors_wp = []
|
|
46
|
+
for i_color in range(len(colors)):
|
|
47
|
+
colors_wp.append(wp.array(colors[i_color], dtype=wp.int32))
|
|
48
|
+
|
|
49
|
+
return colors_wp
|
|
50
|
+
|
|
51
|
+
|
|
29
52
|
class IntegratorType(Enum):
|
|
30
53
|
EULER = "euler"
|
|
31
54
|
XPBD = "xpbd"
|
|
55
|
+
VBD = "vbd"
|
|
32
56
|
|
|
33
57
|
def __str__(self):
|
|
34
58
|
return self.value
|
|
@@ -67,7 +91,7 @@ class Example:
|
|
|
67
91
|
tri_ka=1.0e3,
|
|
68
92
|
tri_kd=1.0e1,
|
|
69
93
|
)
|
|
70
|
-
|
|
94
|
+
elif self.integrator_type == IntegratorType.XPBD:
|
|
71
95
|
builder.add_cloth_grid(
|
|
72
96
|
pos=wp.vec3(0.0, 4.0, 0.0),
|
|
73
97
|
rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), math.pi * 0.5),
|
|
@@ -83,6 +107,22 @@ class Example:
|
|
|
83
107
|
spring_ke=1.0e3,
|
|
84
108
|
spring_kd=0.0,
|
|
85
109
|
)
|
|
110
|
+
else:
|
|
111
|
+
# VBD
|
|
112
|
+
builder.add_cloth_grid(
|
|
113
|
+
pos=wp.vec3(0.0, 4.0, 0.0),
|
|
114
|
+
rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), math.pi * 0.5),
|
|
115
|
+
vel=wp.vec3(0.0, 0.0, 0.0),
|
|
116
|
+
dim_x=self.sim_width,
|
|
117
|
+
dim_y=self.sim_height,
|
|
118
|
+
cell_x=0.1,
|
|
119
|
+
cell_y=0.1,
|
|
120
|
+
mass=0.1,
|
|
121
|
+
fix_left=True,
|
|
122
|
+
tri_ke=1e4,
|
|
123
|
+
tri_ka=1e4,
|
|
124
|
+
tri_kd=1e-5,
|
|
125
|
+
)
|
|
86
126
|
|
|
87
127
|
usd_stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "bunny.usd"))
|
|
88
128
|
usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/root/bunny"))
|
|
@@ -103,16 +143,20 @@ class Example:
|
|
|
103
143
|
kf=1.0e1,
|
|
104
144
|
)
|
|
105
145
|
|
|
106
|
-
if self.integrator_type == IntegratorType.EULER:
|
|
107
|
-
self.integrator = wp.sim.SemiImplicitIntegrator()
|
|
108
|
-
else:
|
|
109
|
-
self.integrator = wp.sim.XPBDIntegrator(iterations=1)
|
|
110
|
-
|
|
111
146
|
self.model = builder.finalize()
|
|
112
147
|
self.model.ground = True
|
|
113
148
|
self.model.soft_contact_ke = 1.0e4
|
|
114
149
|
self.model.soft_contact_kd = 1.0e2
|
|
115
150
|
|
|
151
|
+
if self.integrator_type == IntegratorType.EULER:
|
|
152
|
+
self.integrator = wp.sim.SemiImplicitIntegrator()
|
|
153
|
+
elif self.integrator_type == IntegratorType.XPBD:
|
|
154
|
+
self.integrator = wp.sim.XPBDIntegrator(iterations=1)
|
|
155
|
+
else:
|
|
156
|
+
self.integrator = wp.sim.VBDIntegrator(self.model, iterations=1)
|
|
157
|
+
# we need to give VBD coloring information
|
|
158
|
+
self.model.particle_coloring = color_lattice_grid(width, height)
|
|
159
|
+
|
|
116
160
|
self.state_0 = self.model.state()
|
|
117
161
|
self.state_1 = self.model.state()
|
|
118
162
|
|
warp/fem/__init__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from .adaptivity import adaptive_nanogrid_from_field, adaptive_nanogrid_from_hierarchy
|
|
1
2
|
from .cache import TemporaryStore, borrow_temporary, borrow_temporary_like, set_default_temporary_store
|
|
2
3
|
from .dirichlet import normalize_dirichlet_projector, project_linear_system
|
|
3
4
|
from .domain import BoundarySides, Cells, FrontierSides, GeometryDomain, Sides, Subdomain
|
|
@@ -13,6 +14,7 @@ from .field import (
|
|
|
13
14
|
make_trial,
|
|
14
15
|
)
|
|
15
16
|
from .geometry import (
|
|
17
|
+
AdaptiveNanogrid,
|
|
16
18
|
ExplicitGeometryPartition,
|
|
17
19
|
Geometry,
|
|
18
20
|
GeometryPartition,
|