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.
Files changed (269) hide show
  1. docs/conf.py +17 -5
  2. examples/env/env_ant.py +1 -1
  3. examples/env/env_cartpole.py +1 -1
  4. examples/env/env_humanoid.py +1 -1
  5. examples/env/env_usd.py +4 -1
  6. examples/env/environment.py +8 -9
  7. examples/example_dem.py +34 -33
  8. examples/example_diffray.py +364 -337
  9. examples/example_fluid.py +32 -23
  10. examples/example_jacobian_ik.py +97 -93
  11. examples/example_marching_cubes.py +6 -16
  12. examples/example_mesh.py +6 -16
  13. examples/example_mesh_intersect.py +16 -14
  14. examples/example_nvdb.py +14 -16
  15. examples/example_raycast.py +14 -13
  16. examples/example_raymarch.py +16 -23
  17. examples/example_render_opengl.py +19 -10
  18. examples/example_sim_cartpole.py +82 -78
  19. examples/example_sim_cloth.py +45 -48
  20. examples/example_sim_fk_grad.py +51 -44
  21. examples/example_sim_fk_grad_torch.py +47 -40
  22. examples/example_sim_grad_bounce.py +108 -133
  23. examples/example_sim_grad_cloth.py +99 -113
  24. examples/example_sim_granular.py +5 -6
  25. examples/{example_sim_sdf_shape.py → example_sim_granular_collision_sdf.py} +37 -26
  26. examples/example_sim_neo_hookean.py +51 -55
  27. examples/example_sim_particle_chain.py +4 -4
  28. examples/example_sim_quadruped.py +126 -81
  29. examples/example_sim_rigid_chain.py +54 -61
  30. examples/example_sim_rigid_contact.py +66 -70
  31. examples/example_sim_rigid_fem.py +3 -3
  32. examples/example_sim_rigid_force.py +1 -1
  33. examples/example_sim_rigid_gyroscopic.py +3 -4
  34. examples/example_sim_rigid_kinematics.py +28 -39
  35. examples/example_sim_trajopt.py +112 -110
  36. examples/example_sph.py +9 -8
  37. examples/example_wave.py +7 -7
  38. examples/fem/bsr_utils.py +30 -17
  39. examples/fem/example_apic_fluid.py +85 -69
  40. examples/fem/example_convection_diffusion.py +97 -93
  41. examples/fem/example_convection_diffusion_dg.py +142 -149
  42. examples/fem/example_convection_diffusion_dg0.py +141 -136
  43. examples/fem/example_deformed_geometry.py +146 -0
  44. examples/fem/example_diffusion.py +115 -84
  45. examples/fem/example_diffusion_3d.py +116 -86
  46. examples/fem/example_diffusion_mgpu.py +102 -79
  47. examples/fem/example_mixed_elasticity.py +139 -100
  48. examples/fem/example_navier_stokes.py +175 -162
  49. examples/fem/example_stokes.py +143 -111
  50. examples/fem/example_stokes_transfer.py +186 -157
  51. examples/fem/mesh_utils.py +59 -97
  52. examples/fem/plot_utils.py +138 -17
  53. tools/ci/publishing/build_nodes_info.py +54 -0
  54. warp/__init__.py +4 -3
  55. warp/__init__.pyi +1 -0
  56. warp/bin/warp-clang.so +0 -0
  57. warp/bin/warp.so +0 -0
  58. warp/build.py +5 -3
  59. warp/build_dll.py +29 -9
  60. warp/builtins.py +836 -492
  61. warp/codegen.py +864 -553
  62. warp/config.py +3 -1
  63. warp/context.py +389 -172
  64. warp/fem/__init__.py +24 -6
  65. warp/fem/cache.py +318 -25
  66. warp/fem/dirichlet.py +7 -3
  67. warp/fem/domain.py +14 -0
  68. warp/fem/field/__init__.py +30 -38
  69. warp/fem/field/field.py +149 -0
  70. warp/fem/field/nodal_field.py +244 -138
  71. warp/fem/field/restriction.py +8 -6
  72. warp/fem/field/test.py +127 -59
  73. warp/fem/field/trial.py +117 -60
  74. warp/fem/geometry/__init__.py +5 -1
  75. warp/fem/geometry/deformed_geometry.py +271 -0
  76. warp/fem/geometry/element.py +24 -1
  77. warp/fem/geometry/geometry.py +86 -14
  78. warp/fem/geometry/grid_2d.py +112 -54
  79. warp/fem/geometry/grid_3d.py +134 -65
  80. warp/fem/geometry/hexmesh.py +953 -0
  81. warp/fem/geometry/partition.py +85 -33
  82. warp/fem/geometry/quadmesh_2d.py +532 -0
  83. warp/fem/geometry/tetmesh.py +451 -115
  84. warp/fem/geometry/trimesh_2d.py +197 -92
  85. warp/fem/integrate.py +534 -268
  86. warp/fem/operator.py +58 -31
  87. warp/fem/polynomial.py +11 -0
  88. warp/fem/quadrature/__init__.py +1 -1
  89. warp/fem/quadrature/pic_quadrature.py +150 -58
  90. warp/fem/quadrature/quadrature.py +209 -57
  91. warp/fem/space/__init__.py +230 -53
  92. warp/fem/space/basis_space.py +489 -0
  93. warp/fem/space/collocated_function_space.py +105 -0
  94. warp/fem/space/dof_mapper.py +49 -2
  95. warp/fem/space/function_space.py +90 -39
  96. warp/fem/space/grid_2d_function_space.py +149 -496
  97. warp/fem/space/grid_3d_function_space.py +173 -538
  98. warp/fem/space/hexmesh_function_space.py +352 -0
  99. warp/fem/space/partition.py +129 -76
  100. warp/fem/space/quadmesh_2d_function_space.py +369 -0
  101. warp/fem/space/restriction.py +46 -34
  102. warp/fem/space/shape/__init__.py +15 -0
  103. warp/fem/space/shape/cube_shape_function.py +738 -0
  104. warp/fem/space/shape/shape_function.py +103 -0
  105. warp/fem/space/shape/square_shape_function.py +611 -0
  106. warp/fem/space/shape/tet_shape_function.py +567 -0
  107. warp/fem/space/shape/triangle_shape_function.py +429 -0
  108. warp/fem/space/tetmesh_function_space.py +132 -1039
  109. warp/fem/space/topology.py +295 -0
  110. warp/fem/space/trimesh_2d_function_space.py +104 -742
  111. warp/fem/types.py +13 -11
  112. warp/fem/utils.py +335 -60
  113. warp/native/array.h +120 -34
  114. warp/native/builtin.h +101 -72
  115. warp/native/bvh.cpp +73 -325
  116. warp/native/bvh.cu +406 -23
  117. warp/native/bvh.h +22 -40
  118. warp/native/clang/clang.cpp +1 -0
  119. warp/native/crt.h +2 -0
  120. warp/native/cuda_util.cpp +8 -3
  121. warp/native/cuda_util.h +1 -0
  122. warp/native/exports.h +1522 -1243
  123. warp/native/intersect.h +19 -4
  124. warp/native/intersect_adj.h +8 -8
  125. warp/native/mat.h +76 -17
  126. warp/native/mesh.cpp +33 -108
  127. warp/native/mesh.cu +114 -18
  128. warp/native/mesh.h +395 -40
  129. warp/native/noise.h +272 -329
  130. warp/native/quat.h +51 -8
  131. warp/native/rand.h +44 -34
  132. warp/native/reduce.cpp +1 -1
  133. warp/native/sparse.cpp +4 -4
  134. warp/native/sparse.cu +163 -155
  135. warp/native/spatial.h +2 -2
  136. warp/native/temp_buffer.h +18 -14
  137. warp/native/vec.h +103 -21
  138. warp/native/warp.cpp +2 -1
  139. warp/native/warp.cu +28 -3
  140. warp/native/warp.h +4 -3
  141. warp/render/render_opengl.py +261 -109
  142. warp/sim/__init__.py +1 -2
  143. warp/sim/articulation.py +385 -185
  144. warp/sim/import_mjcf.py +59 -48
  145. warp/sim/import_urdf.py +15 -15
  146. warp/sim/import_usd.py +174 -102
  147. warp/sim/inertia.py +17 -18
  148. warp/sim/integrator_xpbd.py +4 -3
  149. warp/sim/model.py +330 -250
  150. warp/sim/render.py +1 -1
  151. warp/sparse.py +625 -152
  152. warp/stubs.py +341 -309
  153. warp/tape.py +9 -6
  154. warp/tests/__main__.py +3 -6
  155. warp/tests/assets/curlnoise_golden.npy +0 -0
  156. warp/tests/assets/pnoise_golden.npy +0 -0
  157. warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
  158. warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
  159. warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
  160. warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
  161. warp/tests/aux_test_unresolved_func.py +14 -0
  162. warp/tests/aux_test_unresolved_symbol.py +14 -0
  163. warp/tests/disabled_kinematics.py +239 -0
  164. warp/tests/run_coverage_serial.py +31 -0
  165. warp/tests/test_adam.py +103 -106
  166. warp/tests/test_arithmetic.py +94 -74
  167. warp/tests/test_array.py +82 -101
  168. warp/tests/test_array_reduce.py +57 -23
  169. warp/tests/test_atomic.py +64 -28
  170. warp/tests/test_bool.py +22 -12
  171. warp/tests/test_builtins_resolution.py +1292 -0
  172. warp/tests/test_bvh.py +18 -18
  173. warp/tests/test_closest_point_edge_edge.py +54 -57
  174. warp/tests/test_codegen.py +165 -134
  175. warp/tests/test_compile_consts.py +28 -20
  176. warp/tests/test_conditional.py +108 -24
  177. warp/tests/test_copy.py +10 -12
  178. warp/tests/test_ctypes.py +112 -88
  179. warp/tests/test_dense.py +21 -14
  180. warp/tests/test_devices.py +98 -0
  181. warp/tests/test_dlpack.py +75 -75
  182. warp/tests/test_examples.py +237 -0
  183. warp/tests/test_fabricarray.py +22 -24
  184. warp/tests/test_fast_math.py +15 -11
  185. warp/tests/test_fem.py +1034 -124
  186. warp/tests/test_fp16.py +23 -16
  187. warp/tests/test_func.py +187 -86
  188. warp/tests/test_generics.py +194 -49
  189. warp/tests/test_grad.py +123 -181
  190. warp/tests/test_grad_customs.py +176 -0
  191. warp/tests/test_hash_grid.py +35 -34
  192. warp/tests/test_import.py +10 -23
  193. warp/tests/test_indexedarray.py +24 -25
  194. warp/tests/test_intersect.py +18 -9
  195. warp/tests/test_large.py +141 -0
  196. warp/tests/test_launch.py +14 -41
  197. warp/tests/test_lerp.py +64 -65
  198. warp/tests/test_lvalue.py +493 -0
  199. warp/tests/test_marching_cubes.py +12 -13
  200. warp/tests/test_mat.py +517 -2898
  201. warp/tests/test_mat_lite.py +115 -0
  202. warp/tests/test_mat_scalar_ops.py +2889 -0
  203. warp/tests/test_math.py +103 -9
  204. warp/tests/test_matmul.py +304 -69
  205. warp/tests/test_matmul_lite.py +410 -0
  206. warp/tests/test_mesh.py +60 -22
  207. warp/tests/test_mesh_query_aabb.py +21 -25
  208. warp/tests/test_mesh_query_point.py +111 -22
  209. warp/tests/test_mesh_query_ray.py +12 -24
  210. warp/tests/test_mlp.py +30 -22
  211. warp/tests/test_model.py +92 -89
  212. warp/tests/test_modules_lite.py +39 -0
  213. warp/tests/test_multigpu.py +88 -114
  214. warp/tests/test_noise.py +12 -11
  215. warp/tests/test_operators.py +16 -20
  216. warp/tests/test_options.py +11 -11
  217. warp/tests/test_pinned.py +17 -18
  218. warp/tests/test_print.py +32 -11
  219. warp/tests/test_quat.py +275 -129
  220. warp/tests/test_rand.py +18 -16
  221. warp/tests/test_reload.py +38 -34
  222. warp/tests/test_rounding.py +50 -43
  223. warp/tests/test_runlength_encode.py +168 -20
  224. warp/tests/test_smoothstep.py +9 -11
  225. warp/tests/test_snippet.py +143 -0
  226. warp/tests/test_sparse.py +261 -63
  227. warp/tests/test_spatial.py +276 -243
  228. warp/tests/test_streams.py +110 -85
  229. warp/tests/test_struct.py +268 -63
  230. warp/tests/test_tape.py +39 -21
  231. warp/tests/test_torch.py +90 -86
  232. warp/tests/test_transient_module.py +10 -12
  233. warp/tests/test_types.py +363 -0
  234. warp/tests/test_utils.py +451 -0
  235. warp/tests/test_vec.py +354 -2050
  236. warp/tests/test_vec_lite.py +73 -0
  237. warp/tests/test_vec_scalar_ops.py +2099 -0
  238. warp/tests/test_volume.py +418 -376
  239. warp/tests/test_volume_write.py +124 -134
  240. warp/tests/unittest_serial.py +35 -0
  241. warp/tests/unittest_suites.py +291 -0
  242. warp/tests/unittest_utils.py +342 -0
  243. warp/tests/{test_misc.py → unused_test_misc.py} +13 -5
  244. warp/tests/{test_debug.py → walkthough_debug.py} +3 -17
  245. warp/thirdparty/appdirs.py +36 -45
  246. warp/thirdparty/unittest_parallel.py +589 -0
  247. warp/types.py +622 -211
  248. warp/utils.py +54 -393
  249. warp_lang-1.0.0b6.dist-info/METADATA +238 -0
  250. warp_lang-1.0.0b6.dist-info/RECORD +409 -0
  251. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/WHEEL +1 -1
  252. examples/example_cache_management.py +0 -40
  253. examples/example_multigpu.py +0 -54
  254. examples/example_struct.py +0 -65
  255. examples/fem/example_stokes_transfer_3d.py +0 -210
  256. warp/fem/field/discrete_field.py +0 -80
  257. warp/fem/space/nodal_function_space.py +0 -233
  258. warp/tests/test_all.py +0 -223
  259. warp/tests/test_array_scan.py +0 -60
  260. warp/tests/test_base.py +0 -208
  261. warp/tests/test_unresolved_func.py +0 -7
  262. warp/tests/test_unresolved_symbol.py +0 -7
  263. warp_lang-1.0.0b2.dist-info/METADATA +0 -26
  264. warp_lang-1.0.0b2.dist-info/RECORD +0 -378
  265. /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
  266. /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
  267. /warp/tests/{test_square.py → aux_test_square.py} +0 -0
  268. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/LICENSE.md +0 -0
  269. {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
- import matplotlib.pyplot as plt
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
- if __name__ == "__main__":
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("--tri_mesh", action="store_true", help="Use a triangular mesh")
80
- args = parser.parse_args()
81
-
82
- # Grid or triangle mesh geometry
83
- if args.tri_mesh:
84
- positions, tri_vidx = gen_trimesh(res=vec2i(args.resolution))
85
- geo = Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
86
- else:
87
- geo = Grid2D(res=vec2i(args.resolution))
88
-
89
- # Domain and function spaces
90
- domain = Cells(geometry=geo)
91
- scalar_space = make_polynomial_space(geo, degree=args.degree)
92
-
93
- # Right-hand-side (forcing term)
94
- test = make_test(space=scalar_space, domain=domain)
95
- rhs = integrate(linear_form, fields={"v": test})
96
-
97
- # Diffusion form
98
- trial = make_trial(space=scalar_space, domain=domain)
99
- matrix = integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": args.viscosity})
100
-
101
- # Boundary conditions on Y sides
102
- # Use nodal integration so that boundary conditions are specified on each node independently
103
- boundary = BoundarySides(geo)
104
- bd_test = make_test(space=scalar_space, domain=boundary)
105
- bd_trial = make_trial(space=scalar_space, domain=boundary)
106
-
107
- bd_matrix = integrate(y_boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
108
- bd_rhs = integrate(y_boundary_value_form, fields={"v": bd_test}, values={"val": args.boundary_value}, nodal=True)
109
-
110
- # Assemble linear system
111
- if args.boundary_compliance == 0.0:
112
- # Hard BC: project linear system
113
- project_linear_system(matrix, rhs, bd_matrix, bd_rhs)
114
- else:
115
- # Weak BC: add toegether diffusion and boundary condition matrices
116
- boundary_strength = 1.0 / args.boundary_compliance
117
- bsr_axpy(x=bd_matrix, y=matrix, alpha=boundary_strength, beta=1)
118
- array_axpy(x=bd_rhs, y=rhs, alpha=boundary_strength, beta=1)
119
-
120
- # Solve linear system using Conjugate Gradient
121
- x = wp.zeros_like(rhs)
122
- bsr_cg(matrix, b=rhs, x=x)
123
-
124
- # Assign system result to a discrete field,
125
- scalar_field = scalar_space.make_field()
126
- scalar_field.dof_values = x
127
-
128
- # Visualize it with matplotlib
129
- plot_surface(scalar_field)
130
- plt.show()
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 numpy as np
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
- from plot_utils import plot_3d_scatter
24
- from bsr_utils import bsr_cg
25
- from mesh_utils import gen_tetmesh
26
-
27
- from example_diffusion import diffusion_form, linear_form
28
-
29
- import matplotlib.pyplot as plt
30
-
31
-
32
- @integrand
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
- if __name__ == "__main__":
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("--tet_mesh", action="store_true", help="Use a tetrahedral mesh")
54
- args = parser.parse_args()
55
-
56
- res = vec3i(args.resolution, args.resolution // 2, args.resolution * 2)
57
-
58
- if args.tet_mesh:
59
- pos, tet_vtx_indices = gen_tetmesh(
60
- res=res,
61
- bounds_lo=wp.vec3(0.0, 0.0, 0.0),
62
- bounds_hi=wp.vec3(1.0, 0.5, 2.0),
63
- )
64
- geo = Tetmesh(tet_vtx_indices, pos)
65
- else:
66
- geo = Grid3D(
67
- res=res,
68
- bounds_lo=wp.vec3(0.0, 0.0, 0.0),
69
- bounds_hi=wp.vec3(1.0, 0.5, 2.0),
70
- )
71
-
72
- # Domain and function spaces
73
- domain = Cells(geometry=geo)
74
- scalar_space = make_polynomial_space(geo, degree=args.degree)
75
-
76
- # Right-hand-side
77
- test = make_test(space=scalar_space, domain=domain)
78
- rhs = integrate(linear_form, fields={"v": test})
79
-
80
- # Weakly-imposed boundary conditions on Y sides
81
- with wp.ScopedTimer("Integrate"):
82
- boundary = BoundarySides(geo)
83
-
84
- bd_test = make_test(space=scalar_space, domain=boundary)
85
- bd_trial = make_trial(space=scalar_space, domain=boundary)
86
- bd_matrix = integrate(vert_boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
87
-
88
- # Diffusion form
89
- trial = make_trial(space=scalar_space, domain=domain)
90
- matrix = integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": args.viscosity})
91
-
92
- if args.boundary_compliance == 0.0:
93
- # Hard BC: project linear system
94
- bd_rhs = wp.zeros_like(rhs)
95
- project_linear_system(matrix, rhs, bd_matrix, bd_rhs)
96
- else:
97
- # Weak BC: add toegether diffusion and boundary condition matrices
98
- boundary_strength = 1.0 / args.boundary_compliance
99
- bsr_axpy(x=bd_matrix, y=matrix, alpha=100.0, beta=1)
100
-
101
- with wp.ScopedTimer("CG solve"):
102
- x = wp.zeros_like(rhs)
103
- bsr_cg(matrix, b=rhs, x=x)
104
-
105
- scalar_field = scalar_space.make_field()
106
- scalar_field.dof_values = x
107
- plot_3d_scatter(scalar_field)
108
-
109
- plt.show()
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()