warp-lang 1.4.1__py3-none-macosx_10_13_universal2.whl → 1.5.0__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.
Potentially problematic release.
This version of warp-lang might be problematic. Click here for more details.
- warp/__init__.py +4 -0
- warp/autograd.py +43 -8
- warp/bin/libwarp-clang.dylib +0 -0
- warp/bin/libwarp.dylib +0 -0
- warp/build.py +21 -2
- warp/build_dll.py +23 -6
- warp/builtins.py +1920 -111
- warp/codegen.py +186 -62
- warp/config.py +2 -2
- warp/context.py +322 -73
- warp/examples/assets/pixel.jpg +0 -0
- warp/examples/benchmarks/benchmark_cloth_paddle.py +86 -0
- warp/examples/benchmarks/benchmark_gemm.py +121 -0
- warp/examples/benchmarks/benchmark_interop_paddle.py +158 -0
- warp/examples/benchmarks/benchmark_tile.py +179 -0
- warp/examples/core/example_dem.py +2 -1
- warp/examples/core/example_mesh_intersect.py +3 -3
- warp/examples/fem/example_adaptive_grid.py +37 -10
- warp/examples/fem/example_apic_fluid.py +3 -2
- warp/examples/fem/example_convection_diffusion_dg.py +4 -5
- warp/examples/fem/example_deformed_geometry.py +1 -1
- warp/examples/fem/example_diffusion_3d.py +47 -4
- warp/examples/fem/example_distortion_energy.py +220 -0
- warp/examples/fem/example_magnetostatics.py +127 -85
- warp/examples/fem/example_nonconforming_contact.py +5 -5
- warp/examples/fem/example_stokes.py +3 -1
- warp/examples/fem/example_streamlines.py +12 -19
- warp/examples/fem/utils.py +38 -15
- warp/examples/optim/example_walker.py +2 -2
- warp/examples/sim/example_cloth.py +2 -25
- warp/examples/sim/example_jacobian_ik.py +6 -2
- warp/examples/sim/example_quadruped.py +2 -1
- warp/examples/tile/example_tile_convolution.py +58 -0
- warp/examples/tile/example_tile_fft.py +47 -0
- warp/examples/tile/example_tile_filtering.py +105 -0
- warp/examples/tile/example_tile_matmul.py +79 -0
- warp/examples/tile/example_tile_mlp.py +375 -0
- warp/fem/__init__.py +8 -0
- warp/fem/cache.py +16 -12
- warp/fem/dirichlet.py +1 -1
- warp/fem/domain.py +44 -1
- warp/fem/field/__init__.py +1 -2
- warp/fem/field/field.py +31 -19
- warp/fem/field/nodal_field.py +101 -49
- warp/fem/field/virtual.py +794 -0
- warp/fem/geometry/__init__.py +2 -2
- warp/fem/geometry/deformed_geometry.py +3 -105
- warp/fem/geometry/element.py +13 -0
- warp/fem/geometry/geometry.py +165 -5
- warp/fem/geometry/grid_2d.py +3 -6
- warp/fem/geometry/grid_3d.py +31 -28
- warp/fem/geometry/hexmesh.py +3 -46
- warp/fem/geometry/nanogrid.py +3 -2
- warp/fem/geometry/{quadmesh_2d.py → quadmesh.py} +280 -159
- warp/fem/geometry/tetmesh.py +2 -43
- warp/fem/geometry/{trimesh_2d.py → trimesh.py} +354 -186
- warp/fem/integrate.py +683 -261
- warp/fem/linalg.py +404 -0
- warp/fem/operator.py +101 -18
- warp/fem/polynomial.py +5 -5
- warp/fem/quadrature/quadrature.py +45 -21
- warp/fem/space/__init__.py +45 -11
- warp/fem/space/basis_function_space.py +451 -0
- warp/fem/space/basis_space.py +58 -11
- warp/fem/space/function_space.py +146 -5
- warp/fem/space/grid_2d_function_space.py +80 -66
- warp/fem/space/grid_3d_function_space.py +113 -68
- warp/fem/space/hexmesh_function_space.py +96 -108
- warp/fem/space/nanogrid_function_space.py +62 -110
- warp/fem/space/quadmesh_function_space.py +208 -0
- warp/fem/space/shape/__init__.py +45 -7
- warp/fem/space/shape/cube_shape_function.py +328 -54
- warp/fem/space/shape/shape_function.py +10 -1
- warp/fem/space/shape/square_shape_function.py +328 -60
- warp/fem/space/shape/tet_shape_function.py +269 -19
- warp/fem/space/shape/triangle_shape_function.py +238 -19
- warp/fem/space/tetmesh_function_space.py +69 -37
- warp/fem/space/topology.py +38 -0
- warp/fem/space/trimesh_function_space.py +179 -0
- warp/fem/utils.py +6 -331
- warp/jax_experimental.py +3 -1
- warp/native/array.h +55 -40
- warp/native/builtin.h +124 -43
- warp/native/bvh.h +4 -0
- warp/native/coloring.cpp +600 -0
- warp/native/cuda_util.cpp +14 -0
- warp/native/cuda_util.h +2 -1
- warp/native/fabric.h +8 -0
- warp/native/hashgrid.h +4 -0
- warp/native/marching.cu +8 -0
- warp/native/mat.h +14 -3
- warp/native/mathdx.cpp +59 -0
- warp/native/mesh.h +4 -0
- warp/native/range.h +13 -1
- warp/native/reduce.cpp +9 -1
- warp/native/reduce.cu +7 -0
- warp/native/runlength_encode.cpp +9 -1
- warp/native/runlength_encode.cu +7 -1
- warp/native/scan.cpp +8 -0
- warp/native/scan.cu +8 -0
- warp/native/scan.h +8 -1
- warp/native/sparse.cpp +8 -0
- warp/native/sparse.cu +8 -0
- warp/native/temp_buffer.h +7 -0
- warp/native/tile.h +1857 -0
- warp/native/tile_gemm.h +341 -0
- warp/native/tile_reduce.h +210 -0
- warp/native/volume_builder.cu +8 -0
- warp/native/volume_builder.h +8 -0
- warp/native/warp.cpp +10 -2
- warp/native/warp.cu +369 -15
- warp/native/warp.h +12 -2
- warp/optim/adam.py +39 -4
- warp/paddle.py +29 -12
- warp/render/render_opengl.py +137 -65
- warp/sim/graph_coloring.py +292 -0
- warp/sim/integrator_euler.py +4 -2
- warp/sim/integrator_featherstone.py +115 -44
- warp/sim/integrator_vbd.py +6 -0
- warp/sim/model.py +90 -17
- warp/stubs.py +651 -85
- warp/tape.py +12 -7
- warp/tests/assets/pixel.npy +0 -0
- warp/tests/aux_test_instancing_gc.py +18 -0
- warp/tests/test_array.py +207 -48
- warp/tests/test_closest_point_edge_edge.py +8 -8
- warp/tests/test_codegen.py +120 -1
- warp/tests/test_codegen_instancing.py +30 -0
- warp/tests/test_collision.py +110 -0
- warp/tests/test_coloring.py +241 -0
- warp/tests/test_context.py +34 -0
- warp/tests/test_examples.py +18 -4
- warp/tests/test_fabricarray.py +33 -0
- warp/tests/test_fem.py +453 -113
- warp/tests/test_func.py +48 -1
- warp/tests/test_generics.py +52 -0
- warp/tests/test_iter.py +68 -0
- warp/tests/test_mat_scalar_ops.py +1 -1
- warp/tests/test_mesh_query_point.py +5 -4
- warp/tests/test_module_hashing.py +23 -0
- warp/tests/test_paddle.py +27 -87
- warp/tests/test_print.py +191 -1
- warp/tests/test_spatial.py +1 -1
- warp/tests/test_tile.py +700 -0
- warp/tests/test_tile_mathdx.py +144 -0
- warp/tests/test_tile_mlp.py +383 -0
- warp/tests/test_tile_reduce.py +374 -0
- warp/tests/test_tile_shared_memory.py +190 -0
- warp/tests/test_vbd.py +12 -20
- warp/tests/test_volume.py +43 -0
- warp/tests/unittest_suites.py +23 -2
- warp/tests/unittest_utils.py +4 -0
- warp/types.py +339 -73
- warp/utils.py +22 -1
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/METADATA +33 -7
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/RECORD +159 -132
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/WHEEL +1 -1
- warp/fem/field/test.py +0 -180
- warp/fem/field/trial.py +0 -183
- warp/fem/space/collocated_function_space.py +0 -102
- warp/fem/space/quadmesh_2d_function_space.py +0 -261
- warp/fem/space/trimesh_2d_function_space.py +0 -153
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -8,17 +8,18 @@
|
|
|
8
8
|
###########################################################################
|
|
9
9
|
# Example Magnetostatics
|
|
10
10
|
#
|
|
11
|
-
# This example demonstrates solving
|
|
12
|
-
#
|
|
11
|
+
# This example demonstrates solving a 3d magnetostatics problem
|
|
12
|
+
# (a copper coil with radial current around a cylindrical iron core)
|
|
13
|
+
# using a curl-curl formulation and H(curl)-conforming function space
|
|
13
14
|
#
|
|
14
15
|
# 1/mu Curl B + j = 0
|
|
15
16
|
# Div. B = 0
|
|
16
17
|
#
|
|
17
|
-
# solved over field A such that B = Curl A,
|
|
18
|
-
# and
|
|
18
|
+
# solved over field A such that B = Curl A,
|
|
19
|
+
# and Direchlet homogeneous essential boundary conditions
|
|
19
20
|
#
|
|
20
|
-
# This example also illustrates using an ImplictField to warp a
|
|
21
|
-
# to a
|
|
21
|
+
# This example also illustrates using an ImplictField to warp a grid mesh
|
|
22
|
+
# to a cylindrical domain
|
|
22
23
|
###########################################################################
|
|
23
24
|
|
|
24
25
|
import numpy as np
|
|
@@ -27,138 +28,179 @@ import warp as wp
|
|
|
27
28
|
import warp.examples.fem.utils as fem_example_utils
|
|
28
29
|
import warp.fem as fem
|
|
29
30
|
|
|
30
|
-
#
|
|
31
|
-
MU_0 = wp.constant(np.pi * 4.0e-7)
|
|
32
|
-
|
|
31
|
+
# Physics constants
|
|
32
|
+
MU_0 = wp.constant(np.pi * 4.0e-7) # Vacuum magnetic permeability
|
|
33
|
+
MU_c = wp.constant(1.25e-6) # Copper magnetic permeability
|
|
34
|
+
MU_i = wp.constant(6.0e-3) # Iron magnetic permeability
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
@wp.func
|
|
36
|
-
def
|
|
38
|
+
def cube_to_cylinder(x: wp.vec3):
|
|
37
39
|
# mapping from unit square to unit disk
|
|
38
|
-
|
|
40
|
+
pos_xz = wp.vec3(x[0], 0.0, x[2])
|
|
41
|
+
return wp.max(wp.abs(pos_xz)) * wp.normalize(pos_xz) + wp.vec3(0.0, x[1], 0.0)
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
@wp.func
|
|
42
|
-
def
|
|
45
|
+
def cube_to_cylinder_grad(x: wp.vec3):
|
|
43
46
|
# gradient of mapping from unit square to unit disk
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
pos_xz = wp.vec3(x[0], 0.0, x[2])
|
|
48
|
+
if pos_xz == wp.vec3(0.0):
|
|
49
|
+
grad = wp.mat33(0.0)
|
|
50
|
+
else:
|
|
51
|
+
dir_xz = wp.normalize(pos_xz)
|
|
52
|
+
dir_grad = (wp.identity(n=3, dtype=float) - wp.outer(dir_xz, dir_xz)) / wp.length(pos_xz)
|
|
53
|
+
|
|
54
|
+
abs_xz = wp.abs(pos_xz)
|
|
55
|
+
xinf_grad = wp.select(
|
|
56
|
+
abs_xz[0] > abs_xz[2], wp.vec3(0.0, 0.0, wp.sign(pos_xz[2])), wp.vec(wp.sign(pos_xz[0]), 0.0, 0.0)
|
|
57
|
+
)
|
|
58
|
+
grad = dir_grad * wp.max(abs_xz) + wp.outer(dir_xz, xinf_grad)
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
grad[1, 1] = 1.0
|
|
61
|
+
return grad
|
|
49
62
|
|
|
50
|
-
ax = wp.abs(x)
|
|
51
|
-
xinf = wp.max(ax)
|
|
52
63
|
|
|
53
|
-
|
|
64
|
+
@wp.func
|
|
65
|
+
def permeability_field(
|
|
66
|
+
pos: wp.vec3,
|
|
67
|
+
core_radius: float,
|
|
68
|
+
core_height: float,
|
|
69
|
+
coil_internal_radius: float,
|
|
70
|
+
coil_external_radius: float,
|
|
71
|
+
coil_height: float,
|
|
72
|
+
):
|
|
73
|
+
x = wp.abs(pos[0])
|
|
74
|
+
y = wp.abs(pos[1])
|
|
75
|
+
z = wp.abs(pos[2])
|
|
54
76
|
|
|
55
|
-
|
|
77
|
+
r = wp.sqrt(x * x + z * z)
|
|
56
78
|
|
|
79
|
+
if r <= core_radius:
|
|
80
|
+
return wp.select(y < core_height, MU_0, MU_i)
|
|
57
81
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# space-varying permeability
|
|
82
|
+
if r >= coil_internal_radius and r <= coil_external_radius:
|
|
83
|
+
return wp.select(y < coil_height, MU_0, MU_c)
|
|
61
84
|
|
|
62
|
-
|
|
63
|
-
y = wp.abs(pos[1])
|
|
64
|
-
return wp.select(
|
|
65
|
-
y < coil_height and x > coil_internal_radius and x < coil_external_radius,
|
|
66
|
-
MU_0,
|
|
67
|
-
MU_C,
|
|
68
|
-
)
|
|
85
|
+
return MU_0
|
|
69
86
|
|
|
70
87
|
|
|
71
88
|
@wp.func
|
|
72
89
|
def current_field(
|
|
73
|
-
pos: wp.
|
|
90
|
+
pos: wp.vec3,
|
|
91
|
+
current: float,
|
|
92
|
+
coil_internal_radius: float,
|
|
93
|
+
coil_external_radius: float,
|
|
94
|
+
coil_height: float,
|
|
74
95
|
):
|
|
75
|
-
|
|
76
|
-
x = wp.abs(pos[0])
|
|
96
|
+
x = pos[0]
|
|
77
97
|
y = wp.abs(pos[1])
|
|
78
|
-
|
|
79
|
-
wp.select(
|
|
80
|
-
y < coil_height and x > coil_internal_radius and x < coil_external_radius,
|
|
81
|
-
0.0,
|
|
82
|
-
wp.sign(pos[0]),
|
|
83
|
-
)
|
|
84
|
-
* current
|
|
85
|
-
)
|
|
98
|
+
z = pos[2]
|
|
86
99
|
|
|
100
|
+
r = wp.sqrt(x * x + z * z)
|
|
87
101
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
102
|
+
return wp.select(
|
|
103
|
+
y < coil_height and r >= coil_internal_radius and r <= coil_external_radius,
|
|
104
|
+
wp.vec3(0.0),
|
|
105
|
+
wp.vec3(z, 0.0, -x) * current / r,
|
|
106
|
+
)
|
|
93
107
|
|
|
94
108
|
|
|
95
109
|
@fem.integrand
|
|
96
110
|
def curl_curl_form(s: fem.Sample, domain: fem.Domain, u: fem.Field, v: fem.Field, mu: fem.Field):
|
|
97
|
-
return wp.dot(
|
|
111
|
+
return wp.dot(fem.curl(u, s), fem.curl(v, s)) / mu(s)
|
|
98
112
|
|
|
99
113
|
|
|
100
114
|
@fem.integrand
|
|
101
115
|
def mass_form(s: fem.Sample, domain: fem.Domain, v: fem.Field, u: fem.Field):
|
|
102
|
-
return u(s)
|
|
116
|
+
return wp.dot(u(s), v(s))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@fem.integrand
|
|
120
|
+
def curl_expr(s: fem.Sample, u: fem.Field):
|
|
121
|
+
return fem.curl(u, s)
|
|
103
122
|
|
|
104
123
|
|
|
105
124
|
class Example:
|
|
106
|
-
def __init__(self, quiet=False,
|
|
125
|
+
def __init__(self, quiet=False, mesh: str = "grid", resolution=32, domain_radius=2.0, current=1.0e6):
|
|
107
126
|
# We mesh the unit disk by first meshing the unit square, then building a deformed geometry
|
|
108
127
|
# from an implicit mapping field
|
|
109
|
-
square_geo = fem.Grid2D(
|
|
110
|
-
bounds_lo=wp.vec2(-domain_radius, -domain_radius),
|
|
111
|
-
bounds_hi=wp.vec2(domain_radius, domain_radius),
|
|
112
|
-
res=wp.vec2i(resolution, resolution),
|
|
113
|
-
)
|
|
114
128
|
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
if mesh == "hex":
|
|
130
|
+
positions, hex_vidx = fem_example_utils.gen_hexmesh(
|
|
131
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
132
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
133
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
134
|
+
)
|
|
135
|
+
cube_geo = fem.Hexmesh(hex_vertex_indices=hex_vidx, positions=positions)
|
|
136
|
+
elif mesh == "tet":
|
|
137
|
+
positions, tet_vidx = fem_example_utils.gen_tetmesh(
|
|
138
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
139
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
140
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
141
|
+
)
|
|
142
|
+
cube_geo = fem.Tetmesh(tet_vertex_indices=tet_vidx, positions=positions)
|
|
143
|
+
elif mesh == "nano":
|
|
144
|
+
vol = fem_example_utils.gen_volume(
|
|
145
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
146
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
147
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
148
|
+
)
|
|
149
|
+
cube_geo = fem.Nanogrid(grid=vol)
|
|
150
|
+
else:
|
|
151
|
+
cube_geo = fem.Grid3D(
|
|
152
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
153
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
154
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def_field = fem.ImplicitField(
|
|
158
|
+
domain=fem.Cells(cube_geo), func=cube_to_cylinder, grad_func=cube_to_cylinder_grad
|
|
159
|
+
)
|
|
160
|
+
sim_geo = def_field.make_deformed_geometry(relative=False)
|
|
117
161
|
|
|
118
|
-
coil_config = {"coil_height":
|
|
162
|
+
coil_config = {"coil_height": 0.25, "coil_internal_radius": 0.3, "coil_external_radius": 0.4}
|
|
163
|
+
core_config = {"core_height": 1.0, "core_radius": 0.2}
|
|
119
164
|
|
|
120
|
-
domain = fem.Cells(
|
|
121
|
-
self._permeability_field = fem.ImplicitField(
|
|
165
|
+
domain = fem.Cells(sim_geo)
|
|
166
|
+
self._permeability_field = fem.ImplicitField(
|
|
167
|
+
domain, func=permeability_field, values=dict(**coil_config, **core_config)
|
|
168
|
+
)
|
|
122
169
|
self._current_field = fem.ImplicitField(domain, func=current_field, values=dict(current=current, **coil_config))
|
|
123
170
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
disk_geo, degree=degree, element_basis=fem.ElementBasis.LAGRANGE, dtype=wp.vec2
|
|
171
|
+
A_space = fem.make_polynomial_space(
|
|
172
|
+
sim_geo, degree=1, element_basis=fem.ElementBasis.NEDELEC_FIRST_KIND, dtype=wp.vec3
|
|
127
173
|
)
|
|
174
|
+
self.A_field = A_space.make_field()
|
|
128
175
|
|
|
129
|
-
|
|
130
|
-
self.B_field =
|
|
176
|
+
B_space = fem.make_polynomial_space(sim_geo, degree=1, element_basis=fem.ElementBasis.LAGRANGE, dtype=wp.vec3)
|
|
177
|
+
self.B_field = B_space.make_field()
|
|
131
178
|
|
|
132
179
|
self.renderer = fem_example_utils.Plot()
|
|
133
180
|
|
|
134
181
|
def step(self):
|
|
135
|
-
|
|
136
|
-
|
|
182
|
+
A_space = self.A_field.space
|
|
183
|
+
sim_geo = A_space.geometry
|
|
137
184
|
|
|
138
|
-
u = fem.make_trial(space=
|
|
139
|
-
v = fem.make_test(space=
|
|
140
|
-
lhs = fem.integrate(curl_curl_form, fields={"u": u, "v": v, "mu": self._permeability_field})
|
|
141
|
-
rhs = fem.integrate(mass_form, fields={"v": v, "u": self._current_field})
|
|
185
|
+
u = fem.make_trial(space=A_space)
|
|
186
|
+
v = fem.make_test(space=A_space)
|
|
187
|
+
lhs = fem.integrate(curl_curl_form, fields={"u": u, "v": v, "mu": self._permeability_field}, output_dtype=float)
|
|
188
|
+
rhs = fem.integrate(mass_form, fields={"v": v, "u": self._current_field}, output_dtype=float)
|
|
142
189
|
|
|
143
190
|
# Dirichlet BC
|
|
144
|
-
boundary = fem.BoundarySides(
|
|
145
|
-
u_bd = fem.make_trial(space=
|
|
146
|
-
v_bd = fem.make_test(space=
|
|
147
|
-
dirichlet_bd_proj = fem.integrate(mass_form, fields={"u": u_bd, "v": v_bd}, nodal=True)
|
|
191
|
+
boundary = fem.BoundarySides(sim_geo)
|
|
192
|
+
u_bd = fem.make_trial(space=A_space, domain=boundary)
|
|
193
|
+
v_bd = fem.make_test(space=A_space, domain=boundary)
|
|
194
|
+
dirichlet_bd_proj = fem.integrate(mass_form, fields={"u": u_bd, "v": v_bd}, nodal=True, output_dtype=float)
|
|
148
195
|
fem.project_linear_system(lhs, rhs, dirichlet_bd_proj)
|
|
149
196
|
|
|
150
|
-
|
|
151
|
-
fem_example_utils.bsr_cg(lhs, b=rhs, x=
|
|
152
|
-
|
|
153
|
-
# make sure result is exactly zero outside of circle
|
|
154
|
-
wp.sparse.bsr_mv(dirichlet_bd_proj, x=x, y=x, alpha=-1.0, beta=1.0)
|
|
155
|
-
wp.utils.array_cast(in_array=x, out_array=self.A_field.dof_values)
|
|
197
|
+
# solve using Conjugate Residual (numerically rhs may not be in image of lhs)
|
|
198
|
+
fem_example_utils.bsr_cg(lhs, b=rhs, x=self.A_field.dof_values, method="cr", max_iters=250, quiet=False)
|
|
156
199
|
|
|
157
200
|
# compute B as curl(A)
|
|
158
|
-
fem.interpolate(
|
|
201
|
+
fem.interpolate(curl_expr, dest=self.B_field, fields={"u": self.A_field})
|
|
159
202
|
|
|
160
203
|
def render(self):
|
|
161
|
-
self.renderer.add_field("A", self.A_field)
|
|
162
204
|
self.renderer.add_field("B", self.B_field)
|
|
163
205
|
|
|
164
206
|
|
|
@@ -170,7 +212,7 @@ if __name__ == "__main__":
|
|
|
170
212
|
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
171
213
|
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
172
214
|
parser.add_argument("--resolution", type=int, default=32, help="Grid resolution.")
|
|
173
|
-
parser.add_argument("--
|
|
215
|
+
parser.add_argument("--mesh", type=str, default="grid", choices=["tet", "hex", "grid", "nano"], help="Mesh type.")
|
|
174
216
|
parser.add_argument("--radius", type=float, default=2.0, help="Radius of simulation domain.")
|
|
175
217
|
parser.add_argument(
|
|
176
218
|
"--headless",
|
|
@@ -182,9 +224,9 @@ if __name__ == "__main__":
|
|
|
182
224
|
args = parser.parse_known_args()[0]
|
|
183
225
|
|
|
184
226
|
with wp.ScopedDevice(args.device):
|
|
185
|
-
example = Example(quiet=args.quiet,
|
|
227
|
+
example = Example(quiet=args.quiet, mesh=args.mesh, resolution=args.resolution, domain_radius=args.radius)
|
|
186
228
|
example.step()
|
|
187
229
|
example.render()
|
|
188
230
|
|
|
189
231
|
if not args.headless:
|
|
190
|
-
example.renderer.plot({"
|
|
232
|
+
example.renderer.plot({"B": {"streamlines": {"density": 1.0}}})
|
|
@@ -210,11 +210,11 @@ class Example:
|
|
|
210
210
|
|
|
211
211
|
# Add boundary stress from other solid field
|
|
212
212
|
other_stress_field = fem.field.field.NonconformingField(boundary, other_stress_field)
|
|
213
|
-
fem.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
fem.integrate(
|
|
214
|
+
boundary_stress_form,
|
|
215
|
+
fields={"u": u_bd_test, "tau": other_stress_field},
|
|
216
|
+
output=u_rhs,
|
|
217
|
+
add=True,
|
|
218
218
|
)
|
|
219
219
|
|
|
220
220
|
# Enforce boundary conditions
|
|
@@ -200,4 +200,6 @@ if __name__ == "__main__":
|
|
|
200
200
|
example.render()
|
|
201
201
|
|
|
202
202
|
if not args.headless:
|
|
203
|
-
example.renderer.plot(
|
|
203
|
+
example.renderer.plot(
|
|
204
|
+
options={"velocity": {"streamlines": {}}, "pressure": {"contours": {}}}, backend="matplotlib"
|
|
205
|
+
)
|
|
@@ -82,7 +82,7 @@ def mass_form(
|
|
|
82
82
|
u: fem.Field,
|
|
83
83
|
v: fem.Field,
|
|
84
84
|
):
|
|
85
|
-
return u(s)
|
|
85
|
+
return wp.dot(u(s), v(s))
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
@fem.integrand
|
|
@@ -199,7 +199,7 @@ class Example:
|
|
|
199
199
|
domain=self._inflow, order=self._degree, family=fem.Polynomial.GAUSS_LEGENDRE
|
|
200
200
|
)
|
|
201
201
|
n_streamlines = streamline_spawn.total_point_count()
|
|
202
|
-
spawn_points = wp.
|
|
202
|
+
spawn_points = wp.empty(dtype=wp.vec3, shape=n_streamlines)
|
|
203
203
|
|
|
204
204
|
jitter_amount = self._streamline_dx / self._degree
|
|
205
205
|
fem.interpolate(
|
|
@@ -212,8 +212,8 @@ class Example:
|
|
|
212
212
|
# to populate the per-point data
|
|
213
213
|
|
|
214
214
|
point_count = self._streamline_point_count
|
|
215
|
-
points = wp.
|
|
216
|
-
speed = wp.
|
|
215
|
+
points = wp.empty(dtype=wp.vec3, shape=(n_streamlines, point_count))
|
|
216
|
+
speed = wp.empty(dtype=float, shape=(n_streamlines, point_count))
|
|
217
217
|
|
|
218
218
|
fem.interpolate(
|
|
219
219
|
gen_streamlines,
|
|
@@ -235,7 +235,7 @@ class Example:
|
|
|
235
235
|
def render(self):
|
|
236
236
|
# self.renderer.add_field("solution", self.pressure_field)
|
|
237
237
|
self.plot.add_field("pressure", self.pressure_field)
|
|
238
|
-
self.plot.add_field("velocity", self.velocity_field)
|
|
238
|
+
# self.plot.add_field("velocity", self.velocity_field)
|
|
239
239
|
|
|
240
240
|
if self.renderer is not None:
|
|
241
241
|
streamline_count = self._points.shape[0]
|
|
@@ -259,10 +259,11 @@ class Example:
|
|
|
259
259
|
self.renderer.end_frame()
|
|
260
260
|
|
|
261
261
|
def _generate_incompressible_flow(self):
|
|
262
|
-
# Function spaces for velocity
|
|
263
|
-
u_space = fem.make_polynomial_space(
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
# Function spaces for velocity and pressure (RT1 / P0)
|
|
263
|
+
u_space = fem.make_polynomial_space(
|
|
264
|
+
geo=self._geo, element_basis=fem.ElementBasis.RAVIART_THOMAS, degree=1, dtype=wp.vec3
|
|
265
|
+
)
|
|
266
|
+
p_space = fem.make_polynomial_space(geo=self._geo, degree=0, dtype=float)
|
|
266
267
|
|
|
267
268
|
self.pressure_field = p_space.make_field()
|
|
268
269
|
self.velocity_field = u_space.make_field()
|
|
@@ -288,8 +289,8 @@ class Example:
|
|
|
288
289
|
fem.interpolate(inflow_velocity, dest=fem.make_restriction(self.velocity_field, domain=self._inflow))
|
|
289
290
|
|
|
290
291
|
# (Diagonal) mass matrix
|
|
291
|
-
rho_test = fem.make_test(
|
|
292
|
-
rho_trial = fem.make_trial(
|
|
292
|
+
rho_test = fem.make_test(u_space)
|
|
293
|
+
rho_trial = fem.make_trial(u_space)
|
|
293
294
|
inv_mass_matrix = fem.integrate(
|
|
294
295
|
mass_form, fields={"u": rho_trial, "v": rho_test}, nodal=True, output_dtype=float
|
|
295
296
|
)
|
|
@@ -341,11 +342,3 @@ if __name__ == "__main__":
|
|
|
341
342
|
|
|
342
343
|
example.step()
|
|
343
344
|
example.render()
|
|
344
|
-
|
|
345
|
-
if not args.headless:
|
|
346
|
-
example.plot.plot(
|
|
347
|
-
{
|
|
348
|
-
"velocity": {"streamlines": {"density": 2}},
|
|
349
|
-
"pressure": {"contours": {}},
|
|
350
|
-
}
|
|
351
|
-
)
|
warp/examples/fem/utils.py
CHANGED
|
@@ -31,7 +31,7 @@ def gen_trimesh(res, bounds_lo: Optional[wp.vec2] = None, bounds_hi: Optional[wp
|
|
|
31
31
|
Args:
|
|
32
32
|
res: Resolution of the grid along each dimension
|
|
33
33
|
bounds_lo: Position of the lower bound of the axis-aligned grid
|
|
34
|
-
|
|
34
|
+
bounds_hi: Position of the upper bound of the axis-aligned grid
|
|
35
35
|
|
|
36
36
|
Returns:
|
|
37
37
|
Tuple of ndarrays: (Vertex positions, Triangle vertex indices)
|
|
@@ -62,7 +62,7 @@ def gen_tetmesh(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp
|
|
|
62
62
|
Args:
|
|
63
63
|
res: Resolution of the grid along each dimension
|
|
64
64
|
bounds_lo: Position of the lower bound of the axis-aligned grid
|
|
65
|
-
|
|
65
|
+
bounds_hi: Position of the upper bound of the axis-aligned grid
|
|
66
66
|
|
|
67
67
|
Returns:
|
|
68
68
|
Tuple of ndarrays: (Vertex positions, Tetrahedron vertex indices)
|
|
@@ -95,7 +95,7 @@ def gen_quadmesh(res, bounds_lo: Optional[wp.vec2] = None, bounds_hi: Optional[w
|
|
|
95
95
|
Args:
|
|
96
96
|
res: Resolution of the grid along each dimension
|
|
97
97
|
bounds_lo: Position of the lower bound of the axis-aligned grid
|
|
98
|
-
|
|
98
|
+
bounds_hi: Position of the upper bound of the axis-aligned grid
|
|
99
99
|
|
|
100
100
|
Returns:
|
|
101
101
|
Tuple of ndarrays: (Vertex positions, Triangle vertex indices)
|
|
@@ -125,7 +125,7 @@ def gen_hexmesh(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp
|
|
|
125
125
|
Args:
|
|
126
126
|
res: Resolution of the grid along each dimension
|
|
127
127
|
bounds_lo: Position of the lower bound of the axis-aligned grid
|
|
128
|
-
|
|
128
|
+
bounds_hi: Position of the upper bound of the axis-aligned grid
|
|
129
129
|
|
|
130
130
|
Returns:
|
|
131
131
|
Tuple of ndarrays: (Vertex positions, Triangle vertex indices)
|
|
@@ -158,7 +158,7 @@ def gen_volume(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp.
|
|
|
158
158
|
Args:
|
|
159
159
|
res: Resolution of the grid along each dimension
|
|
160
160
|
bounds_lo: Position of the lower bound of the axis-aligned grid
|
|
161
|
-
|
|
161
|
+
bounds_hi: Position of the upper bound of the axis-aligned grid
|
|
162
162
|
device: Cuda device on which to allocate the grid
|
|
163
163
|
"""
|
|
164
164
|
|
|
@@ -575,6 +575,7 @@ class Plot:
|
|
|
575
575
|
|
|
576
576
|
def _plot_pyvista(self, options: Dict[str, Any]):
|
|
577
577
|
import pyvista
|
|
578
|
+
import pyvista.themes
|
|
578
579
|
|
|
579
580
|
grids = {}
|
|
580
581
|
scales = {}
|
|
@@ -702,7 +703,7 @@ class Plot:
|
|
|
702
703
|
subplot_rows = options.get("rows", 1)
|
|
703
704
|
subplot_shape = (subplot_rows, (len(grids) + subplot_rows - 1) // subplot_rows)
|
|
704
705
|
|
|
705
|
-
plotter = pyvista.Plotter(shape=subplot_shape)
|
|
706
|
+
plotter = pyvista.Plotter(shape=subplot_shape, theme=pyvista.themes.DocumentProTheme())
|
|
706
707
|
plotter.link_views()
|
|
707
708
|
plotter.add_camera_orientation_widget()
|
|
708
709
|
for index, (name, grid) in enumerate(grids.items()):
|
|
@@ -717,7 +718,7 @@ class Plot:
|
|
|
717
718
|
plotter.view_xy()
|
|
718
719
|
else:
|
|
719
720
|
plotter.add_mesh(marker)
|
|
720
|
-
elif field.space.
|
|
721
|
+
elif field.space.geometry.cell_dimension == 3:
|
|
721
722
|
plotter.add_mesh_clip_plane(grid, show_edges=True, clim=value_range, assign_to_axis="z")
|
|
722
723
|
else:
|
|
723
724
|
plotter.add_mesh(grid, show_edges=True, clim=value_range)
|
|
@@ -809,6 +810,8 @@ class Plot:
|
|
|
809
810
|
if "arrows" in args or "streamlines" in args:
|
|
810
811
|
plot_opts["glyph_scale"] = args.get("arrows", {}).get("glyph_scale", 1.0)
|
|
811
812
|
plot_fn = _plot_quivers_3d
|
|
813
|
+
elif field.space.geometry.cell_dimension == 2:
|
|
814
|
+
plot_fn = _plot_surface
|
|
812
815
|
else:
|
|
813
816
|
plot_fn = _plot_3d_scatter
|
|
814
817
|
plot_3d = True
|
|
@@ -856,23 +859,43 @@ def _field_triangulation(field):
|
|
|
856
859
|
|
|
857
860
|
|
|
858
861
|
def _plot_surface(field, axes, **kwargs):
|
|
859
|
-
|
|
862
|
+
from matplotlib.cm import get_cmap
|
|
863
|
+
from matplotlib.colors import Normalize
|
|
860
864
|
|
|
861
|
-
|
|
862
|
-
|
|
865
|
+
C = _value_or_magnitude(field.dof_values.numpy())
|
|
866
|
+
|
|
867
|
+
positions = field.space.node_positions().numpy().T
|
|
868
|
+
if field.space.dimension == 3:
|
|
869
|
+
X, Y, Z = positions
|
|
870
|
+
else:
|
|
871
|
+
X, Y = positions
|
|
872
|
+
Z = C
|
|
873
|
+
axes.set_zlim(kwargs["clim"])
|
|
863
874
|
|
|
864
875
|
if hasattr(field.space, "node_grid"):
|
|
865
876
|
X, Y = field.space.node_grid()
|
|
866
|
-
|
|
867
|
-
return axes.plot_surface(X, Y,
|
|
877
|
+
C = C.reshape(X.shape)
|
|
878
|
+
return axes.plot_surface(X, Y, C, linewidth=0.1, antialiased=False, **kwargs)
|
|
868
879
|
|
|
869
880
|
if hasattr(field.space, "node_triangulation"):
|
|
870
881
|
triangulation = _field_triangulation(field)
|
|
871
|
-
|
|
882
|
+
|
|
883
|
+
if field.space.dimension == 3:
|
|
884
|
+
plot = axes.plot_trisurf(triangulation, Z, linewidth=0.1, antialiased=False)
|
|
885
|
+
# change colors -- recompute color map manually
|
|
886
|
+
vmin, vmax = kwargs["clim"]
|
|
887
|
+
norm = Normalize(vmin=vmin, vmax=vmax)
|
|
888
|
+
values = np.mean(C[triangulation.triangles], axis=1)
|
|
889
|
+
colors = get_cmap(kwargs["cmap"])(norm(values))
|
|
890
|
+
plot.set_norm(norm)
|
|
891
|
+
plot.set_fc(colors)
|
|
892
|
+
else:
|
|
893
|
+
plot = axes.plot_trisurf(triangulation, C, linewidth=0.1, antialiased=False, **kwargs)
|
|
894
|
+
|
|
895
|
+
return plot
|
|
872
896
|
|
|
873
897
|
# scatter
|
|
874
|
-
X, Y =
|
|
875
|
-
return axes.scatter(X, Y, Z, c=Z, **kwargs)
|
|
898
|
+
return axes.scatter(X, Y, Z, c=C, **kwargs)
|
|
876
899
|
|
|
877
900
|
|
|
878
901
|
def _plot_displaced_tri_mesh(field, axes, **kwargs):
|
|
@@ -21,7 +21,7 @@ import math
|
|
|
21
21
|
import os
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
|
-
from pxr import Usd, UsdGeom
|
|
24
|
+
from pxr import Gf, Usd, UsdGeom
|
|
25
25
|
|
|
26
26
|
import warp as wp
|
|
27
27
|
import warp.examples
|
|
@@ -93,7 +93,7 @@ class Example:
|
|
|
93
93
|
geom = UsdGeom.Mesh(asset_stage.GetPrimAtPath("/root/bear"))
|
|
94
94
|
points = geom.GetPointsAttr().Get()
|
|
95
95
|
|
|
96
|
-
xform = geom.ComputeLocalToWorldTransform(0.0)
|
|
96
|
+
xform = Gf.Matrix4f(geom.ComputeLocalToWorldTransform(0.0))
|
|
97
97
|
for i in range(len(points)):
|
|
98
98
|
points[i] = xform.Transform(points[i])
|
|
99
99
|
|
|
@@ -26,29 +26,6 @@ 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
|
-
|
|
52
29
|
class IntegratorType(Enum):
|
|
53
30
|
EULER = "euler"
|
|
54
31
|
XPBD = "xpbd"
|
|
@@ -122,6 +99,8 @@ class Example:
|
|
|
122
99
|
tri_ke=1e4,
|
|
123
100
|
tri_ka=1e4,
|
|
124
101
|
tri_kd=1e-5,
|
|
102
|
+
edge_ke=100,
|
|
103
|
+
color_particles=True,
|
|
125
104
|
)
|
|
126
105
|
|
|
127
106
|
usd_stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "bunny.usd"))
|
|
@@ -154,8 +133,6 @@ class Example:
|
|
|
154
133
|
self.integrator = wp.sim.XPBDIntegrator(iterations=1)
|
|
155
134
|
else:
|
|
156
135
|
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
136
|
|
|
160
137
|
self.state_0 = self.model.state()
|
|
161
138
|
self.state_1 = self.model.state()
|
|
@@ -41,6 +41,8 @@ def compute_endeffector_position(
|
|
|
41
41
|
|
|
42
42
|
class Example:
|
|
43
43
|
def __init__(self, stage_path="example_jacobian_ik.usd", num_envs=10):
|
|
44
|
+
rng = np.random.default_rng(42)
|
|
45
|
+
|
|
44
46
|
builder = wp.sim.ModelBuilder()
|
|
45
47
|
|
|
46
48
|
self.num_envs = num_envs
|
|
@@ -81,7 +83,7 @@ class Example:
|
|
|
81
83
|
)
|
|
82
84
|
self.target_origin.append((i * 2.0, 4.0, 0.0))
|
|
83
85
|
# joint initial positions
|
|
84
|
-
builder.joint_q[-3:] =
|
|
86
|
+
builder.joint_q[-3:] = rng.uniform(-0.5, 0.5, size=3)
|
|
85
87
|
self.target_origin = np.array(self.target_origin)
|
|
86
88
|
|
|
87
89
|
# finalize model
|
|
@@ -207,6 +209,8 @@ if __name__ == "__main__":
|
|
|
207
209
|
|
|
208
210
|
args = parser.parse_known_args()[0]
|
|
209
211
|
|
|
212
|
+
rng = np.random.default_rng(42)
|
|
213
|
+
|
|
210
214
|
with wp.ScopedDevice(args.device):
|
|
211
215
|
example = Example(stage_path=args.stage_path, num_envs=args.num_envs)
|
|
212
216
|
|
|
@@ -218,7 +222,7 @@ if __name__ == "__main__":
|
|
|
218
222
|
for _ in range(args.num_rollouts):
|
|
219
223
|
# select new random target points for all envs
|
|
220
224
|
example.targets = example.target_origin.copy()
|
|
221
|
-
example.targets[:, 1:] +=
|
|
225
|
+
example.targets[:, 1:] += rng.uniform(-0.5, 0.5, size=(example.num_envs, 2))
|
|
222
226
|
|
|
223
227
|
for iter in range(args.train_iters):
|
|
224
228
|
example.step()
|
|
@@ -115,10 +115,11 @@ class Example:
|
|
|
115
115
|
|
|
116
116
|
self.model.joint_attach_ke = 16000.0
|
|
117
117
|
self.model.joint_attach_kd = 200.0
|
|
118
|
+
self.use_tile_gemm = False
|
|
118
119
|
|
|
119
120
|
# self.integrator = wp.sim.XPBDIntegrator()
|
|
120
121
|
# self.integrator = wp.sim.SemiImplicitIntegrator()
|
|
121
|
-
self.integrator = wp.sim.FeatherstoneIntegrator(self.model)
|
|
122
|
+
self.integrator = wp.sim.FeatherstoneIntegrator(self.model, use_tile_gemm=self.use_tile_gemm)
|
|
122
123
|
|
|
123
124
|
if stage_path:
|
|
124
125
|
self.renderer = wp.sim.render.SimRenderer(self.model, stage_path)
|