warp-lang 1.0.0b2__py3-none-manylinux2014_x86_64.whl → 1.0.0b6__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.
- docs/conf.py +17 -5
- examples/env/env_ant.py +1 -1
- examples/env/env_cartpole.py +1 -1
- examples/env/env_humanoid.py +1 -1
- examples/env/env_usd.py +4 -1
- examples/env/environment.py +8 -9
- examples/example_dem.py +34 -33
- examples/example_diffray.py +364 -337
- examples/example_fluid.py +32 -23
- examples/example_jacobian_ik.py +97 -93
- examples/example_marching_cubes.py +6 -16
- examples/example_mesh.py +6 -16
- examples/example_mesh_intersect.py +16 -14
- examples/example_nvdb.py +14 -16
- examples/example_raycast.py +14 -13
- examples/example_raymarch.py +16 -23
- examples/example_render_opengl.py +19 -10
- examples/example_sim_cartpole.py +82 -78
- examples/example_sim_cloth.py +45 -48
- examples/example_sim_fk_grad.py +51 -44
- examples/example_sim_fk_grad_torch.py +47 -40
- examples/example_sim_grad_bounce.py +108 -133
- examples/example_sim_grad_cloth.py +99 -113
- examples/example_sim_granular.py +5 -6
- examples/{example_sim_sdf_shape.py → example_sim_granular_collision_sdf.py} +37 -26
- examples/example_sim_neo_hookean.py +51 -55
- examples/example_sim_particle_chain.py +4 -4
- examples/example_sim_quadruped.py +126 -81
- examples/example_sim_rigid_chain.py +54 -61
- examples/example_sim_rigid_contact.py +66 -70
- examples/example_sim_rigid_fem.py +3 -3
- examples/example_sim_rigid_force.py +1 -1
- examples/example_sim_rigid_gyroscopic.py +3 -4
- examples/example_sim_rigid_kinematics.py +28 -39
- examples/example_sim_trajopt.py +112 -110
- examples/example_sph.py +9 -8
- examples/example_wave.py +7 -7
- examples/fem/bsr_utils.py +30 -17
- examples/fem/example_apic_fluid.py +85 -69
- examples/fem/example_convection_diffusion.py +97 -93
- examples/fem/example_convection_diffusion_dg.py +142 -149
- examples/fem/example_convection_diffusion_dg0.py +141 -136
- examples/fem/example_deformed_geometry.py +146 -0
- examples/fem/example_diffusion.py +115 -84
- examples/fem/example_diffusion_3d.py +116 -86
- examples/fem/example_diffusion_mgpu.py +102 -79
- examples/fem/example_mixed_elasticity.py +139 -100
- examples/fem/example_navier_stokes.py +175 -162
- examples/fem/example_stokes.py +143 -111
- examples/fem/example_stokes_transfer.py +186 -157
- examples/fem/mesh_utils.py +59 -97
- examples/fem/plot_utils.py +138 -17
- tools/ci/publishing/build_nodes_info.py +54 -0
- warp/__init__.py +4 -3
- warp/__init__.pyi +1 -0
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +5 -3
- warp/build_dll.py +29 -9
- warp/builtins.py +836 -492
- warp/codegen.py +864 -553
- warp/config.py +3 -1
- warp/context.py +389 -172
- warp/fem/__init__.py +24 -6
- warp/fem/cache.py +318 -25
- warp/fem/dirichlet.py +7 -3
- warp/fem/domain.py +14 -0
- warp/fem/field/__init__.py +30 -38
- warp/fem/field/field.py +149 -0
- warp/fem/field/nodal_field.py +244 -138
- warp/fem/field/restriction.py +8 -6
- warp/fem/field/test.py +127 -59
- warp/fem/field/trial.py +117 -60
- warp/fem/geometry/__init__.py +5 -1
- warp/fem/geometry/deformed_geometry.py +271 -0
- warp/fem/geometry/element.py +24 -1
- warp/fem/geometry/geometry.py +86 -14
- warp/fem/geometry/grid_2d.py +112 -54
- warp/fem/geometry/grid_3d.py +134 -65
- warp/fem/geometry/hexmesh.py +953 -0
- warp/fem/geometry/partition.py +85 -33
- warp/fem/geometry/quadmesh_2d.py +532 -0
- warp/fem/geometry/tetmesh.py +451 -115
- warp/fem/geometry/trimesh_2d.py +197 -92
- warp/fem/integrate.py +534 -268
- warp/fem/operator.py +58 -31
- warp/fem/polynomial.py +11 -0
- warp/fem/quadrature/__init__.py +1 -1
- warp/fem/quadrature/pic_quadrature.py +150 -58
- warp/fem/quadrature/quadrature.py +209 -57
- warp/fem/space/__init__.py +230 -53
- warp/fem/space/basis_space.py +489 -0
- warp/fem/space/collocated_function_space.py +105 -0
- warp/fem/space/dof_mapper.py +49 -2
- warp/fem/space/function_space.py +90 -39
- warp/fem/space/grid_2d_function_space.py +149 -496
- warp/fem/space/grid_3d_function_space.py +173 -538
- warp/fem/space/hexmesh_function_space.py +352 -0
- warp/fem/space/partition.py +129 -76
- warp/fem/space/quadmesh_2d_function_space.py +369 -0
- warp/fem/space/restriction.py +46 -34
- warp/fem/space/shape/__init__.py +15 -0
- warp/fem/space/shape/cube_shape_function.py +738 -0
- warp/fem/space/shape/shape_function.py +103 -0
- warp/fem/space/shape/square_shape_function.py +611 -0
- warp/fem/space/shape/tet_shape_function.py +567 -0
- warp/fem/space/shape/triangle_shape_function.py +429 -0
- warp/fem/space/tetmesh_function_space.py +132 -1039
- warp/fem/space/topology.py +295 -0
- warp/fem/space/trimesh_2d_function_space.py +104 -742
- warp/fem/types.py +13 -11
- warp/fem/utils.py +335 -60
- warp/native/array.h +120 -34
- warp/native/builtin.h +101 -72
- warp/native/bvh.cpp +73 -325
- warp/native/bvh.cu +406 -23
- warp/native/bvh.h +22 -40
- warp/native/clang/clang.cpp +1 -0
- warp/native/crt.h +2 -0
- warp/native/cuda_util.cpp +8 -3
- warp/native/cuda_util.h +1 -0
- warp/native/exports.h +1522 -1243
- warp/native/intersect.h +19 -4
- warp/native/intersect_adj.h +8 -8
- warp/native/mat.h +76 -17
- warp/native/mesh.cpp +33 -108
- warp/native/mesh.cu +114 -18
- warp/native/mesh.h +395 -40
- warp/native/noise.h +272 -329
- warp/native/quat.h +51 -8
- warp/native/rand.h +44 -34
- warp/native/reduce.cpp +1 -1
- warp/native/sparse.cpp +4 -4
- warp/native/sparse.cu +163 -155
- warp/native/spatial.h +2 -2
- warp/native/temp_buffer.h +18 -14
- warp/native/vec.h +103 -21
- warp/native/warp.cpp +2 -1
- warp/native/warp.cu +28 -3
- warp/native/warp.h +4 -3
- warp/render/render_opengl.py +261 -109
- warp/sim/__init__.py +1 -2
- warp/sim/articulation.py +385 -185
- warp/sim/import_mjcf.py +59 -48
- warp/sim/import_urdf.py +15 -15
- warp/sim/import_usd.py +174 -102
- warp/sim/inertia.py +17 -18
- warp/sim/integrator_xpbd.py +4 -3
- warp/sim/model.py +330 -250
- warp/sim/render.py +1 -1
- warp/sparse.py +625 -152
- warp/stubs.py +341 -309
- warp/tape.py +9 -6
- warp/tests/__main__.py +3 -6
- warp/tests/assets/curlnoise_golden.npy +0 -0
- warp/tests/assets/pnoise_golden.npy +0 -0
- warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
- warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
- warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
- warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
- warp/tests/aux_test_unresolved_func.py +14 -0
- warp/tests/aux_test_unresolved_symbol.py +14 -0
- warp/tests/disabled_kinematics.py +239 -0
- warp/tests/run_coverage_serial.py +31 -0
- warp/tests/test_adam.py +103 -106
- warp/tests/test_arithmetic.py +94 -74
- warp/tests/test_array.py +82 -101
- warp/tests/test_array_reduce.py +57 -23
- warp/tests/test_atomic.py +64 -28
- warp/tests/test_bool.py +22 -12
- warp/tests/test_builtins_resolution.py +1292 -0
- warp/tests/test_bvh.py +18 -18
- warp/tests/test_closest_point_edge_edge.py +54 -57
- warp/tests/test_codegen.py +165 -134
- warp/tests/test_compile_consts.py +28 -20
- warp/tests/test_conditional.py +108 -24
- warp/tests/test_copy.py +10 -12
- warp/tests/test_ctypes.py +112 -88
- warp/tests/test_dense.py +21 -14
- warp/tests/test_devices.py +98 -0
- warp/tests/test_dlpack.py +75 -75
- warp/tests/test_examples.py +237 -0
- warp/tests/test_fabricarray.py +22 -24
- warp/tests/test_fast_math.py +15 -11
- warp/tests/test_fem.py +1034 -124
- warp/tests/test_fp16.py +23 -16
- warp/tests/test_func.py +187 -86
- warp/tests/test_generics.py +194 -49
- warp/tests/test_grad.py +123 -181
- warp/tests/test_grad_customs.py +176 -0
- warp/tests/test_hash_grid.py +35 -34
- warp/tests/test_import.py +10 -23
- warp/tests/test_indexedarray.py +24 -25
- warp/tests/test_intersect.py +18 -9
- warp/tests/test_large.py +141 -0
- warp/tests/test_launch.py +14 -41
- warp/tests/test_lerp.py +64 -65
- warp/tests/test_lvalue.py +493 -0
- warp/tests/test_marching_cubes.py +12 -13
- warp/tests/test_mat.py +517 -2898
- warp/tests/test_mat_lite.py +115 -0
- warp/tests/test_mat_scalar_ops.py +2889 -0
- warp/tests/test_math.py +103 -9
- warp/tests/test_matmul.py +304 -69
- warp/tests/test_matmul_lite.py +410 -0
- warp/tests/test_mesh.py +60 -22
- warp/tests/test_mesh_query_aabb.py +21 -25
- warp/tests/test_mesh_query_point.py +111 -22
- warp/tests/test_mesh_query_ray.py +12 -24
- warp/tests/test_mlp.py +30 -22
- warp/tests/test_model.py +92 -89
- warp/tests/test_modules_lite.py +39 -0
- warp/tests/test_multigpu.py +88 -114
- warp/tests/test_noise.py +12 -11
- warp/tests/test_operators.py +16 -20
- warp/tests/test_options.py +11 -11
- warp/tests/test_pinned.py +17 -18
- warp/tests/test_print.py +32 -11
- warp/tests/test_quat.py +275 -129
- warp/tests/test_rand.py +18 -16
- warp/tests/test_reload.py +38 -34
- warp/tests/test_rounding.py +50 -43
- warp/tests/test_runlength_encode.py +168 -20
- warp/tests/test_smoothstep.py +9 -11
- warp/tests/test_snippet.py +143 -0
- warp/tests/test_sparse.py +261 -63
- warp/tests/test_spatial.py +276 -243
- warp/tests/test_streams.py +110 -85
- warp/tests/test_struct.py +268 -63
- warp/tests/test_tape.py +39 -21
- warp/tests/test_torch.py +90 -86
- warp/tests/test_transient_module.py +10 -12
- warp/tests/test_types.py +363 -0
- warp/tests/test_utils.py +451 -0
- warp/tests/test_vec.py +354 -2050
- warp/tests/test_vec_lite.py +73 -0
- warp/tests/test_vec_scalar_ops.py +2099 -0
- warp/tests/test_volume.py +418 -376
- warp/tests/test_volume_write.py +124 -134
- warp/tests/unittest_serial.py +35 -0
- warp/tests/unittest_suites.py +291 -0
- warp/tests/unittest_utils.py +342 -0
- warp/tests/{test_misc.py → unused_test_misc.py} +13 -5
- warp/tests/{test_debug.py → walkthough_debug.py} +3 -17
- warp/thirdparty/appdirs.py +36 -45
- warp/thirdparty/unittest_parallel.py +589 -0
- warp/types.py +622 -211
- warp/utils.py +54 -393
- warp_lang-1.0.0b6.dist-info/METADATA +238 -0
- warp_lang-1.0.0b6.dist-info/RECORD +409 -0
- {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/WHEEL +1 -1
- examples/example_cache_management.py +0 -40
- examples/example_multigpu.py +0 -54
- examples/example_struct.py +0 -65
- examples/fem/example_stokes_transfer_3d.py +0 -210
- warp/fem/field/discrete_field.py +0 -80
- warp/fem/space/nodal_function_space.py +0 -233
- warp/tests/test_all.py +0 -223
- warp/tests/test_array_scan.py +0 -60
- warp/tests/test_base.py +0 -208
- warp/tests/test_unresolved_func.py +0 -7
- warp/tests/test_unresolved_symbol.py +0 -7
- warp_lang-1.0.0b2.dist-info/METADATA +0 -26
- warp_lang-1.0.0b2.dist-info/RECORD +0 -378
- /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
- /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
- /warp/tests/{test_square.py → aux_test_square.py} +0 -0
- {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/top_level.txt +0 -0
|
@@ -5,30 +5,27 @@ This example illustrates using domain decomposition to solve a diffusion PDE ove
|
|
|
5
5
|
from typing import Tuple
|
|
6
6
|
|
|
7
7
|
import warp as wp
|
|
8
|
-
|
|
9
|
-
from warp.fem.types import *
|
|
10
|
-
from warp.fem.geometry import Grid2D, LinearGeometryPartition
|
|
11
|
-
from warp.fem.space import make_polynomial_space, make_space_partition
|
|
12
|
-
from warp.fem.field import make_test, make_trial
|
|
13
|
-
from warp.fem.domain import Cells, BoundarySides
|
|
14
|
-
from warp.fem.integrate import integrate
|
|
15
|
-
from warp.fem.operator import integrand
|
|
16
|
-
|
|
8
|
+
import warp.fem as fem
|
|
17
9
|
from warp.sparse import bsr_axpy, bsr_mv
|
|
18
10
|
from warp.utils import array_cast
|
|
19
11
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
# Import example utilities
|
|
13
|
+
# Make sure that works both when imported as module and run as standalone file
|
|
14
|
+
try:
|
|
15
|
+
from .bsr_utils import bsr_cg
|
|
16
|
+
from .example_diffusion import diffusion_form, linear_form
|
|
17
|
+
from .plot_utils import Plot
|
|
18
|
+
except ImportError:
|
|
19
|
+
from bsr_utils import bsr_cg
|
|
20
|
+
from example_diffusion import diffusion_form, linear_form
|
|
21
|
+
from plot_utils import Plot
|
|
25
22
|
|
|
26
23
|
|
|
27
|
-
@integrand
|
|
24
|
+
@fem.integrand
|
|
28
25
|
def mass_form(
|
|
29
|
-
s: Sample,
|
|
30
|
-
u: Field,
|
|
31
|
-
v: Field,
|
|
26
|
+
s: fem.Sample,
|
|
27
|
+
u: fem.Field,
|
|
28
|
+
v: fem.Field,
|
|
32
29
|
):
|
|
33
30
|
return u(s) * v(s)
|
|
34
31
|
|
|
@@ -96,77 +93,103 @@ def mv_routine(A: DistributedSystem, x: wp.array, y: wp.array, alpha=1.0, beta=0
|
|
|
96
93
|
wp.launch(kernel=sum_kernel, dim=idx.shape, device=y_idx.device, inputs=[y_idx, tmp_i], stream=stream)
|
|
97
94
|
|
|
98
95
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
96
|
+
class Example:
|
|
97
|
+
def __init__(self, stage=None, quiet=False):
|
|
98
|
+
self._bd_weight = 100.0
|
|
99
|
+
self._quiet = quiet
|
|
100
|
+
|
|
101
|
+
self._geo = fem.Grid2D(res=wp.vec2i(25))
|
|
102
|
+
|
|
103
|
+
self._main_device = wp.get_device("cuda")
|
|
104
|
+
|
|
105
|
+
with wp.ScopedDevice(self._main_device):
|
|
106
|
+
self._scalar_space = fem.make_polynomial_space(self._geo, degree=3)
|
|
107
|
+
self._scalar_field = self._scalar_space.make_field()
|
|
108
|
+
|
|
109
|
+
self.renderer = Plot(stage)
|
|
110
|
+
|
|
111
|
+
def update(self):
|
|
112
|
+
devices = wp.get_cuda_devices()
|
|
113
|
+
main_device = self._main_device
|
|
114
|
+
|
|
115
|
+
rhs_vecs = []
|
|
116
|
+
res_vecs = []
|
|
117
|
+
matrices = []
|
|
118
|
+
indices = []
|
|
119
|
+
|
|
120
|
+
# Build local system for each device
|
|
121
|
+
for k, device in enumerate(devices):
|
|
122
|
+
with wp.ScopedDevice(device):
|
|
123
|
+
# Construct the partition corresponding to the k'th device
|
|
124
|
+
geo_partition = fem.LinearGeometryPartition(self._geo, k, len(devices))
|
|
125
|
+
matrix, rhs, partition_node_indices = self._assemble_local_system(geo_partition)
|
|
126
|
+
|
|
127
|
+
rhs_vecs.append(rhs)
|
|
128
|
+
res_vecs.append(wp.empty_like(rhs))
|
|
129
|
+
matrices.append(matrix)
|
|
130
|
+
indices.append(partition_node_indices.to(main_device))
|
|
131
|
+
|
|
132
|
+
# Global rhs as sum of all local rhs
|
|
133
|
+
glob_rhs = wp.zeros(n=self._scalar_space.node_count(), dtype=wp.float64, device=main_device)
|
|
134
|
+
tmp = wp.empty_like(glob_rhs)
|
|
135
|
+
sum_vecs(rhs_vecs, indices, glob_rhs, tmp)
|
|
136
|
+
|
|
137
|
+
# Distributed CG
|
|
138
|
+
global_res = wp.zeros_like(glob_rhs)
|
|
139
|
+
A = DistributedSystem()
|
|
140
|
+
A.device = device
|
|
141
|
+
A.scalar_type = glob_rhs.dtype
|
|
142
|
+
A.nrow = self._scalar_space.node_count()
|
|
143
|
+
A.shape = (A.nrow, A.nrow)
|
|
144
|
+
A.tmp_buf = tmp
|
|
145
|
+
A.rank_data = (matrices, rhs_vecs, res_vecs, indices)
|
|
146
|
+
|
|
147
|
+
bsr_cg(
|
|
148
|
+
A,
|
|
149
|
+
x=global_res,
|
|
150
|
+
b=glob_rhs,
|
|
151
|
+
use_diag_precond=False,
|
|
152
|
+
quiet=self._quiet,
|
|
153
|
+
mv_routine=mv_routine,
|
|
154
|
+
device=main_device,
|
|
155
|
+
)
|
|
125
156
|
|
|
126
|
-
|
|
127
|
-
test = make_test(space_partition=space_partition, domain=domain)
|
|
128
|
-
rhs = integrate(linear_form, fields={"v": test})
|
|
157
|
+
array_cast(in_array=global_res, out_array=self._scalar_field.dof_values)
|
|
129
158
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
bd_test = make_test(space_partition=space_partition, domain=boundary)
|
|
133
|
-
bd_trial = make_trial(space_partition=space_partition, domain=boundary)
|
|
134
|
-
bd_matrix = integrate(mass_form, fields={"u": bd_trial, "v": bd_test})
|
|
159
|
+
def render(self):
|
|
160
|
+
self.renderer.add_surface("solution", self._scalar_field)
|
|
135
161
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
162
|
+
def _assemble_local_system(self, geo_partition: fem.GeometryPartition):
|
|
163
|
+
scalar_space = self._scalar_space
|
|
164
|
+
space_partition = fem.make_space_partition(scalar_space, geo_partition)
|
|
139
165
|
|
|
140
|
-
|
|
166
|
+
domain = fem.Cells(geometry=geo_partition)
|
|
141
167
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
indices.append(space_partition.space_node_indices().to(main_device))
|
|
168
|
+
# Right-hand-side
|
|
169
|
+
test = fem.make_test(space=scalar_space, space_partition=space_partition, domain=domain)
|
|
170
|
+
rhs = fem.integrate(linear_form, fields={"v": test})
|
|
146
171
|
|
|
172
|
+
# Weakly-imposed boundary conditions on all sides
|
|
173
|
+
boundary = fem.BoundarySides(geometry=geo_partition)
|
|
174
|
+
bd_test = fem.make_test(space=scalar_space, space_partition=space_partition, domain=boundary)
|
|
175
|
+
bd_trial = fem.make_trial(space=scalar_space, space_partition=space_partition, domain=boundary)
|
|
176
|
+
bd_matrix = fem.integrate(mass_form, fields={"u": bd_trial, "v": bd_test})
|
|
147
177
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
sum_vecs(rhs_vecs, indices, glob_rhs, tmp)
|
|
178
|
+
# Diffusion form
|
|
179
|
+
trial = fem.make_trial(space=scalar_space, space_partition=space_partition, domain=domain)
|
|
180
|
+
matrix = fem.integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": 1.0})
|
|
152
181
|
|
|
153
|
-
|
|
154
|
-
glob_res = wp.zeros_like(glob_rhs)
|
|
155
|
-
A = DistributedSystem()
|
|
156
|
-
A.device = device
|
|
157
|
-
A.scalar_type = glob_rhs.dtype
|
|
158
|
-
A.nrow = scalar_space.node_count()
|
|
159
|
-
A.shape = (A.nrow, A.nrow)
|
|
160
|
-
A.tmp_buf = tmp
|
|
161
|
-
A.rank_data = (matrices, rhs_vecs, res_vecs, indices)
|
|
182
|
+
bsr_axpy(y=matrix, x=bd_matrix, alpha=self._bd_weight)
|
|
162
183
|
|
|
163
|
-
|
|
164
|
-
bsr_cg(A, x=glob_res, b=glob_rhs, use_diag_precond=False, mv_routine=mv_routine, device=main_device)
|
|
184
|
+
return matrix, rhs, space_partition.space_node_indices()
|
|
165
185
|
|
|
166
|
-
scalar_field = scalar_space.make_field()
|
|
167
186
|
|
|
168
|
-
|
|
187
|
+
if __name__ == "__main__":
|
|
188
|
+
wp.init()
|
|
189
|
+
wp.set_module_options({"enable_backward": False})
|
|
169
190
|
|
|
170
|
-
|
|
191
|
+
example = Example()
|
|
192
|
+
example.update()
|
|
193
|
+
example.render()
|
|
171
194
|
|
|
172
|
-
|
|
195
|
+
example.renderer.plot()
|
|
@@ -5,25 +5,20 @@ with Dirichlet boundary conditions on horizontal sides, and E the elasticity ran
|
|
|
5
5
|
import argparse
|
|
6
6
|
|
|
7
7
|
import warp as wp
|
|
8
|
-
|
|
9
8
|
import numpy as np
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
from warp.fem.geometry import Grid2D, Trimesh2D
|
|
13
|
-
from warp.fem.field import make_test, make_trial
|
|
14
|
-
from warp.fem.space import make_polynomial_space, SymmetricTensorMapper
|
|
15
|
-
from warp.fem.domain import Cells, BoundarySides
|
|
16
|
-
from warp.fem.integrate import integrate
|
|
17
|
-
from warp.fem.operator import normal, integrand, D
|
|
18
|
-
from warp.fem.dirichlet import project_linear_system
|
|
10
|
+
import warp.fem as fem
|
|
19
11
|
|
|
20
12
|
from warp.sparse import bsr_transposed, bsr_mm
|
|
21
13
|
|
|
22
|
-
|
|
23
|
-
from
|
|
24
|
-
from
|
|
25
|
-
|
|
26
|
-
|
|
14
|
+
try:
|
|
15
|
+
from .plot_utils import Plot
|
|
16
|
+
from .bsr_utils import bsr_cg, invert_diagonal_bsr_mass_matrix
|
|
17
|
+
from .mesh_utils import gen_trimesh, gen_quadmesh
|
|
18
|
+
except ImportError:
|
|
19
|
+
from plot_utils import Plot
|
|
20
|
+
from bsr_utils import bsr_cg, invert_diagonal_bsr_mass_matrix
|
|
21
|
+
from mesh_utils import gen_trimesh, gen_quadmesh
|
|
27
22
|
|
|
28
23
|
|
|
29
24
|
@wp.func
|
|
@@ -34,134 +29,178 @@ def compute_stress(tau: wp.mat22, E: wp.mat33):
|
|
|
34
29
|
return wp.mat22(sig_sym[0], 0.5 * sig_sym[2], 0.5 * sig_sym[2], sig_sym[1])
|
|
35
30
|
|
|
36
31
|
|
|
37
|
-
@integrand
|
|
32
|
+
@fem.integrand
|
|
38
33
|
def symmetric_grad_form(
|
|
39
|
-
s: Sample,
|
|
40
|
-
u: Field,
|
|
41
|
-
tau: Field,
|
|
34
|
+
s: fem.Sample,
|
|
35
|
+
u: fem.Field,
|
|
36
|
+
tau: fem.Field,
|
|
42
37
|
):
|
|
43
38
|
"""D(u) : tau"""
|
|
44
|
-
return wp.ddot(tau(s), D(u, s))
|
|
39
|
+
return wp.ddot(tau(s), fem.D(u, s))
|
|
45
40
|
|
|
46
41
|
|
|
47
|
-
@integrand
|
|
48
|
-
def stress_form(s: Sample, u: Field, tau: Field, E: wp.mat33):
|
|
42
|
+
@fem.integrand
|
|
43
|
+
def stress_form(s: fem.Sample, u: fem.Field, tau: fem.Field, E: wp.mat33):
|
|
49
44
|
"""(E : D(u)) : tau"""
|
|
50
|
-
return wp.ddot(tau(s), compute_stress(D(u, s), E))
|
|
45
|
+
return wp.ddot(tau(s), compute_stress(fem.D(u, s), E))
|
|
51
46
|
|
|
52
47
|
|
|
53
|
-
@integrand
|
|
48
|
+
@fem.integrand
|
|
54
49
|
def horizontal_boundary_projector_form(
|
|
55
|
-
s: Sample,
|
|
56
|
-
domain: Domain,
|
|
57
|
-
u: Field,
|
|
58
|
-
v: Field,
|
|
50
|
+
s: fem.Sample,
|
|
51
|
+
domain: fem.Domain,
|
|
52
|
+
u: fem.Field,
|
|
53
|
+
v: fem.Field,
|
|
59
54
|
):
|
|
60
55
|
# non zero on horizontal boundary of domain only
|
|
61
|
-
nor = normal(domain, s)
|
|
56
|
+
nor = fem.normal(domain, s)
|
|
62
57
|
return wp.dot(u(s), v(s)) * wp.abs(nor[1])
|
|
63
58
|
|
|
64
59
|
|
|
65
|
-
@integrand
|
|
60
|
+
@fem.integrand
|
|
66
61
|
def horizontal_displacement_form(
|
|
67
|
-
s: Sample,
|
|
68
|
-
domain: Domain,
|
|
69
|
-
v: Field,
|
|
62
|
+
s: fem.Sample,
|
|
63
|
+
domain: fem.Domain,
|
|
64
|
+
v: fem.Field,
|
|
70
65
|
displacement: float,
|
|
71
66
|
):
|
|
72
67
|
# opposed to normal on horizontal boundary of domain only
|
|
73
|
-
nor = normal(domain, s)
|
|
68
|
+
nor = fem.normal(domain, s)
|
|
74
69
|
return -wp.abs(nor[1]) * displacement * wp.dot(nor, v(s))
|
|
75
70
|
|
|
76
71
|
|
|
77
|
-
@integrand
|
|
72
|
+
@fem.integrand
|
|
78
73
|
def tensor_mass_form(
|
|
79
|
-
s: Sample,
|
|
80
|
-
sig: Field,
|
|
81
|
-
tau: Field,
|
|
74
|
+
s: fem.Sample,
|
|
75
|
+
sig: fem.Field,
|
|
76
|
+
tau: fem.Field,
|
|
82
77
|
):
|
|
83
78
|
return wp.ddot(tau(s), sig(s))
|
|
84
79
|
|
|
85
80
|
|
|
86
|
-
|
|
87
|
-
wp.init()
|
|
88
|
-
wp.set_module_options({"enable_backward": False})
|
|
89
|
-
|
|
81
|
+
class Example:
|
|
90
82
|
parser = argparse.ArgumentParser()
|
|
91
83
|
parser.add_argument("--resolution", type=int, default=25)
|
|
92
84
|
parser.add_argument("--degree", type=int, default=2)
|
|
93
85
|
parser.add_argument("--displacement", type=float, default=0.1)
|
|
94
86
|
parser.add_argument("--young_modulus", type=float, default=1.0)
|
|
95
87
|
parser.add_argument("--poisson_ratio", type=float, default=0.5)
|
|
96
|
-
parser.add_argument("--
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if args.tri_mesh:
|
|
100
|
-
positions, tri_vidx = gen_trimesh(res=vec2i(args.resolution))
|
|
101
|
-
geo = Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
102
|
-
else:
|
|
103
|
-
geo = Grid2D(res=vec2i(args.resolution))
|
|
104
|
-
|
|
105
|
-
boundary = BoundarySides(geo)
|
|
106
|
-
|
|
107
|
-
# Strain-stress matrix
|
|
108
|
-
young = args.young_modulus
|
|
109
|
-
poisson = args.poisson_ratio
|
|
110
|
-
elasticity_mat = wp.mat33(
|
|
111
|
-
young
|
|
112
|
-
/ (1.0 - poisson * poisson)
|
|
113
|
-
* np.array(
|
|
114
|
-
[[1.0, poisson, 0.0], [poisson, 1.0, 0.0], [0.0, 0.0, (2.0 * (1.0 + poisson)) * (1.0 - poisson * poisson)]]
|
|
115
|
-
)
|
|
88
|
+
parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
|
|
89
|
+
parser.add_argument(
|
|
90
|
+
"--nonconforming_stresses", action="store_true", help="For grid, use non-conforming stresses (Q_d/P_d)"
|
|
116
91
|
)
|
|
117
92
|
|
|
118
|
-
|
|
93
|
+
def __init__(self, stage=None, quiet=False, args=None, **kwargs):
|
|
94
|
+
if args is None:
|
|
95
|
+
# Read args from kwargs, add default arg values from parser
|
|
96
|
+
args = argparse.Namespace(**kwargs)
|
|
97
|
+
args = Example.parser.parse_args(args=[], namespace=args)
|
|
98
|
+
self._args = args
|
|
99
|
+
self._quiet = quiet
|
|
100
|
+
|
|
101
|
+
# Grid or triangle mesh geometry
|
|
102
|
+
if args.mesh == "tri":
|
|
103
|
+
positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
|
|
104
|
+
self._geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
105
|
+
elif args.mesh == "quad":
|
|
106
|
+
positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
|
|
107
|
+
self._geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
|
|
108
|
+
else:
|
|
109
|
+
self._geo = fem.Grid2D(res=wp.vec2i(args.resolution))
|
|
110
|
+
|
|
111
|
+
# Strain-stress matrix
|
|
112
|
+
young = args.young_modulus
|
|
113
|
+
poisson = args.poisson_ratio
|
|
114
|
+
self._elasticity_mat = wp.mat33(
|
|
115
|
+
young
|
|
116
|
+
/ (1.0 - poisson * poisson)
|
|
117
|
+
* np.array(
|
|
118
|
+
[
|
|
119
|
+
[1.0, poisson, 0.0],
|
|
120
|
+
[poisson, 1.0, 0.0],
|
|
121
|
+
[0.0, 0.0, (2.0 * (1.0 + poisson)) * (1.0 - poisson * poisson)],
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
)
|
|
119
125
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
geo, degree=args.degree - 1, discontinuous=True, dof_mapper=SymmetricTensorMapper(wp.mat22)
|
|
125
|
-
)
|
|
126
|
+
# Function spaces -- S_k for displacement, Q_{k-1}d for stress
|
|
127
|
+
self._u_space = fem.make_polynomial_space(
|
|
128
|
+
self._geo, degree=args.degree, dtype=wp.vec2, element_basis=fem.ElementBasis.SERENDIPITY
|
|
129
|
+
)
|
|
126
130
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
# Store stress degrees of freedom as symmetric tensors (3 dof) rather than full 2x2 matrices
|
|
132
|
+
tau_basis = (
|
|
133
|
+
fem.ElementBasis.NONCONFORMING_POLYNOMIAL if args.nonconforming_stresses else fem.ElementBasis.LAGRANGE
|
|
134
|
+
)
|
|
135
|
+
self._tau_space = fem.make_polynomial_space(
|
|
136
|
+
self._geo,
|
|
137
|
+
degree=args.degree - 1,
|
|
138
|
+
discontinuous=True,
|
|
139
|
+
element_basis=tau_basis,
|
|
140
|
+
dof_mapper=fem.SymmetricTensorMapper(wp.mat22),
|
|
141
|
+
)
|
|
138
142
|
|
|
139
|
-
|
|
140
|
-
u_trial = make_trial(space=u_space, domain=domain)
|
|
141
|
-
tau_test = make_test(space=tau_space, domain=domain)
|
|
142
|
-
tau_trial = make_trial(space=tau_space, domain=domain)
|
|
143
|
+
self._u_field = self._u_space.make_field()
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
stress_matrix = integrate(stress_form, fields={"u": u_trial, "tau": tau_test}, values={"E": elasticity_mat})
|
|
145
|
+
self.renderer = Plot(stage)
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
def update(self):
|
|
148
|
+
boundary = fem.BoundarySides(self._geo)
|
|
149
|
+
domain = fem.Cells(geometry=self._geo)
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
# Displacement boundary conditions
|
|
152
|
+
u_bd_test = fem.make_test(space=self._u_space, domain=boundary)
|
|
153
|
+
u_bd_trial = fem.make_trial(space=self._u_space, domain=boundary)
|
|
154
|
+
u_bd_rhs = fem.integrate(
|
|
155
|
+
horizontal_displacement_form,
|
|
156
|
+
fields={"v": u_bd_test},
|
|
157
|
+
values={"displacement": self._args.displacement},
|
|
158
|
+
nodal=True,
|
|
159
|
+
output_dtype=wp.vec2d,
|
|
160
|
+
)
|
|
161
|
+
u_bd_matrix = fem.integrate(
|
|
162
|
+
horizontal_boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Stress/velocity coupling
|
|
166
|
+
u_trial = fem.make_trial(space=self._u_space, domain=domain)
|
|
167
|
+
tau_test = fem.make_test(space=self._tau_space, domain=domain)
|
|
168
|
+
tau_trial = fem.make_trial(space=self._tau_space, domain=domain)
|
|
169
|
+
|
|
170
|
+
sym_grad_matrix = fem.integrate(symmetric_grad_form, fields={"u": u_trial, "tau": tau_test})
|
|
171
|
+
stress_matrix = fem.integrate(
|
|
172
|
+
stress_form, fields={"u": u_trial, "tau": tau_test}, values={"E": self._elasticity_mat}
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Compute inverse of the (block-diagonal) tau mass matrix
|
|
176
|
+
tau_inv_mass_matrix = fem.integrate(tensor_mass_form, fields={"sig": tau_trial, "tau": tau_test}, nodal=True)
|
|
177
|
+
invert_diagonal_bsr_mass_matrix(tau_inv_mass_matrix)
|
|
178
|
+
|
|
179
|
+
# Assemble system matrix
|
|
180
|
+
u_matrix = bsr_mm(bsr_transposed(sym_grad_matrix), bsr_mm(tau_inv_mass_matrix, stress_matrix))
|
|
181
|
+
|
|
182
|
+
# Enforce boundary conditions
|
|
183
|
+
u_rhs = wp.zeros_like(u_bd_rhs)
|
|
184
|
+
fem.project_linear_system(u_matrix, u_rhs, u_bd_matrix, u_bd_rhs)
|
|
153
185
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
project_linear_system(u_matrix, u_rhs, u_bd_matrix, u_bd_rhs)
|
|
186
|
+
x = wp.zeros_like(u_rhs)
|
|
187
|
+
bsr_cg(u_matrix, b=u_rhs, x=x, tol=1.0e-16, quiet=self._quiet)
|
|
157
188
|
|
|
158
|
-
|
|
159
|
-
|
|
189
|
+
# Extract result
|
|
190
|
+
self._u_field.dof_values = x
|
|
191
|
+
|
|
192
|
+
def render(self):
|
|
193
|
+
self.renderer.add_surface_vector("solution", self._u_field)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if __name__ == "__main__":
|
|
197
|
+
wp.init()
|
|
198
|
+
wp.set_module_options({"enable_backward": False})
|
|
160
199
|
|
|
161
|
-
|
|
162
|
-
u_field = u_space.make_field()
|
|
163
|
-
u_field.dof_values = x # .reshape((-1, 2))
|
|
200
|
+
args = Example.parser.parse_args()
|
|
164
201
|
|
|
165
|
-
|
|
202
|
+
example = Example(args=args)
|
|
203
|
+
example.update()
|
|
204
|
+
example.render()
|
|
166
205
|
|
|
167
|
-
|
|
206
|
+
example.renderer.plot()
|