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
@@ -1,487 +1,147 @@
1
1
  import warp as wp
2
2
  import numpy as np
3
3
 
4
-
5
- from warp.fem.types import ElementIndex, Coords, OUTSIDE
6
- from warp.fem.types import vec2i
7
- from warp.fem.polynomial import Polynomial, lagrange_scales, quadrature_1d, is_closed
4
+ from warp.fem.types import ElementIndex, Coords
5
+ from warp.fem.polynomial import Polynomial, is_closed
8
6
  from warp.fem.geometry import Grid2D
7
+ from warp.fem import cache
9
8
 
10
- from .dof_mapper import DofMapper
11
- from .nodal_function_space import NodalFunctionSpace, NodalFunctionSpaceTrace
12
-
13
-
14
- class Grid2DFunctionSpace(NodalFunctionSpace):
15
- DIMENSION = wp.constant(2)
16
-
17
- @wp.struct
18
- class SpaceArg:
19
- geo_arg: Grid2D.SideArg
20
- inv_cell_size: wp.vec2
21
-
22
- def __init__(self, grid: Grid2D, dtype: type = float, dof_mapper: DofMapper = None):
23
- super().__init__(dtype, dof_mapper)
24
- self._grid = grid
25
-
26
- @property
27
- def geometry(self) -> Grid2D:
28
- return self._grid
29
-
30
- def space_arg_value(self, device):
31
- arg = self.SpaceArg()
32
- arg.geo_arg = self.geometry.side_arg_value(device)
33
- arg.inv_cell_size = wp.vec2(
34
- 1.0 / self.geometry.cell_size[0],
35
- 1.0 / self.geometry.cell_size[1],
36
- )
37
-
38
- return arg
9
+ from .topology import SpaceTopology, DiscontinuousSpaceTopologyMixin, forward_base_topology
10
+ from .basis_space import ShapeBasisSpace, TraceBasisSpace
39
11
 
40
- class Trace(NodalFunctionSpaceTrace):
41
- def __init__(self, space: NodalFunctionSpace):
42
- super().__init__(space)
43
- self.ORDER = space.ORDER
12
+ from .shape import ShapeFunction, ConstantShapeFunction
13
+ from .shape import (
14
+ SquareBipolynomialShapeFunctions,
15
+ SquareSerendipityShapeFunctions,
16
+ SquareNonConformingPolynomialShapeFunctions,
17
+ )
44
18
 
45
- @wp.func
46
- def _inner_cell_index(args: SpaceArg, side_index: ElementIndex):
47
- return Grid2D.side_inner_cell_index(args.geo_arg, side_index)
48
19
 
49
- @wp.func
50
- def _outer_cell_index(args: SpaceArg, side_index: ElementIndex):
51
- return Grid2D.side_outer_cell_index(args.geo_arg, side_index)
52
-
53
- @wp.func
54
- def _inner_cell_coords(args: SpaceArg, side_index: ElementIndex, side_coords: Coords):
55
- side = Grid2D.get_side(args.geo_arg, side_index)
56
-
57
- if side.origin[0] == 0:
58
- inner_alt = 0.0
59
- else:
60
- inner_alt = 1.0
61
-
62
- coords = Grid2D._rotate(side.axis, wp.vec2(inner_alt, side_coords[0]))
63
- return Coords(coords[0], coords[1], 0.0)
64
-
65
- @wp.func
66
- def _outer_cell_coords(args: SpaceArg, side_index: ElementIndex, side_coords: Coords):
67
- side = Grid2D.get_side(args.geo_arg, side_index)
68
-
69
- alt_axis = Grid2D.ROTATION[side.axis, 0]
70
- if side.origin[0] == args.geo_arg.cell_arg.res[alt_axis]:
71
- outer_alt = 1.0
72
- else:
73
- outer_alt = 0.0
74
-
75
- coords = Grid2D._rotate(side.axis, wp.vec2(outer_alt, side_coords[0]))
76
- return Coords(coords[0], coords[1], 0.0)
77
-
78
- @wp.func
79
- def _cell_to_side_coords(
80
- args: SpaceArg,
81
- side_index: ElementIndex,
82
- element_index: ElementIndex,
83
- element_coords: Coords,
84
- ):
85
- side = Grid2D.get_side(args.geo_arg, side_index)
86
- cell = Grid2D.get_cell(args.geo_arg.cell_arg.res, element_index)
87
-
88
- if float(side.origin[0] - cell[side.axis]) == element_coords[side.axis]:
89
- long_axis = Grid2D.ROTATION[side.axis, 1]
90
- return Coords(element_coords[long_axis], 0.0, 0.0)
91
-
92
- return Coords(OUTSIDE)
20
+ class Grid2DSpaceTopology(SpaceTopology):
21
+ def __init__(self, grid: Grid2D, shape: ShapeFunction):
22
+ super().__init__(grid, shape.NODES_PER_ELEMENT)
23
+ self._shape = shape
93
24
 
94
25
  @wp.func
95
26
  def _vertex_coords(vidx_in_cell: int):
96
27
  x = vidx_in_cell // 2
97
28
  y = vidx_in_cell - 2 * x
98
- return vec2i(x, y)
29
+ return wp.vec2i(x, y)
99
30
 
100
31
  @wp.func
101
- def _vertex_coords_f(vidx_in_cell: int):
102
- x = vidx_in_cell // 2
103
- y = vidx_in_cell - 2 * x
104
- return wp.vec2(float(x), float(y))
105
-
106
- @wp.func
107
- def _vertex_index(args: SpaceArg, cell_index: ElementIndex, vidx_in_cell: int):
108
- res = args.geo_arg.cell_arg.res
32
+ def _vertex_index(cell_arg: Grid2D.CellArg, cell_index: ElementIndex, vidx_in_cell: int):
33
+ res = cell_arg.res
109
34
  x_stride = res[1] + 1
110
35
 
111
- corner = Grid2D.get_cell(res, cell_index) + Grid2DFunctionSpace._vertex_coords(vidx_in_cell)
36
+ corner = Grid2D.get_cell(res, cell_index) + Grid2DSpaceTopology._vertex_coords(vidx_in_cell)
112
37
  return Grid2D._from_2d_index(x_stride, corner)
113
38
 
114
39
 
115
- class GridPiecewiseConstantSpace(Grid2DFunctionSpace):
116
- ORDER = wp.constant(0)
117
- NODES_PER_ELEMENT = wp.constant(1)
40
+ class Grid2DDiscontinuousSpaceTopology(
41
+ DiscontinuousSpaceTopologyMixin,
42
+ Grid2DSpaceTopology,
43
+ ):
44
+ pass
118
45
 
119
- def __init__(self, grid: Grid2D, dtype: type = float, dof_mapper: DofMapper = None):
120
- super().__init__(grid, dtype, dof_mapper)
121
46
 
122
- self.element_outer_weight = self.element_inner_weight
123
- self.element_outer_weight_gradient = self.element_inner_weight_gradient
47
+ class Grid2DBasisSpace(ShapeBasisSpace):
48
+ def __init__(self, topology: Grid2DSpaceTopology, shape: ShapeFunction):
49
+ super().__init__(topology, shape)
124
50
 
125
- def node_count(self) -> int:
126
- return self._grid.cell_count()
51
+ self._grid: Grid2D = topology.geometry
52
+
53
+
54
+ class GridPiecewiseConstantBasis(Grid2DBasisSpace):
55
+ def __init__(self, grid: Grid2D):
56
+ shape = ConstantShapeFunction(grid.reference_cell(), space_dimension=2)
57
+ topology = Grid2DDiscontinuousSpaceTopology(grid, shape)
58
+ super().__init__(shape=shape, topology=topology)
127
59
 
128
- def node_positions(self):
60
+ if isinstance(grid, Grid2D):
61
+ self.node_grid = self._node_grid
62
+
63
+ def _node_grid(self):
129
64
  res = self._grid.res
130
65
 
131
66
  X = (np.arange(0, res[0], dtype=float) + 0.5) * self._grid.cell_size[0] + self._grid.origin[0]
132
67
  Y = (np.arange(0, res[1], dtype=float) + 0.5) * self._grid.cell_size[1] + self._grid.origin[1]
133
68
  return np.meshgrid(X, Y, indexing="ij")
134
69
 
135
- @wp.func
136
- def element_node_index(
137
- args: Grid2DFunctionSpace.SpaceArg,
138
- element_index: ElementIndex,
139
- node_index_in_elt: int,
140
- ):
141
- return element_index
142
-
143
- @wp.func
144
- def node_coords_in_element(
145
- args: Grid2DFunctionSpace.SpaceArg,
146
- element_index: ElementIndex,
147
- node_index_in_elt: int,
148
- ):
149
- if node_index_in_elt == 0:
150
- return Coords(0.5, 0.5, 0.0)
151
-
152
- return Coords(OUTSIDE)
153
-
154
- @wp.func
155
- def node_quadrature_weight(
156
- args: Grid2DFunctionSpace.SpaceArg,
157
- element_index: ElementIndex,
158
- node_index_in_elt: int,
159
- ):
160
- return 1.0
161
-
162
- @wp.func
163
- def element_inner_weight(
164
- args: Grid2DFunctionSpace.SpaceArg,
165
- element_index: ElementIndex,
166
- coords: Coords,
167
- node_index_in_elt: int,
168
- ):
169
- if node_index_in_elt == 0:
170
- return 1.0
171
- return 0.0
172
-
173
- @wp.func
174
- def element_inner_weight_gradient(
175
- args: Grid2DFunctionSpace.SpaceArg,
176
- element_index: ElementIndex,
177
- coords: Coords,
178
- node_index_in_elt: int,
179
- ):
180
- return wp.vec2(0.0)
181
-
182
- class Trace(Grid2DFunctionSpace.Trace):
183
- NODES_PER_ELEMENT = wp.constant(2)
184
- ORDER = wp.constant(0)
185
-
186
- def __init__(self, space: "GridPiecewiseConstantSpace"):
187
- super().__init__(space)
188
-
189
- self.element_node_index = self._make_element_node_index(space)
190
-
191
- self.element_inner_weight = self._make_element_inner_weight(space)
192
- self.element_inner_weight_gradient = self._make_element_inner_weight_gradient(space)
193
-
194
- self.element_outer_weight = self._make_element_outer_weight(space)
195
- self.element_outer_weight_gradient = self._make_element_outer_weight_gradient(space)
196
-
70
+ class Trace(TraceBasisSpace):
197
71
  @wp.func
198
- def node_coords_in_element(
199
- args: Grid2DFunctionSpace.SpaceArg,
72
+ def _node_coords_in_element(
73
+ side_arg: Grid2D.SideArg,
74
+ basis_arg: Grid2DBasisSpace.BasisArg,
200
75
  element_index: ElementIndex,
201
76
  node_index_in_element: int,
202
77
  ):
203
- if node_index_in_element == 0:
204
- return Coords(0.5, 0.0, 0.0)
205
- elif node_index_in_element == 1:
206
- return Coords(0.5, 0.0, 0.0)
78
+ return Coords(0.5, 0.0, 0.0)
207
79
 
208
- return Coords(OUTSIDE)
209
-
210
- @wp.func
211
- def node_quadrature_weight(
212
- args: Grid2DFunctionSpace.SpaceArg,
213
- element_index: ElementIndex,
214
- node_index_in_elt: int,
215
- ):
216
- return 1.0
80
+ def make_node_coords_in_element(self):
81
+ return self._node_coords_in_element
217
82
 
218
83
  def trace(self):
219
- return GridPiecewiseConstantSpace.Trace(self)
220
-
221
-
222
- class GridBipolynomialShapeFunctions:
223
- def __init__(self, degree: int, family: Polynomial):
224
- self.family = family
225
-
226
- self.ORDER = wp.constant(degree)
227
- self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 1))
228
- self.NODES_PER_SIDE = wp.constant(degree + 1)
229
-
230
- lobatto_coords, lobatto_weight = quadrature_1d(point_count=degree + 1, family=family)
231
- lagrange_scale = lagrange_scales(lobatto_coords)
232
-
233
- NodeVec = wp.types.vector(length=degree + 1, dtype=wp.float32)
234
- self.LOBATTO_COORDS = wp.constant(NodeVec(lobatto_coords))
235
- self.LOBATTO_WEIGHT = wp.constant(NodeVec(lobatto_weight))
236
- self.LAGRANGE_SCALE = wp.constant(NodeVec(lagrange_scale))
237
-
238
- @property
239
- def name(self) -> str:
240
- return f"{self.family}_{self.ORDER}"
241
-
242
- def make_node_coords_in_element(self):
243
- ORDER = self.ORDER
244
- LOBATTO_COORDS = self.LOBATTO_COORDS
245
-
246
- def node_coords_in_element(
247
- args: Grid2DFunctionSpace.SpaceArg,
248
- element_index: ElementIndex,
249
- node_index_in_elt: int,
250
- ):
251
- node_i = node_index_in_elt // (ORDER + 1)
252
- node_j = node_index_in_elt - (ORDER + 1) * node_i
253
- return Coords(LOBATTO_COORDS[node_i], LOBATTO_COORDS[node_j], 0.0)
254
-
255
- from warp.fem import cache
256
-
257
- return cache.get_func(node_coords_in_element, self.name)
258
-
259
- def make_node_quadrature_weight(self):
260
- ORDER = self.ORDER
261
- LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
262
-
263
- def node_quadrature_weight(
264
- args: Grid2DFunctionSpace.SpaceArg,
265
- element_index: ElementIndex,
266
- node_index_in_elt: int,
267
- ):
268
- node_i = node_index_in_elt // (ORDER + 1)
269
- node_j = node_index_in_elt - (ORDER + 1) * node_i
270
- return LOBATTO_WEIGHT[node_i] * LOBATTO_WEIGHT[node_j]
271
-
272
- def node_quadrature_weight_linear(
273
- args: Grid2DFunctionSpace.SpaceArg,
274
- element_index: ElementIndex,
275
- node_index_in_elt: int,
276
- ):
277
- return 0.25
278
-
279
- from warp.fem import cache
280
-
281
- if ORDER == 1:
282
- return cache.get_func(node_quadrature_weight_linear, self.name)
283
-
284
- return cache.get_func(node_quadrature_weight, self.name)
285
-
286
- def make_trace_node_quadrature_weight(self):
287
- ORDER = self.ORDER
288
- NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
289
- LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
290
-
291
- def trace_node_quadrature_weight(
292
- args: Grid2DFunctionSpace.SpaceArg,
293
- element_index: ElementIndex,
294
- node_index_in_elt: int,
295
- ):
296
- if node_index_in_elt >= NODES_PER_ELEMENT:
297
- node_index_in_cell = node_index_in_elt - NODES_PER_ELEMENT
298
- else:
299
- node_index_in_cell = node_index_in_elt
300
-
301
- # We're either on a side interior or at a vertex
302
- # I.e., either both indices are at extrema, or only one is
303
- # Pick the interior one if possible, if both are at extrema pick any one
304
- node_i = node_index_in_cell // (ORDER + 1)
305
- if node_i > 0 and node_i < ORDER:
306
- return LOBATTO_WEIGHT[node_i]
307
-
308
- node_j = node_index_in_cell - (ORDER + 1) * node_i
309
- return LOBATTO_WEIGHT[node_j]
310
-
311
- def trace_node_quadrature_weight_linear(
312
- args: Grid2DFunctionSpace.SpaceArg,
313
- element_index: ElementIndex,
314
- node_index_in_elt: int,
315
- ):
316
- return 0.5
317
-
318
- from warp.fem import cache
319
-
320
- if ORDER == 1:
321
- return cache.get_func(trace_node_quadrature_weight_linear, self.name)
322
-
323
- return cache.get_func(trace_node_quadrature_weight, self.name)
324
-
325
- def make_element_inner_weight(self):
326
- ORDER = self.ORDER
327
- NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
328
- LOBATTO_COORDS = self.LOBATTO_COORDS
329
- LAGRANGE_SCALE = self.LAGRANGE_SCALE
84
+ return GridPiecewiseConstantBasis.Trace(self)
330
85
 
331
- def element_inner_weight(
332
- args: Grid2DFunctionSpace.SpaceArg,
333
- element_index: ElementIndex,
334
- coords: Coords,
335
- node_index_in_elt: int,
336
- ):
337
- if node_index_in_elt < 0 or node_index_in_elt >= NODES_PER_ELEMENT:
338
- return 0.0
339
-
340
- node_i = node_index_in_elt // (ORDER + 1)
341
- node_j = node_index_in_elt - (ORDER + 1) * node_i
342
86
 
343
- w = float(1.0)
344
- for k in range(ORDER + 1):
345
- if k != node_i:
346
- w *= coords[0] - LOBATTO_COORDS[k]
347
- if k != node_j:
348
- w *= coords[1] - LOBATTO_COORDS[k]
87
+ class GridBipolynomialSpaceTopology(Grid2DSpaceTopology):
88
+ def __init__(self, grid: Grid2D, shape: SquareBipolynomialShapeFunctions):
89
+ super().__init__(grid, shape)
349
90
 
350
- w *= LAGRANGE_SCALE[node_i] * LAGRANGE_SCALE[node_j]
351
-
352
- return w
353
-
354
- def element_inner_weight_linear(
355
- args: Grid2DFunctionSpace.SpaceArg,
356
- element_index: ElementIndex,
357
- coords: Coords,
358
- node_index_in_elt: int,
359
- ):
360
- if node_index_in_elt < 0 or node_index_in_elt >= 4:
361
- return 0.0
362
-
363
- v = Grid2DFunctionSpace._vertex_coords_f(node_index_in_elt)
364
-
365
- wx = (1.0 - coords[0]) * (1.0 - v[0]) + v[0] * coords[0]
366
- wy = (1.0 - coords[1]) * (1.0 - v[1]) + v[1] * coords[1]
367
- return wx * wy
368
-
369
- from warp.fem import cache
370
-
371
- if ORDER == 1:
372
- return cache.get_func(element_inner_weight_linear, self.name)
91
+ self.element_node_index = self._make_element_node_index()
373
92
 
374
- return cache.get_func(element_inner_weight, self.name)
93
+ def node_count(self) -> int:
94
+ return (self.geometry.res[0] * self._shape.ORDER + 1) * (self.geometry.res[1] * self._shape.ORDER + 1)
375
95
 
376
- def make_element_inner_weight_gradient(self):
377
- ORDER = self.ORDER
378
- NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
379
- LOBATTO_COORDS = self.LOBATTO_COORDS
380
- LAGRANGE_SCALE = self.LAGRANGE_SCALE
96
+ def _make_element_node_index(self):
97
+ ORDER = self._shape.ORDER
381
98
 
382
- def element_inner_weight_gradient(
383
- args: Grid2DFunctionSpace.SpaceArg,
99
+ @cache.dynamic_func(suffix=self.name)
100
+ def element_node_index(
101
+ cell_arg: Grid2D.CellArg,
102
+ topo_arg: Grid2DSpaceTopology.TopologyArg,
384
103
  element_index: ElementIndex,
385
- coords: Coords,
386
104
  node_index_in_elt: int,
387
105
  ):
388
- if node_index_in_elt < 0 or node_index_in_elt >= NODES_PER_ELEMENT:
389
- return wp.vec2(0.0)
106
+ res = cell_arg.res
107
+ cell = Grid2D.get_cell(res, element_index)
390
108
 
391
109
  node_i = node_index_in_elt // (ORDER + 1)
392
110
  node_j = node_index_in_elt - (ORDER + 1) * node_i
393
111
 
394
- prefix_x = float(1.0)
395
- prefix_y = float(1.0)
396
- for k in range(ORDER + 1):
397
- if k != node_i:
398
- prefix_y *= coords[0] - LOBATTO_COORDS[k]
399
- if k != node_j:
400
- prefix_x *= coords[1] - LOBATTO_COORDS[k]
401
-
402
- grad_x = float(0.0)
403
- grad_y = float(0.0)
404
-
405
- for k in range(ORDER + 1):
406
- if k != node_i:
407
- delta_x = coords[0] - LOBATTO_COORDS[k]
408
- grad_x = grad_x * delta_x + prefix_x
409
- prefix_x *= delta_x
410
- if k != node_j:
411
- delta_y = coords[1] - LOBATTO_COORDS[k]
412
- grad_y = grad_y * delta_y + prefix_y
413
- prefix_y *= delta_y
414
-
415
- grad = (
416
- LAGRANGE_SCALE[node_i]
417
- * LAGRANGE_SCALE[node_j]
418
- * wp.vec2(grad_x * args.inv_cell_size[0], grad_y * args.inv_cell_size[1])
419
- )
420
-
421
- return grad
422
-
423
- def element_inner_weight_gradient_linear(
424
- args: Grid2DFunctionSpace.SpaceArg,
425
- element_index: ElementIndex,
426
- coords: Coords,
427
- node_index_in_elt: int,
428
- ):
429
- if node_index_in_elt < 0 or node_index_in_elt >= 4:
430
- return wp.vec2(0.0)
431
-
432
- v = Grid2DFunctionSpace._vertex_coords_f(node_index_in_elt)
433
-
434
- wx = (1.0 - coords[0]) * (1.0 - v[0]) + v[0] * coords[0]
435
- wy = (1.0 - coords[1]) * (1.0 - v[1]) + v[1] * coords[1]
436
-
437
- dx = (2.0 * v[0] - 1.0) * args.inv_cell_size[0]
438
- dy = (2.0 * v[1] - 1.0) * args.inv_cell_size[1]
439
-
440
- return wp.vec2(dx * wy, dy * wx)
112
+ node_x = ORDER * cell[0] + node_i
113
+ node_y = ORDER * cell[1] + node_j
441
114
 
442
- from warp.fem import cache
115
+ node_pitch = (res[1] * ORDER) + 1
116
+ node_index = node_pitch * node_x + node_y
443
117
 
444
- if ORDER == 1:
445
- return cache.get_func(element_inner_weight_gradient_linear, self.name)
118
+ return node_index
446
119
 
447
- return cache.get_func(element_inner_weight_gradient, self.name)
120
+ return element_node_index
448
121
 
449
122
 
450
- class GridBipolynomialSpace(Grid2DFunctionSpace):
123
+ class GridBipolynomialBasisSpace(Grid2DBasisSpace):
451
124
  def __init__(
452
125
  self,
453
126
  grid: Grid2D,
454
127
  degree: int,
455
- family: int,
456
- dtype: type = float,
457
- dof_mapper: DofMapper = None,
128
+ family: Polynomial,
458
129
  ):
459
- super().__init__(grid, dtype, dof_mapper)
460
-
461
130
  if family is None:
462
131
  family = Polynomial.LOBATTO_GAUSS_LEGENDRE
463
132
 
464
133
  if not is_closed(family):
465
- raise ValueError("A closed polynomial family is required to defined a continuous funciton space")
134
+ raise ValueError("A closed polynomial family is required to define a continuous function space")
466
135
 
467
- self._shape = GridBipolynomialShapeFunctions(degree, family=family)
136
+ shape = SquareBipolynomialShapeFunctions(degree, family=family)
137
+ topology = forward_base_topology(GridBipolynomialSpaceTopology, grid, shape)
468
138
 
469
- self.ORDER = self._shape.ORDER
470
- self.NODES_PER_ELEMENT = self._shape.NODES_PER_ELEMENT
471
-
472
- self.element_node_index = self._make_element_node_index()
473
- self.node_coords_in_element = self._shape.make_node_coords_in_element()
474
- self.node_quadrature_weight = self._shape.make_node_quadrature_weight()
475
- self.element_inner_weight = self._shape.make_element_inner_weight()
476
- self.element_inner_weight_gradient = self._shape.make_element_inner_weight_gradient()
139
+ super().__init__(topology, shape)
477
140
 
478
- self.element_outer_weight = self.element_inner_weight
479
- self.element_outer_weight_gradient = self.element_inner_weight_gradient
141
+ if isinstance(grid, Grid2D):
142
+ self.node_grid = self._node_grid
480
143
 
481
- def node_count(self) -> int:
482
- return (self._grid.res[0] * self.ORDER + 1) * (self._grid.res[1] * self.ORDER + 1)
483
-
484
- def node_positions(self):
144
+ def _node_grid(self):
485
145
  res = self._grid.res
486
146
 
487
147
  cell_coords = np.array(self._shape.LOBATTO_COORDS)[:-1]
@@ -500,115 +160,108 @@ class GridBipolynomialSpace(Grid2DFunctionSpace):
500
160
 
501
161
  return np.meshgrid(X, Y, indexing="ij")
502
162
 
163
+
164
+ class GridDGBipolynomialBasisSpace(Grid2DBasisSpace):
165
+ def __init__(
166
+ self,
167
+ grid: Grid2D,
168
+ degree: int,
169
+ family: Polynomial,
170
+ ):
171
+ if family is None:
172
+ family = Polynomial.LOBATTO_GAUSS_LEGENDRE
173
+
174
+ shape = SquareBipolynomialShapeFunctions(degree, family=family)
175
+ topology = Grid2DDiscontinuousSpaceTopology(grid, shape)
176
+
177
+ super().__init__(shape=shape, topology=topology)
178
+
179
+
180
+ class GridSerendipitySpaceTopology(Grid2DSpaceTopology):
181
+ def __init__(self, grid: Grid2D, shape: SquareSerendipityShapeFunctions):
182
+ super().__init__(grid, shape)
183
+
184
+ self.element_node_index = self._make_element_node_index()
185
+
186
+ TopologyArg = Grid2D.SideArg
187
+
188
+ def topo_arg_value(self, device):
189
+ return self.geometry.side_arg_value(device)
190
+
191
+ def node_count(self) -> int:
192
+ return self.geometry.vertex_count() + (self._shape.ORDER - 1) * self.geometry.side_count()
193
+
503
194
  def _make_element_node_index(self):
504
- ORDER = self.ORDER
195
+ ORDER = self._shape.ORDER
505
196
 
197
+ @cache.dynamic_func(suffix=self.name)
506
198
  def element_node_index(
507
- args: Grid2DFunctionSpace.SpaceArg,
199
+ cell_arg: Grid2D.CellArg,
200
+ topo_arg: Grid2D.SideArg,
508
201
  element_index: ElementIndex,
509
202
  node_index_in_elt: int,
510
203
  ):
511
- res = args.geo_arg.cell_arg.res
512
- cell = Grid2D.get_cell(res, element_index)
204
+ node_type, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
513
205
 
514
- node_i = node_index_in_elt // (ORDER + 1)
515
- node_j = node_index_in_elt - (ORDER + 1) * node_i
206
+ if node_type == SquareSerendipityShapeFunctions.VERTEX:
207
+ return Grid2DSpaceTopology._vertex_index(cell_arg, element_index, type_index)
516
208
 
517
- node_x = ORDER * cell[0] + node_i
518
- node_y = ORDER * cell[1] + node_j
209
+ side_offset, index_in_side = SquareSerendipityShapeFunctions.side_offset_and_index(type_index)
210
+ axis = 1 - (node_type - SquareSerendipityShapeFunctions.EDGE_X)
519
211
 
520
- node_pitch = (res[1] * ORDER) + 1
521
- node_index = node_pitch * node_x + node_y
212
+ cell = Grid2D.get_cell(cell_arg.res, element_index)
213
+ origin = wp.vec2i(cell[Grid2D.ROTATION[axis, 0]] + side_offset, cell[Grid2D.ROTATION[axis, 1]])
522
214
 
523
- return node_index
524
-
525
- from warp.fem import cache
526
-
527
- return cache.get_func(element_node_index, f"{self.name}_{ORDER}")
215
+ side = Grid2D.Side(axis, origin)
216
+ side_index = Grid2D.side_index(topo_arg, side)
528
217
 
529
- class Trace(Grid2DFunctionSpace.Trace):
530
- def __init__(self, space: "GridBipolynomialSpace"):
531
- super().__init__(space)
218
+ res = cell_arg.res
219
+ vertex_count = (res[0] + 1) * (res[1] + 1)
532
220
 
533
- self.element_node_index = self._make_element_node_index(space)
534
- self.node_coords_in_element = self._make_node_coords_in_element(space)
535
- self.node_quadrature_weight = space._shape.make_trace_node_quadrature_weight()
221
+ return vertex_count + (ORDER - 1) * side_index + index_in_side
536
222
 
537
- self.element_inner_weight = self._make_element_inner_weight(space)
538
- self.element_inner_weight_gradient = self._make_element_inner_weight_gradient(space)
539
-
540
- self.element_outer_weight = self._make_element_outer_weight(space)
541
- self.element_outer_weight_gradient = self._make_element_outer_weight_gradient(space)
542
-
543
- def trace(self):
544
- return GridBipolynomialSpace.Trace(self)
223
+ return element_node_index
545
224
 
546
225
 
547
- class GridDGBipolynomialSpace(Grid2DFunctionSpace):
226
+ class GridSerendipityBasisSpace(Grid2DBasisSpace):
548
227
  def __init__(
549
228
  self,
550
229
  grid: Grid2D,
551
230
  degree: int,
552
231
  family: Polynomial,
553
- dtype: type = float,
554
- dof_mapper: DofMapper = None,
555
232
  ):
556
- super().__init__(grid, dtype, dof_mapper)
557
-
558
233
  if family is None:
559
234
  family = Polynomial.LOBATTO_GAUSS_LEGENDRE
560
235
 
561
- self._shape = GridBipolynomialShapeFunctions(degree, family=family)
562
-
563
- self.ORDER = self._shape.ORDER
564
- self.NODES_PER_ELEMENT = self._shape.NODES_PER_ELEMENT
565
-
566
- self.element_node_index = self._make_element_node_index()
567
- self.node_coords_in_element = self._shape.make_node_coords_in_element()
568
- self.node_quadrature_weight = self._shape.make_node_quadrature_weight()
569
- self.element_inner_weight = self._shape.make_element_inner_weight()
570
- self.element_inner_weight_gradient = self._shape.make_element_inner_weight_gradient()
571
-
572
- self.element_outer_weight = self.element_inner_weight
573
- self.element_outer_weight_gradient = self.element_inner_weight_gradient
574
-
575
- def node_count(self) -> int:
576
- return self._grid.cell_count() * (self.ORDER + 1) ** 2
577
-
578
- def node_positions(self):
579
- res = self._grid.res
580
-
581
- cell_coords = np.array(self._shape.LOBATTO_COORDS)
582
-
583
- grid_coords_x = np.repeat(np.arange(0, res[0], dtype=float), len(cell_coords)) + np.tile(
584
- cell_coords, reps=res[0]
585
- )
586
- X = grid_coords_x * self._grid.cell_size[0] + self._grid.origin[0]
236
+ shape = SquareSerendipityShapeFunctions(degree, family=family)
237
+ topology = forward_base_topology(GridSerendipitySpaceTopology, grid, shape=shape)
587
238
 
588
- grid_coords_y = np.repeat(np.arange(0, res[1], dtype=float), len(cell_coords)) + np.tile(
589
- cell_coords, reps=res[1]
590
- )
591
- Y = grid_coords_y * self._grid.cell_size[1] + self._grid.origin[1]
239
+ super().__init__(topology=topology, shape=shape)
592
240
 
593
- return np.meshgrid(X, Y, indexing="ij")
594
241
 
595
- def _make_element_node_index(self):
596
- NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
242
+ class GridDGSerendipityBasisSpace(Grid2DBasisSpace):
243
+ def __init__(
244
+ self,
245
+ grid: Grid2D,
246
+ degree: int,
247
+ family: Polynomial,
248
+ ):
249
+ if family is None:
250
+ family = Polynomial.LOBATTO_GAUSS_LEGENDRE
597
251
 
598
- def element_node_index(
599
- args: Grid2DFunctionSpace.SpaceArg,
600
- element_index: ElementIndex,
601
- node_index_in_elt: int,
602
- ):
603
- return element_index * NODES_PER_ELEMENT + node_index_in_elt
252
+ shape = SquareSerendipityShapeFunctions(degree, family=family)
253
+ topology = Grid2DDiscontinuousSpaceTopology(grid, shape=shape)
604
254
 
605
- from warp.fem import cache
255
+ super().__init__(topology=topology, shape=shape)
606
256
 
607
- return cache.get_func(element_node_index, f"{self.name}_{self.ORDER}")
608
257
 
609
- class Trace(GridBipolynomialSpace.Trace):
610
- def __init__(self, space: "GridBipolynomialSpace"):
611
- super().__init__(space)
258
+ class GridDGPolynomialBasisSpace(Grid2DBasisSpace):
259
+ def __init__(
260
+ self,
261
+ grid: Grid2D,
262
+ degree: int,
263
+ ):
264
+ shape = SquareNonConformingPolynomialShapeFunctions(degree)
265
+ topology = Grid2DDiscontinuousSpaceTopology(grid, shape=shape)
612
266
 
613
- def trace(self):
614
- return GridDGBipolynomialSpace.Trace(self)
267
+ super().__init__(topology=topology, shape=shape)