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
@@ -9,202 +9,195 @@ with upwind transport and Symmetric Interior Penalty
9
9
  import argparse
10
10
 
11
11
  import warp as wp
12
-
13
- from warp.fem.types import *
14
- from warp.fem.geometry import Grid2D, Trimesh2D
15
- from warp.fem.field import make_test, make_trial
16
- from warp.fem.space import make_polynomial_space
17
- from warp.fem.quadrature import RegularQuadrature
18
- from warp.fem.domain import Cells, Sides
19
- from warp.fem.integrate import integrate, interpolate
20
- from warp.fem.polynomial import Polynomial
21
- from warp.fem.operator import (
22
- grad,
23
- integrand,
24
- jump,
25
- average,
26
- normal,
27
- grad_average,
28
- measure_ratio,
29
- degree,
30
- )
12
+ import warp.fem as fem
31
13
 
32
14
  from warp.sparse import bsr_axpy
33
15
 
34
- from bsr_utils import bsr_to_scipy
35
- from plot_utils import plot_surface
36
- from mesh_utils import gen_trimesh
37
-
38
- from example_convection_diffusion import (
39
- initial_condition,
40
- velocity,
41
- inertia_form,
42
- diffusion_form,
43
- )
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_to_scipy
20
+ from .mesh_utils import gen_trimesh, gen_quadmesh
21
+ from .plot_utils import Plot
22
+ from .example_convection_diffusion import (
23
+ initial_condition,
24
+ velocity,
25
+ inertia_form,
26
+ diffusion_form,
27
+ )
28
+ except ImportError:
29
+ from bsr_utils import bsr_to_scipy
30
+ from mesh_utils import gen_trimesh, gen_quadmesh
31
+ from plot_utils import Plot
32
+ from example_convection_diffusion import (
33
+ initial_condition,
34
+ velocity,
35
+ inertia_form,
36
+ diffusion_form,
37
+ )
44
38
 
39
+ # Non-SPD system, solve using scipy
45
40
  from scipy.sparse.linalg import factorized
46
41
 
47
- import matplotlib.pyplot as plt
48
- import matplotlib.animation as animation
49
-
50
42
 
51
43
  # Standard transport term, on cells' interior
52
- @integrand
53
- def transport_form(s: Sample, domain: Domain, phi: Field, psi: Field, ang_vel: float):
44
+ @fem.integrand
45
+ def transport_form(s: fem.Sample, domain: fem.Domain, phi: fem.Field, psi: fem.Field, ang_vel: float):
54
46
  pos = domain(s)
55
47
  vel = velocity(pos, ang_vel)
56
48
 
57
- return psi(s) * wp.dot(grad(phi, s), vel)
49
+ return psi(s) * wp.dot(fem.grad(phi, s), vel)
58
50
 
59
51
 
60
52
  # Upwind flux, on cell sides
61
- @integrand
62
- def upwind_transport_form(s: Sample, domain: Domain, phi: Field, psi: Field, ang_vel: float):
53
+ @fem.integrand
54
+ def upwind_transport_form(s: fem.Sample, domain: fem.Domain, phi: fem.Field, psi: fem.Field, ang_vel: float):
63
55
  pos = domain(s)
64
56
  vel = velocity(pos, ang_vel)
65
- vel_n = wp.dot(vel, normal(domain, s))
57
+ vel_n = wp.dot(vel, fem.normal(domain, s))
66
58
 
67
- return jump(phi, s) * (-average(psi, s) * vel_n + 0.5 * jump(psi, s) * wp.abs(vel_n))
59
+ return fem.jump(phi, s) * (-fem.average(psi, s) * vel_n + 0.5 * fem.jump(psi, s) * wp.abs(vel_n))
68
60
 
69
61
 
70
62
  # Symmetric-Interior-Penalty diffusion term (See Pietro Ern 2012)
71
- @integrand
63
+ @fem.integrand
72
64
  def sip_diffusion_form(
73
- s: Sample,
74
- domain: Domain,
75
- psi: Field,
76
- phi: Field,
65
+ s: fem.Sample,
66
+ domain: fem.Domain,
67
+ psi: fem.Field,
68
+ phi: fem.Field,
77
69
  ):
78
- nor = normal(domain, s)
79
- penalty = measure_ratio(domain, s) * float(degree(psi) * degree(phi))
70
+ nor = fem.normal(domain, s)
71
+ penalty = fem.measure_ratio(domain, s) * float(fem.degree(psi) * fem.degree(phi))
80
72
 
81
- return penalty * jump(phi, s) * jump(psi, s) - (
82
- wp.dot(grad_average(phi, s), nor) * jump(psi, s) + wp.dot(grad_average(psi, s), nor) * jump(phi, s)
73
+ return penalty * fem.jump(phi, s) * fem.jump(psi, s) - (
74
+ wp.dot(fem.grad_average(phi, s), nor) * fem.jump(psi, s)
75
+ + wp.dot(fem.grad_average(psi, s), nor) * fem.jump(phi, s)
83
76
  )
84
77
 
85
78
 
86
- @integrand
87
- def identity(s: Sample, phi: Field):
88
- return phi(s)
89
-
90
-
91
- if __name__ == "__main__":
92
- wp.init()
93
- wp.set_module_options({"enable_backward": False})
94
-
79
+ class Example:
95
80
  parser = argparse.ArgumentParser()
96
81
  parser.add_argument("--resolution", type=int, default=50)
97
82
  parser.add_argument("--degree", type=int, default=2)
98
- parser.add_argument("--n_frames", type=int, default=100)
83
+ parser.add_argument("--num_frames", type=int, default=100)
99
84
  parser.add_argument("--viscosity", type=float, default=0.001)
100
85
  parser.add_argument("--ang_vel", type=float, default=1.0)
101
- parser.add_argument("--tri_mesh", action="store_true", help="Use a triangular mesh")
102
- args = parser.parse_args()
103
-
104
- res = args.resolution
105
- dt = 1.0 / (args.ang_vel * res)
106
-
107
- if args.tri_mesh:
108
- positions, tri_vidx = gen_trimesh(res=vec2i(res))
109
- geo = Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
110
- else:
111
- geo = Grid2D(res=vec2i(res))
112
-
113
- domain = Cells(geometry=geo)
114
- sides = Sides(geo)
115
- quadrature = RegularQuadrature(domain=domain, order=2 * args.degree)
116
- scalar_space = make_polynomial_space(
117
- geo,
118
- discontinuous=True,
119
- degree=args.degree,
120
- family=Polynomial.GAUSS_LEGENDRE,
121
- )
86
+ parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
87
+
88
+ def __init__(self, stage=None, quiet=False, args=None, **kwargs):
89
+ if args is None:
90
+ # Read args from kwargs, add default arg values from parser
91
+ args = argparse.Namespace(**kwargs)
92
+ args = Example.parser.parse_args(args=[], namespace=args)
93
+ self._args = args
94
+ self._quiet = quiet
95
+
96
+ res = args.resolution
97
+ self.sim_dt = 1.0 / (args.ang_vel * res)
98
+ self.current_frame = 0
99
+
100
+ if args.mesh == "tri":
101
+ positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
102
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
103
+ elif args.mesh == "quad":
104
+ positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
105
+ geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
106
+ else:
107
+ geo = fem.Grid2D(res=wp.vec2i(args.resolution))
108
+
109
+ domain = fem.Cells(geometry=geo)
110
+ sides = fem.Sides(geo)
111
+ scalar_space = fem.make_polynomial_space(
112
+ geo,
113
+ discontinuous=True,
114
+ degree=args.degree,
115
+ family=fem.Polynomial.GAUSS_LEGENDRE,
116
+ )
122
117
 
123
- # Right-hand-side
124
- phi0 = scalar_space.make_field()
125
- interpolate(initial_condition, dest=phi0)
118
+ # Assemble transport, diffusion and inertia matrices
126
119
 
127
- test = make_test(space=scalar_space, domain=domain)
128
- trial = make_trial(space=scalar_space, domain=domain)
120
+ self._test = fem.make_test(space=scalar_space, domain=domain)
121
+ trial = fem.make_trial(space=scalar_space, domain=domain)
129
122
 
130
- side_test = make_test(space=scalar_space, domain=sides)
131
- side_trial = make_trial(space=scalar_space, domain=sides)
123
+ matrix_inertia = fem.integrate(
124
+ inertia_form,
125
+ fields={"phi": trial, "psi": self._test},
126
+ values={"dt": self.sim_dt},
127
+ )
132
128
 
133
- matrix_inertia = integrate(
134
- inertia_form,
135
- quadrature=quadrature,
136
- fields={"phi": trial, "psi": test},
137
- values={"dt": dt},
138
- )
129
+ matrix_transport = fem.integrate(
130
+ transport_form,
131
+ fields={"phi": trial, "psi": self._test},
132
+ values={"ang_vel": args.ang_vel},
133
+ )
139
134
 
140
- matrix_transport = integrate(
141
- transport_form,
142
- fields={"phi": trial, "psi": test},
143
- values={"ang_vel": args.ang_vel},
144
- )
135
+ side_test = fem.make_test(space=scalar_space, domain=sides)
136
+ side_trial = fem.make_trial(space=scalar_space, domain=sides)
145
137
 
146
- bsr_axpy(
147
- integrate(
148
- upwind_transport_form,
149
- fields={"phi": side_trial, "psi": side_test},
150
- values={"ang_vel": args.ang_vel},
151
- ),
152
- y=matrix_transport,
153
- )
138
+ bsr_axpy(
139
+ fem.integrate(
140
+ upwind_transport_form,
141
+ fields={"phi": side_trial, "psi": side_test},
142
+ values={"ang_vel": args.ang_vel},
143
+ ),
144
+ y=matrix_transport,
145
+ )
154
146
 
155
- matrix_diffusion = integrate(
156
- diffusion_form,
157
- fields={"u": trial, "v": test},
158
- )
159
- bsr_axpy(
160
- integrate(
161
- sip_diffusion_form,
162
- fields={"phi": side_trial, "psi": side_test},
163
- ),
164
- y=matrix_diffusion,
165
- )
147
+ matrix_diffusion = fem.integrate(
148
+ diffusion_form,
149
+ fields={"u": trial, "v": self._test},
150
+ )
151
+ bsr_axpy(
152
+ fem.integrate(
153
+ sip_diffusion_form,
154
+ fields={"phi": side_trial, "psi": side_test},
155
+ ),
156
+ y=matrix_diffusion,
157
+ )
158
+
159
+ self._matrix = matrix_inertia
160
+ bsr_axpy(x=matrix_transport, y=self._matrix)
161
+ bsr_axpy(x=matrix_diffusion, y=self._matrix, alpha=args.viscosity)
162
+
163
+ # Compute LU factorization of system matrix
164
+ self._solve_lu = factorized(bsr_to_scipy(self._matrix))
165
+
166
+ # Initial condition
167
+ self._phi_field = scalar_space.make_field()
168
+ fem.interpolate(initial_condition, dest=self._phi_field)
169
+
170
+ self.renderer = Plot(stage)
171
+ self.renderer.add_surface("phi", self._phi_field)
166
172
 
167
- matrix = matrix_inertia
168
- bsr_axpy(x=matrix_transport, y=matrix)
169
- bsr_axpy(x=matrix_diffusion, y=matrix, alpha=args.viscosity)
170
173
 
171
- matrix_solve = factorized(bsr_to_scipy(matrix))
174
+ def update(self):
175
+ self.current_frame += 1
172
176
 
173
- results = [phi0.dof_values.numpy()]
174
- phik = phi0
175
- for k in range(args.n_frames):
176
- rhs = integrate(
177
+ rhs = fem.integrate(
177
178
  inertia_form,
178
- quadrature=quadrature,
179
- fields={"phi": phik, "psi": test},
180
- values={"dt": dt},
179
+ fields={"phi": self._phi_field, "psi": self._test},
180
+ values={"dt": self.sim_dt},
181
181
  )
182
182
 
183
- # Solve using Scipy
184
- x = matrix_solve(rhs.numpy().flatten())
183
+ self._phi_field.dof_values = self._solve_lu(rhs.numpy())
185
184
 
186
- phik.dof_values = x
187
- results.append(x)
185
+ def render(self):
186
+ self.renderer.begin_frame(time = self.current_frame * self.sim_dt)
187
+ self.renderer.add_surface("phi", self._phi_field)
188
+ self.renderer.end_frame()
188
189
 
189
- colormesh = plot_surface(phi0)
190
- ax = colormesh.axes
191
190
 
192
- # Convert to continuous for visualization
193
- viz_space = make_polynomial_space(geo, degree=args.degree)
194
- phi_viz = viz_space.make_field()
191
+ if __name__ == "__main__":
192
+ wp.init()
193
+ wp.set_module_options({"enable_backward": False})
195
194
 
196
- def animate(i):
197
- ax.clear()
198
- phik.dof_values = results[i]
199
- interpolate(identity, fields={"phi": phik}, dest=phi_viz)
195
+ args = Example.parser.parse_args()
200
196
 
201
- return plot_surface(phi_viz, axes=ax)
197
+ example = Example(args=args)
198
+ for k in range(args.num_frames):
199
+ print(f"Frame {k}:")
200
+ example.update()
201
+ example.render()
202
202
 
203
- anim = animation.FuncAnimation(
204
- ax.figure,
205
- animate,
206
- interval=30,
207
- blit=False,
208
- frames=len(results),
209
- )
210
- plt.show()
203
+ example.renderer.plot()
@@ -9,174 +9,179 @@ This example simulates a convection-diffusion PDE using FVM with upwind transpor
9
9
  import argparse
10
10
 
11
11
  import warp as wp
12
-
13
- from warp.fem.types import *
14
- from warp.fem.geometry import Grid2D, Trimesh2D
15
- from warp.fem.field import make_test, make_trial
16
- from warp.fem.space import make_polynomial_space
17
- from warp.fem.quadrature import RegularQuadrature
18
- from warp.fem.domain import Cells, Sides
19
- from warp.fem.integrate import integrate, interpolate
20
- from warp.fem.operator import integrand, jump, average, normal
12
+ import warp.fem as fem
21
13
 
22
14
  from warp.sparse import bsr_mm, bsr_axpy, bsr_transposed
23
15
 
24
- from bsr_utils import bsr_to_scipy, invert_diagonal_bsr_mass_matrix
25
- from plot_utils import plot_surface
26
- from mesh_utils import gen_trimesh
27
16
 
28
- from example_convection_diffusion import initial_condition, velocity, inertia_form
17
+ # Import example utilities
18
+ # Make sure that works both when imported as module and run as standalone file
19
+ try:
20
+ from .bsr_utils import bsr_to_scipy, invert_diagonal_bsr_mass_matrix
21
+ from .plot_utils import Plot
22
+ from .mesh_utils import gen_trimesh, gen_quadmesh
23
+ from .example_convection_diffusion import initial_condition, velocity, inertia_form
24
+ except ImportError:
25
+ from bsr_utils import bsr_to_scipy, invert_diagonal_bsr_mass_matrix
26
+ from plot_utils import Plot
27
+ from mesh_utils import gen_trimesh, gen_quadmesh
28
+ from example_convection_diffusion import initial_condition, velocity, inertia_form
29
29
 
30
30
  from scipy.sparse.linalg import factorized
31
31
 
32
- import matplotlib.pyplot as plt
33
- import matplotlib.animation as animation
34
-
35
32
 
36
- @integrand
33
+ @fem.integrand
37
34
  def vel_mass_form(
38
- s: Sample,
39
- u: Field,
40
- v: Field,
35
+ s: fem.Sample,
36
+ u: fem.Field,
37
+ v: fem.Field,
41
38
  ):
42
39
  return wp.dot(v(s), u(s))
43
40
 
44
41
 
45
- @integrand
42
+ @fem.integrand
46
43
  def half_diffusion_form(
47
- s: Sample,
48
- domain: Domain,
49
- psi: Field,
50
- u: Field,
44
+ s: fem.Sample,
45
+ domain: fem.Domain,
46
+ psi: fem.Field,
47
+ u: fem.Field,
51
48
  ):
52
- return jump(psi, s) * wp.dot(average(u, s), normal(domain, s))
49
+ return fem.jump(psi, s) * wp.dot(fem.average(u, s), fem.normal(domain, s))
53
50
 
54
51
 
55
- @integrand
56
- def upwind_transport_form(s: Sample, domain: Domain, phi: Field, psi: Field, ang_vel: float):
52
+ @fem.integrand
53
+ def upwind_transport_form(s: fem.Sample, domain: fem.Domain, phi: fem.Field, psi: fem.Field, ang_vel: float):
57
54
  pos = domain(s)
58
55
 
59
56
  vel = velocity(pos, ang_vel)
60
57
 
61
- vel_n = wp.dot(vel, normal(domain, s))
58
+ vel_n = wp.dot(vel, fem.normal(domain, s))
62
59
 
63
- return jump(psi, s) * (average(phi, s) * vel_n + 0.5 * jump(phi, s) * wp.abs(vel_n))
60
+ return fem.jump(psi, s) * (fem.average(phi, s) * vel_n + 0.5 * fem.jump(phi, s) * wp.abs(vel_n))
64
61
 
65
62
 
66
- if __name__ == "__main__":
67
- wp.init()
68
- wp.set_module_options({"enable_backward": False})
69
-
63
+ class Example:
70
64
  parser = argparse.ArgumentParser()
71
65
  parser.add_argument("--resolution", type=int, default=50)
72
- parser.add_argument("--n_frames", type=int, default=250)
66
+ parser.add_argument("--num_frames", type=int, default=250)
73
67
  parser.add_argument("--viscosity", type=float, default=0.001)
74
68
  parser.add_argument("--ang_vel", type=float, default=1.0)
75
- parser.add_argument("--tri_mesh", action="store_true", help="Use a triangular mesh")
76
-
77
- args = parser.parse_args()
78
-
79
- res = args.resolution
80
- dt = 1.0 / (args.ang_vel * res)
81
-
82
- if args.tri_mesh:
83
- positions, tri_vidx = gen_trimesh(res=vec2i(res))
84
- geo = Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
85
- else:
86
- geo = Grid2D(res=vec2i(res))
87
-
88
- domain = Cells(geometry=geo)
89
- sides = Sides(geo)
90
- quadrature = RegularQuadrature(domain=domain, order=2)
91
- scalar_space = make_polynomial_space(geo, degree=0)
92
-
93
- # Initial condition
94
- phi0 = scalar_space.make_field()
95
- interpolate(initial_condition, dest=phi0)
96
-
97
- # Inertia matrix
98
- test = make_test(space=scalar_space, domain=domain)
99
- trial = make_trial(space=scalar_space, domain=domain)
100
- matrix_inertia = integrate(
101
- inertia_form,
102
- quadrature=quadrature,
103
- fields={"phi": trial, "psi": test},
104
- values={"dt": dt},
105
- )
106
-
107
- # Upwind transport term
108
- side_test = make_test(space=scalar_space, domain=sides)
109
- side_trial = make_trial(space=scalar_space, domain=sides)
110
- matrix_transport = integrate(
111
- upwind_transport_form,
112
- fields={"phi": side_trial, "psi": side_test},
113
- values={"ang_vel": args.ang_vel},
114
- )
115
-
116
- # Diffusion bilinear form
117
- # Since we have piecewise constant element, we cannot use the classical diffusion form
118
- # Instead we assemble the matrix B M^-1 B^T, with B associated to the form psi div(u)
119
- # and the diagonal matrix M to the velocity mass form u.v
120
-
121
- velocity_space = make_polynomial_space(geo, degree=0, dtype=wp.vec2)
122
- side_trial_vel = make_trial(space=velocity_space, domain=sides)
123
- matrix_half_diffusion = integrate(
124
- half_diffusion_form,
125
- fields={"psi": side_test, "u": side_trial_vel},
126
- )
127
-
128
- # Diagonal velocity mass matrix
129
- test_vel = make_test(space=velocity_space, domain=domain)
130
- trial_vel = make_trial(space=velocity_space, domain=domain)
131
- inv_vel_mass_matrix = integrate(vel_mass_form, domain=domain, fields={"u": trial_vel, "v": test_vel}, nodal=True)
132
- invert_diagonal_bsr_mass_matrix(inv_vel_mass_matrix)
133
-
134
- # Assemble system matrix
135
-
136
- matrix = matrix_inertia
137
- # matrix += matrix_transport
138
- bsr_axpy(x=matrix_transport, y=matrix)
139
- # matrix += nu * B M^-1 B^T
140
- bsr_mm(
141
- x=bsr_mm(matrix_half_diffusion, inv_vel_mass_matrix),
142
- y=bsr_transposed(matrix_half_diffusion),
143
- z=matrix,
144
- alpha=args.viscosity,
145
- beta=1.0,
146
- )
147
-
148
- matrix_solve = factorized(bsr_to_scipy(matrix))
149
-
150
- results = [phi0.dof_values.numpy()]
151
- phik = phi0
152
- for k in range(args.n_frames):
153
- # right-hand-side -- standard inertia
154
- rhs = integrate(
69
+ parser.add_argument("--mesh", choices=("grid", "tri", "quad"), default="grid", help="Mesh type")
70
+
71
+ def __init__(self, stage=None, quiet=False, args=None, **kwargs):
72
+ if args is None:
73
+ # Read args from kwargs, add default arg values from parser
74
+ args = argparse.Namespace(**kwargs)
75
+ args = Example.parser.parse_args(args=[], namespace=args)
76
+ self._args = args
77
+ self._quiet = quiet
78
+
79
+ res = args.resolution
80
+ self.sim_dt = 1.0 / (args.ang_vel * res)
81
+ self.current_frame = 0
82
+
83
+ if args.mesh == "tri":
84
+ positions, tri_vidx = gen_trimesh(res=wp.vec2i(args.resolution))
85
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
86
+ elif args.mesh == "quad":
87
+ positions, quad_vidx = gen_quadmesh(res=wp.vec2i(args.resolution))
88
+ geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
89
+ else:
90
+ geo = fem.Grid2D(res=wp.vec2i(args.resolution))
91
+
92
+ domain = fem.Cells(geometry=geo)
93
+ sides = fem.Sides(geo)
94
+ scalar_space = fem.make_polynomial_space(geo, degree=0)
95
+
96
+ # Inertia matrix
97
+ self._test = fem.make_test(space=scalar_space, domain=domain)
98
+ trial = fem.make_trial(space=scalar_space, domain=domain)
99
+ matrix_inertia = fem.integrate(
100
+ inertia_form,
101
+ fields={"phi": trial, "psi": self._test},
102
+ values={"dt": self.sim_dt},
103
+ )
104
+
105
+ # Upwind transport term
106
+ side_test = fem.make_test(space=scalar_space, domain=sides)
107
+ side_trial = fem.make_trial(space=scalar_space, domain=sides)
108
+ matrix_transport = fem.integrate(
109
+ upwind_transport_form,
110
+ fields={"phi": side_trial, "psi": side_test},
111
+ values={"ang_vel": args.ang_vel},
112
+ )
113
+
114
+ # Diffusion bilinear form
115
+ # Since we have piecewise constant element, we cannot use the classical diffusion form
116
+ # Instead we assemble the matrix B M^-1 B^T, with B associated to the form psi div(u)
117
+ # and the diagonal matrix M to the velocity mass form u.v
118
+
119
+ velocity_space = fem.make_polynomial_space(geo, degree=0, dtype=wp.vec2)
120
+ side_trial_vel = fem.make_trial(space=velocity_space, domain=sides)
121
+ matrix_half_diffusion = fem.integrate(
122
+ half_diffusion_form,
123
+ fields={"psi": side_test, "u": side_trial_vel},
124
+ )
125
+
126
+ # Diagonal velocity mass matrix
127
+ test_vel = fem.make_test(space=velocity_space, domain=domain)
128
+ trial_vel = fem.make_trial(space=velocity_space, domain=domain)
129
+ inv_vel_mass_matrix = fem.integrate(
130
+ vel_mass_form, domain=domain, fields={"u": trial_vel, "v": test_vel}, nodal=True
131
+ )
132
+ invert_diagonal_bsr_mass_matrix(inv_vel_mass_matrix)
133
+
134
+ # Assemble system matrix
135
+
136
+ matrix = matrix_inertia
137
+ # matrix += matrix_transport
138
+ bsr_axpy(x=matrix_transport, y=matrix)
139
+ # matrix += nu * B M^-1 B^T
140
+ bsr_mm(
141
+ x=bsr_mm(matrix_half_diffusion, inv_vel_mass_matrix),
142
+ y=bsr_transposed(matrix_half_diffusion),
143
+ z=matrix,
144
+ alpha=args.viscosity,
145
+ beta=1.0,
146
+ )
147
+
148
+ # Compute LU factorization of system matrix
149
+ self._solve_lu = factorized(bsr_to_scipy(matrix))
150
+
151
+ # Initial condition
152
+ self._phi_field = scalar_space.make_field()
153
+ fem.interpolate(initial_condition, dest=self._phi_field)
154
+
155
+ self.renderer = Plot(stage)
156
+ self.renderer.add_surface("phi", self._phi_field)
157
+
158
+ def update(self):
159
+ self.current_frame += 1
160
+
161
+ rhs = fem.integrate(
155
162
  inertia_form,
156
- quadrature=quadrature,
157
- fields={"phi": phik, "psi": test},
158
- values={"dt": dt},
163
+ fields={"phi": self._phi_field, "psi": self._test},
164
+ values={"dt": self.sim_dt},
159
165
  )
160
166
 
161
- # Solve using Scipy
162
- x = matrix_solve(rhs.numpy().flatten())
167
+ self._phi_field.dof_values = self._solve_lu(rhs.numpy())
168
+
169
+ def render(self):
170
+ self.renderer.begin_frame(time = self.current_frame * self.sim_dt)
171
+ self.renderer.add_surface("phi", self._phi_field)
172
+ self.renderer.end_frame()
173
+
163
174
 
164
- phik.dof_values = x
165
- results.append(x)
175
+ if __name__ == "__main__":
176
+ wp.init()
177
+ wp.set_module_options({"enable_backward": False})
166
178
 
167
- colormesh = plot_surface(phi0)
168
- ax = colormesh.axes
179
+ args = Example.parser.parse_args()
169
180
 
170
- def animate(i):
171
- ax.clear()
172
- phik.dof_values = results[i]
173
- return plot_surface(phik, axes=ax)
181
+ example = Example(args=args)
182
+ for k in range(args.num_frames):
183
+ print(f"Frame {k}:")
184
+ example.update()
185
+ example.render()
174
186
 
175
- anim = animation.FuncAnimation(
176
- ax.figure,
177
- animate,
178
- interval=30,
179
- blit=False,
180
- frames=len(results),
181
- )
182
- plt.show()
187
+ example.renderer.plot()