warp-lang 1.0.0b2__py3-none-win_amd64.whl → 1.0.0b6__py3-none-win_amd64.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.
- 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.dll +0 -0
- warp/bin/warp.dll +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/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- 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 -380
- /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
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This example solves a 2d diffusion problem:
|
|
3
|
+
nu Div u = 1
|
|
4
|
+
with Dirichlet boundary conditions on vertical edges and homogeneous Neumann on horizontal edges.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
|
|
9
|
+
import warp as wp
|
|
10
|
+
import warp.fem as fem
|
|
11
|
+
|
|
12
|
+
from warp.sparse import bsr_axpy
|
|
13
|
+
from warp.fem.utils import array_axpy
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Import example utilities
|
|
17
|
+
# Make sure that works both when imported as module and run as standalone file
|
|
18
|
+
try:
|
|
19
|
+
from .example_diffusion import linear_form, diffusion_form
|
|
20
|
+
from .bsr_utils import bsr_cg
|
|
21
|
+
from .mesh_utils import gen_trimesh, gen_quadmesh
|
|
22
|
+
from .plot_utils import Plot
|
|
23
|
+
except ImportError:
|
|
24
|
+
from example_diffusion import linear_form, diffusion_form
|
|
25
|
+
from bsr_utils import bsr_cg
|
|
26
|
+
from mesh_utils import gen_trimesh, gen_quadmesh
|
|
27
|
+
from plot_utils import Plot
|
|
28
|
+
|
|
29
|
+
@fem.integrand
|
|
30
|
+
def deformation_field_expr(
|
|
31
|
+
s: fem.Sample,
|
|
32
|
+
domain: fem.Domain,
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Deformation field mapping the unique square to a circular band
|
|
36
|
+
"""
|
|
37
|
+
x = domain(s)
|
|
38
|
+
|
|
39
|
+
r = x[1] + 0.5
|
|
40
|
+
t = 0.5 * 3.1416 * x[0]
|
|
41
|
+
|
|
42
|
+
return r * wp.vec2(wp.sin(t), wp.cos(t)) - x
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@fem.integrand
|
|
46
|
+
def boundary_projector_form(
|
|
47
|
+
s: fem.Sample,
|
|
48
|
+
domain: fem.Domain,
|
|
49
|
+
u: fem.Field,
|
|
50
|
+
v: fem.Field,
|
|
51
|
+
):
|
|
52
|
+
"""
|
|
53
|
+
Bilinear boundary condition projector form, non-zero on radial edges
|
|
54
|
+
"""
|
|
55
|
+
nor = fem.normal(domain, s)
|
|
56
|
+
active = wp.select(nor[0] < -0.9999 or nor[1] < -0.9999, 0.0, 1.0)
|
|
57
|
+
return active * u(s) * v(s)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Example:
|
|
61
|
+
parser = argparse.ArgumentParser()
|
|
62
|
+
parser.add_argument("--resolution", type=int, default=50)
|
|
63
|
+
parser.add_argument("--degree", type=int, default=2)
|
|
64
|
+
parser.add_argument("--serendipity", action="store_true", default=False)
|
|
65
|
+
parser.add_argument("--viscosity", type=float, default=2.0)
|
|
66
|
+
parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
|
|
67
|
+
|
|
68
|
+
def __init__(self, stage=None, quiet=False, args=None, **kwargs):
|
|
69
|
+
if args is None:
|
|
70
|
+
# Read args from kwargs, add default arg values from parser
|
|
71
|
+
args = argparse.Namespace(**kwargs)
|
|
72
|
+
args = Example.parser.parse_args(args=[], namespace=args)
|
|
73
|
+
self._args = args
|
|
74
|
+
self._quiet = quiet
|
|
75
|
+
|
|
76
|
+
# Grid or triangle mesh geometry
|
|
77
|
+
if args.mesh == "tri":
|
|
78
|
+
positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
|
|
79
|
+
base_geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
80
|
+
elif args.mesh == "quad":
|
|
81
|
+
positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
|
|
82
|
+
base_geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
|
|
83
|
+
else:
|
|
84
|
+
base_geo = fem.Grid2D(res=wp.vec2i(args.resolution))
|
|
85
|
+
|
|
86
|
+
# Construct deformation field on base geometry
|
|
87
|
+
deformation_space = fem.make_polynomial_space(base_geo, degree=args.degree, dtype=wp.vec2)
|
|
88
|
+
deformation_field = deformation_space.make_field()
|
|
89
|
+
fem.interpolate(deformation_field_expr, dest=deformation_field)
|
|
90
|
+
|
|
91
|
+
self._geo = deformation_field.make_deformed_geometry()
|
|
92
|
+
|
|
93
|
+
# Scalar function space on deformed geometry
|
|
94
|
+
element_basis = fem.ElementBasis.SERENDIPITY if args.serendipity else None
|
|
95
|
+
self._scalar_space = fem.make_polynomial_space(self._geo, degree=args.degree, element_basis=element_basis)
|
|
96
|
+
|
|
97
|
+
# Scalar field over our function space
|
|
98
|
+
self._scalar_field = self._scalar_space.make_field()
|
|
99
|
+
|
|
100
|
+
self.renderer = Plot(stage)
|
|
101
|
+
|
|
102
|
+
def update(self):
|
|
103
|
+
args = self._args
|
|
104
|
+
geo = self._geo
|
|
105
|
+
|
|
106
|
+
domain = fem.Cells(geometry=geo)
|
|
107
|
+
|
|
108
|
+
# Right-hand-side (forcing term)
|
|
109
|
+
test = fem.make_test(space=self._scalar_space, domain=domain)
|
|
110
|
+
rhs = fem.integrate(linear_form, fields={"v": test})
|
|
111
|
+
|
|
112
|
+
# Diffusion form
|
|
113
|
+
trial = fem.make_trial(space=self._scalar_space, domain=domain)
|
|
114
|
+
matrix = fem.integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": args.viscosity})
|
|
115
|
+
|
|
116
|
+
# Weakly-imposed boundary conditions on all sides
|
|
117
|
+
boundary = fem.BoundarySides(geo)
|
|
118
|
+
bd_test = fem.make_test(space=self._scalar_space, domain=boundary)
|
|
119
|
+
bd_trial = fem.make_trial(space=self._scalar_space, domain=boundary)
|
|
120
|
+
|
|
121
|
+
bd_matrix = fem.integrate(boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
|
|
122
|
+
|
|
123
|
+
fem.project_linear_system(matrix, rhs, bd_matrix)
|
|
124
|
+
|
|
125
|
+
# Solve linear system using Conjugate Gradient
|
|
126
|
+
x = wp.zeros_like(rhs)
|
|
127
|
+
bsr_cg(matrix, b=rhs, x=x, quiet=self._quiet, tol=1.0e-6)
|
|
128
|
+
|
|
129
|
+
# Assign system result to our discrete field
|
|
130
|
+
self._scalar_field.dof_values = x
|
|
131
|
+
|
|
132
|
+
def render(self):
|
|
133
|
+
self.renderer.add_surface("solution", self._scalar_field)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if __name__ == "__main__":
|
|
137
|
+
wp.init()
|
|
138
|
+
wp.set_module_options({"enable_backward": False})
|
|
139
|
+
|
|
140
|
+
args = Example.parser.parse_args()
|
|
141
|
+
|
|
142
|
+
example = Example(args=args)
|
|
143
|
+
example.update()
|
|
144
|
+
example.render()
|
|
145
|
+
|
|
146
|
+
example.renderer.plot()
|
|
@@ -7,57 +7,57 @@ with Dirichlet boundary conditions on vertical edges and homogeneous Neumann on
|
|
|
7
7
|
import argparse
|
|
8
8
|
|
|
9
9
|
import warp as wp
|
|
10
|
-
|
|
11
|
-
from warp.fem.types import *
|
|
12
|
-
from warp.fem.geometry import Grid2D, Trimesh2D
|
|
13
|
-
from warp.fem.space import make_polynomial_space
|
|
14
|
-
from warp.fem.field import make_test, make_trial
|
|
15
|
-
from warp.fem.domain import Cells, BoundarySides
|
|
16
|
-
from warp.fem.integrate import integrate
|
|
17
|
-
from warp.fem.operator import grad, normal, integrand
|
|
18
|
-
from warp.fem.dirichlet import project_linear_system
|
|
10
|
+
import warp.fem as fem
|
|
19
11
|
|
|
20
12
|
from warp.sparse import bsr_axpy
|
|
21
13
|
from warp.fem.utils import array_axpy
|
|
22
14
|
|
|
23
|
-
from plot_utils import plot_surface
|
|
24
|
-
from bsr_utils import bsr_cg
|
|
25
|
-
from mesh_utils import gen_trimesh
|
|
26
15
|
|
|
27
|
-
|
|
16
|
+
# Import example utilities
|
|
17
|
+
# Make sure that works both when imported as module and run as standalone file
|
|
18
|
+
try:
|
|
19
|
+
from .bsr_utils import bsr_cg
|
|
20
|
+
from .mesh_utils import gen_trimesh, gen_quadmesh
|
|
21
|
+
from .plot_utils import Plot
|
|
22
|
+
except ImportError:
|
|
23
|
+
from bsr_utils import bsr_cg
|
|
24
|
+
from mesh_utils import gen_trimesh, gen_quadmesh
|
|
25
|
+
from plot_utils import Plot
|
|
26
|
+
|
|
27
|
+
wp.set_module_options({"enable_backward": False})
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
@integrand
|
|
30
|
+
@fem.integrand
|
|
31
31
|
def linear_form(
|
|
32
|
-
s: Sample,
|
|
33
|
-
v: Field,
|
|
32
|
+
s: fem.Sample,
|
|
33
|
+
v: fem.Field,
|
|
34
34
|
):
|
|
35
35
|
"""Linear form with constant slope 1 -- forcing term of our problem"""
|
|
36
36
|
return v(s)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
@integrand
|
|
40
|
-
def diffusion_form(s: Sample, u: Field, v: Field, nu: float):
|
|
39
|
+
@fem.integrand
|
|
40
|
+
def diffusion_form(s: fem.Sample, u: fem.Field, v: fem.Field, nu: float):
|
|
41
41
|
"""Diffusion bilinear form with constant coefficient ``nu``"""
|
|
42
42
|
return nu * wp.dot(
|
|
43
|
-
grad(u, s),
|
|
44
|
-
grad(v, s),
|
|
43
|
+
fem.grad(u, s),
|
|
44
|
+
fem.grad(v, s),
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
@integrand
|
|
49
|
-
def y_boundary_value_form(s: Sample, domain: Domain, v: Field, val: float):
|
|
48
|
+
@fem.integrand
|
|
49
|
+
def y_boundary_value_form(s: fem.Sample, domain: fem.Domain, v: fem.Field, val: float):
|
|
50
50
|
"""Linear form with coefficient val on vertical edges, zero elsewhere"""
|
|
51
|
-
nor = normal(domain, s)
|
|
51
|
+
nor = fem.normal(domain, s)
|
|
52
52
|
return val * v(s) * wp.abs(nor[0])
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
@integrand
|
|
55
|
+
@fem.integrand
|
|
56
56
|
def y_boundary_projector_form(
|
|
57
|
-
s: Sample,
|
|
58
|
-
domain: Domain,
|
|
59
|
-
u: Field,
|
|
60
|
-
v: Field,
|
|
57
|
+
s: fem.Sample,
|
|
58
|
+
domain: fem.Domain,
|
|
59
|
+
u: fem.Field,
|
|
60
|
+
v: fem.Field,
|
|
61
61
|
):
|
|
62
62
|
"""
|
|
63
63
|
Bilinear boundary condition projector form, non-zero on vertical edges only.
|
|
@@ -66,65 +66,96 @@ def y_boundary_projector_form(
|
|
|
66
66
|
return y_boundary_value_form(s, domain, v, u(s))
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
wp.init()
|
|
71
|
-
wp.set_module_options({"enable_backward": False})
|
|
72
|
-
|
|
69
|
+
class Example:
|
|
73
70
|
parser = argparse.ArgumentParser()
|
|
74
71
|
parser.add_argument("--resolution", type=int, default=50)
|
|
75
72
|
parser.add_argument("--degree", type=int, default=2)
|
|
73
|
+
parser.add_argument("--serendipity", action="store_true", default=False)
|
|
76
74
|
parser.add_argument("--viscosity", type=float, default=2.0)
|
|
77
75
|
parser.add_argument("--boundary_value", type=float, default=5.0)
|
|
78
76
|
parser.add_argument("--boundary_compliance", type=float, default=0, help="Dirichlet boundary condition compliance")
|
|
79
|
-
parser.add_argument("--
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
77
|
+
parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
|
|
78
|
+
|
|
79
|
+
def __init__(self, stage=None, quiet=False, args=None, **kwargs):
|
|
80
|
+
if args is None:
|
|
81
|
+
# Read args from kwargs, add default arg values from parser
|
|
82
|
+
args = argparse.Namespace(**kwargs)
|
|
83
|
+
args = Example.parser.parse_args(args=[], namespace=args)
|
|
84
|
+
self._args = args
|
|
85
|
+
self._quiet = quiet
|
|
86
|
+
|
|
87
|
+
# Grid or triangle mesh geometry
|
|
88
|
+
if args.mesh == "tri":
|
|
89
|
+
positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
|
|
90
|
+
self._geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
91
|
+
elif args.mesh == "quad":
|
|
92
|
+
positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
|
|
93
|
+
self._geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
|
|
94
|
+
else:
|
|
95
|
+
self._geo = fem.Grid2D(res=wp.vec2i(args.resolution))
|
|
96
|
+
|
|
97
|
+
# Scalar function space
|
|
98
|
+
element_basis = fem.ElementBasis.SERENDIPITY if args.serendipity else None
|
|
99
|
+
self._scalar_space = fem.make_polynomial_space(self._geo, degree=args.degree, element_basis=element_basis)
|
|
100
|
+
|
|
101
|
+
# Scalar field over our function space
|
|
102
|
+
self._scalar_field = self._scalar_space.make_field()
|
|
103
|
+
|
|
104
|
+
self.renderer = Plot(stage)
|
|
105
|
+
|
|
106
|
+
def update(self):
|
|
107
|
+
args = self._args
|
|
108
|
+
geo = self._geo
|
|
109
|
+
|
|
110
|
+
domain = fem.Cells(geometry=geo)
|
|
111
|
+
|
|
112
|
+
# Right-hand-side (forcing term)
|
|
113
|
+
test = fem.make_test(space=self._scalar_space, domain=domain)
|
|
114
|
+
rhs = fem.integrate(linear_form, fields={"v": test})
|
|
115
|
+
|
|
116
|
+
# Diffusion form
|
|
117
|
+
trial = fem.make_trial(space=self._scalar_space, domain=domain)
|
|
118
|
+
matrix = fem.integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": args.viscosity})
|
|
119
|
+
|
|
120
|
+
# Boundary conditions on Y sides
|
|
121
|
+
# Use nodal integration so that boundary conditions are specified on each node independently
|
|
122
|
+
boundary = fem.BoundarySides(geo)
|
|
123
|
+
bd_test = fem.make_test(space=self._scalar_space, domain=boundary)
|
|
124
|
+
bd_trial = fem.make_trial(space=self._scalar_space, domain=boundary)
|
|
125
|
+
|
|
126
|
+
bd_matrix = fem.integrate(y_boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
|
|
127
|
+
bd_rhs = fem.integrate(
|
|
128
|
+
y_boundary_value_form, fields={"v": bd_test}, values={"val": args.boundary_value}, nodal=True
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Assemble linear system
|
|
132
|
+
if args.boundary_compliance == 0.0:
|
|
133
|
+
# Hard BC: project linear system
|
|
134
|
+
fem.project_linear_system(matrix, rhs, bd_matrix, bd_rhs)
|
|
135
|
+
else:
|
|
136
|
+
# Weak BC: add toegether diffusion and boundary condition matrices
|
|
137
|
+
boundary_strength = 1.0 / args.boundary_compliance
|
|
138
|
+
bsr_axpy(x=bd_matrix, y=matrix, alpha=boundary_strength, beta=1)
|
|
139
|
+
array_axpy(x=bd_rhs, y=rhs, alpha=boundary_strength, beta=1)
|
|
140
|
+
|
|
141
|
+
# Solve linear system using Conjugate Gradient
|
|
142
|
+
x = wp.zeros_like(rhs)
|
|
143
|
+
bsr_cg(matrix, b=rhs, x=x, quiet=self._quiet)
|
|
144
|
+
|
|
145
|
+
# Assign system result to our discrete field
|
|
146
|
+
self._scalar_field.dof_values = x
|
|
147
|
+
|
|
148
|
+
def render(self):
|
|
149
|
+
self.renderer.add_surface("solution", self._scalar_field)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
if __name__ == "__main__":
|
|
153
|
+
wp.init()
|
|
154
|
+
|
|
155
|
+
args = Example.parser.parse_args()
|
|
156
|
+
|
|
157
|
+
example = Example(args=args)
|
|
158
|
+
example.update()
|
|
159
|
+
example.render()
|
|
160
|
+
|
|
161
|
+
example.renderer.plot()
|
|
@@ -7,103 +7,133 @@ with homogeneous Neumann conditions on horizontal sides and homogeneous Dirichle
|
|
|
7
7
|
import argparse
|
|
8
8
|
|
|
9
9
|
import warp as wp
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
from warp.fem.types import *
|
|
13
|
-
from warp.fem.geometry import Grid3D, Tetmesh
|
|
14
|
-
from warp.fem.space import make_polynomial_space
|
|
15
|
-
from warp.fem.field import make_test, make_trial
|
|
16
|
-
from warp.fem.domain import Cells, BoundarySides
|
|
17
|
-
from warp.fem.integrate import integrate
|
|
18
|
-
from warp.fem.operator import normal, integrand
|
|
19
|
-
from warp.fem.dirichlet import project_linear_system
|
|
10
|
+
import warp.fem as fem
|
|
20
11
|
|
|
21
12
|
from warp.sparse import bsr_axpy
|
|
22
13
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
from
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
14
|
+
# Import example utilities
|
|
15
|
+
# Make sure that works both when imported as module and run as standalone file
|
|
16
|
+
try:
|
|
17
|
+
from .example_diffusion import diffusion_form, linear_form
|
|
18
|
+
from .bsr_utils import bsr_cg
|
|
19
|
+
from .mesh_utils import gen_tetmesh
|
|
20
|
+
from .plot_utils import Plot
|
|
21
|
+
except ImportError:
|
|
22
|
+
from example_diffusion import diffusion_form, linear_form
|
|
23
|
+
from bsr_utils import bsr_cg
|
|
24
|
+
from mesh_utils import gen_tetmesh, gen_hexmesh
|
|
25
|
+
from plot_utils import Plot
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@fem.integrand
|
|
33
29
|
def vert_boundary_projector_form(
|
|
34
|
-
s: Sample,
|
|
35
|
-
domain: Domain,
|
|
36
|
-
u: Field,
|
|
37
|
-
v: Field,
|
|
30
|
+
s: fem.Sample,
|
|
31
|
+
domain: fem.Domain,
|
|
32
|
+
u: fem.Field,
|
|
33
|
+
v: fem.Field,
|
|
38
34
|
):
|
|
39
35
|
# Non-zero mass on vertical sides only
|
|
40
|
-
w = 1.0 - wp.abs(normal(domain, s)[1])
|
|
36
|
+
w = 1.0 - wp.abs(fem.normal(domain, s)[1])
|
|
41
37
|
return w * u(s) * v(s)
|
|
42
38
|
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
wp.init()
|
|
46
|
-
wp.set_module_options({"enable_backward": False})
|
|
47
|
-
|
|
40
|
+
class Example:
|
|
48
41
|
parser = argparse.ArgumentParser()
|
|
49
42
|
parser.add_argument("--resolution", type=int, default=10)
|
|
50
43
|
parser.add_argument("--degree", type=int, default=2)
|
|
44
|
+
parser.add_argument("--serendipity", action="store_true", default=False)
|
|
51
45
|
parser.add_argument("--viscosity", type=float, default=2.0)
|
|
52
46
|
parser.add_argument("--boundary_compliance", type=float, default=0, help="Dirichlet boundary condition compliance")
|
|
53
|
-
parser.add_argument("--
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
47
|
+
parser.add_argument("--mesh", choices=("grid", "tet", "hex"), default="grid", help="Mesh type")
|
|
48
|
+
|
|
49
|
+
def __init__(self, stage=None, quiet=False, args=None, **kwargs):
|
|
50
|
+
if args is None:
|
|
51
|
+
# Read args from kwargs, add default arg values from parser
|
|
52
|
+
args = argparse.Namespace(**kwargs)
|
|
53
|
+
args = Example.parser.parse_args(args=[], namespace=args)
|
|
54
|
+
self._args = args
|
|
55
|
+
self._quiet = quiet
|
|
56
|
+
|
|
57
|
+
res = wp.vec3i(args.resolution, args.resolution // 2, args.resolution * 2)
|
|
58
|
+
|
|
59
|
+
if args.mesh == "tet":
|
|
60
|
+
pos, tet_vtx_indices = gen_tetmesh(
|
|
61
|
+
res=res,
|
|
62
|
+
bounds_lo=wp.vec3(0.0, 0.0, 0.0),
|
|
63
|
+
bounds_hi=wp.vec3(1.0, 0.5, 2.0),
|
|
64
|
+
)
|
|
65
|
+
self._geo = fem.Tetmesh(tet_vtx_indices, pos)
|
|
66
|
+
elif args.mesh == "hex":
|
|
67
|
+
pos, hex_vtx_indices = gen_hexmesh(
|
|
68
|
+
res=res,
|
|
69
|
+
bounds_lo=wp.vec3(0.0, 0.0, 0.0),
|
|
70
|
+
bounds_hi=wp.vec3(1.0, 0.5, 2.0),
|
|
71
|
+
)
|
|
72
|
+
self._geo = fem.Hexmesh(hex_vtx_indices, pos)
|
|
73
|
+
else:
|
|
74
|
+
self._geo = fem.Grid3D(
|
|
75
|
+
res=res,
|
|
76
|
+
bounds_lo=wp.vec3(0.0, 0.0, 0.0),
|
|
77
|
+
bounds_hi=wp.vec3(1.0, 0.5, 2.0),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Domain and function spaces
|
|
81
|
+
element_basis = fem.ElementBasis.SERENDIPITY if args.serendipity else None
|
|
82
|
+
self._scalar_space = fem.make_polynomial_space(self._geo, degree=args.degree, element_basis=element_basis)
|
|
83
|
+
|
|
84
|
+
# Scalar field over our function space
|
|
85
|
+
self._scalar_field: fem.DiscreteField = self._scalar_space.make_field()
|
|
86
|
+
|
|
87
|
+
self.renderer = Plot(stage)
|
|
88
|
+
|
|
89
|
+
def update(self):
|
|
90
|
+
args = self._args
|
|
91
|
+
geo = self._geo
|
|
92
|
+
|
|
93
|
+
domain = fem.Cells(geometry=geo)
|
|
94
|
+
|
|
95
|
+
# Right-hand-side
|
|
96
|
+
test = fem.make_test(space=self._scalar_space, domain=domain)
|
|
97
|
+
rhs = fem.integrate(linear_form, fields={"v": test})
|
|
98
|
+
|
|
99
|
+
# Weakly-imposed boundary conditions on Y sides
|
|
100
|
+
with wp.ScopedTimer("Integrate"):
|
|
101
|
+
boundary = fem.BoundarySides(geo)
|
|
102
|
+
|
|
103
|
+
bd_test = fem.make_test(space=self._scalar_space, domain=boundary)
|
|
104
|
+
bd_trial = fem.make_trial(space=self._scalar_space, domain=boundary)
|
|
105
|
+
bd_matrix = fem.integrate(vert_boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
|
|
106
|
+
|
|
107
|
+
# Diffusion form
|
|
108
|
+
trial = fem.make_trial(space=self._scalar_space, domain=domain)
|
|
109
|
+
matrix = fem.integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": args.viscosity})
|
|
110
|
+
|
|
111
|
+
if args.boundary_compliance == 0.0:
|
|
112
|
+
# Hard BC: project linear system
|
|
113
|
+
bd_rhs = wp.zeros_like(rhs)
|
|
114
|
+
fem.project_linear_system(matrix, rhs, bd_matrix, bd_rhs)
|
|
115
|
+
else:
|
|
116
|
+
# Weak BC: add toegether diffusion and boundary condition matrices
|
|
117
|
+
boundary_strength = 1.0 / args.boundary_compliance
|
|
118
|
+
bsr_axpy(x=bd_matrix, y=matrix, alpha=boundary_strength, beta=1)
|
|
119
|
+
|
|
120
|
+
with wp.ScopedTimer("CG solve"):
|
|
121
|
+
x = wp.zeros_like(rhs)
|
|
122
|
+
bsr_cg(matrix, b=rhs, x=x, quiet=self._quiet)
|
|
123
|
+
self._scalar_field.dof_values = x
|
|
124
|
+
|
|
125
|
+
def render(self):
|
|
126
|
+
self.renderer.add_volume("solution", self._scalar_field)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if __name__ == "__main__":
|
|
130
|
+
wp.init()
|
|
131
|
+
wp.set_module_options({"enable_backward": False})
|
|
132
|
+
|
|
133
|
+
args = Example.parser.parse_args()
|
|
134
|
+
|
|
135
|
+
example = Example(args=args)
|
|
136
|
+
example.update()
|
|
137
|
+
example.render()
|
|
138
|
+
|
|
139
|
+
example.renderer.plot()
|