warp-lang 1.1.0__py3-none-manylinux2014_x86_64.whl → 1.2.0__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.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (218) hide show
  1. warp/bin/warp-clang.so +0 -0
  2. warp/bin/warp.so +0 -0
  3. warp/build.py +10 -37
  4. warp/build_dll.py +2 -2
  5. warp/builtins.py +274 -6
  6. warp/codegen.py +51 -4
  7. warp/config.py +2 -2
  8. warp/constants.py +4 -0
  9. warp/context.py +418 -203
  10. warp/examples/benchmarks/benchmark_api.py +0 -2
  11. warp/examples/benchmarks/benchmark_cloth_warp.py +0 -1
  12. warp/examples/benchmarks/benchmark_launches.py +0 -2
  13. warp/examples/core/example_dem.py +0 -2
  14. warp/examples/core/example_fluid.py +0 -2
  15. warp/examples/core/example_graph_capture.py +0 -2
  16. warp/examples/core/example_marching_cubes.py +0 -2
  17. warp/examples/core/example_mesh.py +0 -2
  18. warp/examples/core/example_mesh_intersect.py +0 -2
  19. warp/examples/core/example_nvdb.py +0 -2
  20. warp/examples/core/example_raycast.py +0 -2
  21. warp/examples/core/example_raymarch.py +0 -2
  22. warp/examples/core/example_render_opengl.py +0 -2
  23. warp/examples/core/example_sph.py +0 -2
  24. warp/examples/core/example_torch.py +0 -3
  25. warp/examples/core/example_wave.py +0 -2
  26. warp/examples/fem/example_apic_fluid.py +140 -115
  27. warp/examples/fem/example_burgers.py +262 -0
  28. warp/examples/fem/example_convection_diffusion.py +0 -2
  29. warp/examples/fem/example_convection_diffusion_dg.py +0 -2
  30. warp/examples/fem/example_deformed_geometry.py +0 -2
  31. warp/examples/fem/example_diffusion.py +0 -2
  32. warp/examples/fem/example_diffusion_3d.py +5 -4
  33. warp/examples/fem/example_diffusion_mgpu.py +0 -2
  34. warp/examples/fem/example_mixed_elasticity.py +0 -2
  35. warp/examples/fem/example_navier_stokes.py +0 -2
  36. warp/examples/fem/example_stokes.py +0 -2
  37. warp/examples/fem/example_stokes_transfer.py +0 -2
  38. warp/examples/optim/example_bounce.py +0 -2
  39. warp/examples/optim/example_cloth_throw.py +0 -2
  40. warp/examples/optim/example_diffray.py +0 -2
  41. warp/examples/optim/example_drone.py +0 -2
  42. warp/examples/optim/example_inverse_kinematics.py +0 -2
  43. warp/examples/optim/example_inverse_kinematics_torch.py +0 -2
  44. warp/examples/optim/example_spring_cage.py +0 -2
  45. warp/examples/optim/example_trajectory.py +0 -2
  46. warp/examples/optim/example_walker.py +0 -2
  47. warp/examples/sim/example_cartpole.py +0 -2
  48. warp/examples/sim/example_cloth.py +0 -2
  49. warp/examples/sim/example_granular.py +0 -2
  50. warp/examples/sim/example_granular_collision_sdf.py +0 -2
  51. warp/examples/sim/example_jacobian_ik.py +0 -2
  52. warp/examples/sim/example_particle_chain.py +0 -2
  53. warp/examples/sim/example_quadruped.py +0 -2
  54. warp/examples/sim/example_rigid_chain.py +0 -2
  55. warp/examples/sim/example_rigid_contact.py +0 -2
  56. warp/examples/sim/example_rigid_force.py +0 -2
  57. warp/examples/sim/example_rigid_gyroscopic.py +0 -2
  58. warp/examples/sim/example_rigid_soft_contact.py +0 -2
  59. warp/examples/sim/example_soft_body.py +0 -2
  60. warp/fem/__init__.py +1 -0
  61. warp/fem/cache.py +3 -1
  62. warp/fem/geometry/__init__.py +1 -0
  63. warp/fem/geometry/element.py +4 -0
  64. warp/fem/geometry/grid_3d.py +0 -4
  65. warp/fem/geometry/nanogrid.py +455 -0
  66. warp/fem/integrate.py +63 -9
  67. warp/fem/space/__init__.py +43 -158
  68. warp/fem/space/basis_space.py +34 -0
  69. warp/fem/space/collocated_function_space.py +1 -1
  70. warp/fem/space/grid_2d_function_space.py +13 -132
  71. warp/fem/space/grid_3d_function_space.py +16 -154
  72. warp/fem/space/hexmesh_function_space.py +37 -134
  73. warp/fem/space/nanogrid_function_space.py +202 -0
  74. warp/fem/space/quadmesh_2d_function_space.py +12 -119
  75. warp/fem/space/restriction.py +4 -1
  76. warp/fem/space/shape/__init__.py +77 -0
  77. warp/fem/space/shape/cube_shape_function.py +5 -15
  78. warp/fem/space/tetmesh_function_space.py +6 -76
  79. warp/fem/space/trimesh_2d_function_space.py +6 -76
  80. warp/native/array.h +12 -3
  81. warp/native/builtin.h +48 -5
  82. warp/native/bvh.cpp +14 -10
  83. warp/native/bvh.cu +23 -15
  84. warp/native/bvh.h +1 -0
  85. warp/native/clang/clang.cpp +2 -1
  86. warp/native/crt.cpp +11 -1
  87. warp/native/crt.h +18 -1
  88. warp/native/exports.h +187 -0
  89. warp/native/mat.h +47 -0
  90. warp/native/mesh.cpp +1 -1
  91. warp/native/mesh.cu +1 -2
  92. warp/native/nanovdb/GridHandle.h +366 -0
  93. warp/native/nanovdb/HostBuffer.h +590 -0
  94. warp/native/nanovdb/NanoVDB.h +3999 -2157
  95. warp/native/nanovdb/PNanoVDB.h +936 -99
  96. warp/native/quat.h +28 -1
  97. warp/native/rand.h +5 -1
  98. warp/native/vec.h +45 -1
  99. warp/native/volume.cpp +335 -103
  100. warp/native/volume.cu +39 -13
  101. warp/native/volume.h +725 -303
  102. warp/native/volume_builder.cu +381 -360
  103. warp/native/volume_builder.h +16 -1
  104. warp/native/volume_impl.h +61 -0
  105. warp/native/warp.cu +8 -2
  106. warp/native/warp.h +15 -7
  107. warp/render/render_opengl.py +191 -52
  108. warp/sim/integrator_featherstone.py +10 -3
  109. warp/sim/integrator_xpbd.py +16 -22
  110. warp/sparse.py +89 -27
  111. warp/stubs.py +83 -0
  112. warp/tests/assets/test_index_grid.nvdb +0 -0
  113. warp/tests/aux_test_dependent.py +0 -2
  114. warp/tests/aux_test_grad_customs.py +0 -2
  115. warp/tests/aux_test_reference.py +0 -2
  116. warp/tests/aux_test_reference_reference.py +0 -2
  117. warp/tests/aux_test_square.py +0 -2
  118. warp/tests/disabled_kinematics.py +0 -2
  119. warp/tests/test_adam.py +0 -2
  120. warp/tests/test_arithmetic.py +0 -36
  121. warp/tests/test_array.py +9 -11
  122. warp/tests/test_array_reduce.py +0 -2
  123. warp/tests/test_async.py +0 -2
  124. warp/tests/test_atomic.py +0 -2
  125. warp/tests/test_bool.py +58 -50
  126. warp/tests/test_builtins_resolution.py +0 -2
  127. warp/tests/test_bvh.py +0 -2
  128. warp/tests/test_closest_point_edge_edge.py +0 -1
  129. warp/tests/test_codegen.py +0 -4
  130. warp/tests/test_compile_consts.py +130 -10
  131. warp/tests/test_conditional.py +0 -2
  132. warp/tests/test_copy.py +0 -2
  133. warp/tests/test_ctypes.py +6 -8
  134. warp/tests/test_dense.py +0 -2
  135. warp/tests/test_devices.py +0 -2
  136. warp/tests/test_dlpack.py +9 -11
  137. warp/tests/test_examples.py +42 -39
  138. warp/tests/test_fabricarray.py +0 -3
  139. warp/tests/test_fast_math.py +0 -2
  140. warp/tests/test_fem.py +75 -54
  141. warp/tests/test_fp16.py +0 -2
  142. warp/tests/test_func.py +0 -2
  143. warp/tests/test_generics.py +27 -2
  144. warp/tests/test_grad.py +147 -8
  145. warp/tests/test_grad_customs.py +0 -2
  146. warp/tests/test_hash_grid.py +1 -3
  147. warp/tests/test_import.py +0 -2
  148. warp/tests/test_indexedarray.py +0 -2
  149. warp/tests/test_intersect.py +0 -2
  150. warp/tests/test_jax.py +0 -2
  151. warp/tests/test_large.py +11 -9
  152. warp/tests/test_launch.py +0 -2
  153. warp/tests/test_lerp.py +10 -54
  154. warp/tests/test_linear_solvers.py +3 -5
  155. warp/tests/test_lvalue.py +0 -2
  156. warp/tests/test_marching_cubes.py +0 -2
  157. warp/tests/test_mat.py +0 -2
  158. warp/tests/test_mat_lite.py +0 -2
  159. warp/tests/test_mat_scalar_ops.py +0 -2
  160. warp/tests/test_math.py +0 -2
  161. warp/tests/test_matmul.py +35 -37
  162. warp/tests/test_matmul_lite.py +29 -31
  163. warp/tests/test_mempool.py +0 -2
  164. warp/tests/test_mesh.py +0 -3
  165. warp/tests/test_mesh_query_aabb.py +0 -2
  166. warp/tests/test_mesh_query_point.py +0 -2
  167. warp/tests/test_mesh_query_ray.py +0 -2
  168. warp/tests/test_mlp.py +0 -2
  169. warp/tests/test_model.py +0 -2
  170. warp/tests/test_module_hashing.py +111 -0
  171. warp/tests/test_modules_lite.py +0 -3
  172. warp/tests/test_multigpu.py +0 -2
  173. warp/tests/test_noise.py +0 -4
  174. warp/tests/test_operators.py +0 -2
  175. warp/tests/test_options.py +0 -2
  176. warp/tests/test_peer.py +0 -2
  177. warp/tests/test_pinned.py +0 -2
  178. warp/tests/test_print.py +0 -2
  179. warp/tests/test_quat.py +0 -2
  180. warp/tests/test_rand.py +41 -5
  181. warp/tests/test_reload.py +0 -10
  182. warp/tests/test_rounding.py +0 -2
  183. warp/tests/test_runlength_encode.py +0 -2
  184. warp/tests/test_sim_grad.py +0 -2
  185. warp/tests/test_sim_kinematics.py +0 -2
  186. warp/tests/test_smoothstep.py +0 -2
  187. warp/tests/test_snippet.py +0 -2
  188. warp/tests/test_sparse.py +0 -2
  189. warp/tests/test_spatial.py +0 -2
  190. warp/tests/test_special_values.py +362 -0
  191. warp/tests/test_streams.py +0 -2
  192. warp/tests/test_struct.py +0 -2
  193. warp/tests/test_tape.py +0 -2
  194. warp/tests/test_torch.py +0 -2
  195. warp/tests/test_transient_module.py +0 -2
  196. warp/tests/test_types.py +0 -2
  197. warp/tests/test_utils.py +0 -2
  198. warp/tests/test_vec.py +0 -2
  199. warp/tests/test_vec_lite.py +0 -2
  200. warp/tests/test_vec_scalar_ops.py +0 -2
  201. warp/tests/test_verify_fp.py +0 -2
  202. warp/tests/test_volume.py +237 -13
  203. warp/tests/test_volume_write.py +86 -3
  204. warp/tests/unittest_serial.py +10 -9
  205. warp/tests/unittest_suites.py +6 -2
  206. warp/tests/unittest_utils.py +2 -171
  207. warp/tests/unused_test_misc.py +0 -2
  208. warp/tests/walkthrough_debug.py +1 -1
  209. warp/thirdparty/unittest_parallel.py +37 -40
  210. warp/types.py +514 -77
  211. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/METADATA +57 -30
  212. warp_lang-1.2.0.dist-info/RECORD +359 -0
  213. warp/examples/fem/example_convection_diffusion_dg0.py +0 -204
  214. warp/native/nanovdb/PNanoVDBWrite.h +0 -295
  215. warp_lang-1.1.0.dist-info/RECORD +0 -352
  216. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/LICENSE.md +0 -0
  217. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/WHEEL +0 -0
  218. {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/top_level.txt +0 -0
@@ -6,23 +6,24 @@ from warp.fem.geometry.hexmesh import (
6
6
  FACE_ORIENTATION,
7
7
  FACE_TRANSLATION,
8
8
  )
9
- from warp.fem.polynomial import Polynomial, is_closed
10
- from warp.fem.types import Coords, ElementIndex
9
+ from warp.fem.polynomial import is_closed
10
+ from warp.fem.types import ElementIndex
11
11
 
12
- from .basis_space import ShapeBasisSpace, TraceBasisSpace
13
12
  from .shape import (
14
- ConstantShapeFunction,
15
- CubeNonConformingPolynomialShapeFunctions,
16
13
  CubeSerendipityShapeFunctions,
17
14
  CubeTripolynomialShapeFunctions,
18
15
  ShapeFunction,
19
16
  )
20
- from .topology import DiscontinuousSpaceTopologyMixin, SpaceTopology, forward_base_topology
17
+ from .topology import SpaceTopology, forward_base_topology
21
18
 
22
19
  _FACE_ORIENTATION_I = wp.constant(wp.mat(shape=(16, 2), dtype=int)(FACE_ORIENTATION))
23
20
  _FACE_TRANSLATION_I = wp.constant(wp.mat(shape=(4, 2), dtype=int)(FACE_TRANSLATION))
24
21
 
25
- _CUBE_VERTEX_INDICES = wp.constant(wp.vec(length=8, dtype=int)([0, 4, 3, 7, 1, 5, 2, 6]))
22
+ # map from shape function vertex indexing to hexmesh vertex indexing
23
+ _CUBE_TO_HEX_VERTEX = wp.constant(wp.vec(length=8, dtype=int)([0, 4, 3, 7, 1, 5, 2, 6]))
24
+
25
+ # map from shape function edge indexing to hexmesh edge indexing
26
+ _CUBE_TO_HEX_EDGE = wp.constant(wp.vec(length=12, dtype=int)([0, 4, 2, 6, 3, 1, 7, 5, 8, 11, 9, 10]))
26
27
 
27
28
 
28
29
  @wp.struct
@@ -45,9 +46,12 @@ class HexmeshSpaceTopology(SpaceTopology):
45
46
  need_hex_edge_indices: bool = True,
46
47
  need_hex_face_indices: bool = True,
47
48
  ):
49
+ if not is_closed(shape.family):
50
+ raise ValueError("A closed polynomial family is required to define a continuous function space")
51
+
48
52
  super().__init__(mesh, shape.NODES_PER_ELEMENT)
49
53
  self._mesh = mesh
50
- self._shape = shape
54
+ self.shape = shape
51
55
 
52
56
  if need_hex_edge_indices:
53
57
  self._hex_edge_indices = self._mesh.hex_edge_indices
@@ -111,44 +115,6 @@ class HexmeshSpaceTopology(SpaceTopology):
111
115
  hex_face_indices[hx1, local_face_1] = wp.vec2i(f, ori_1)
112
116
 
113
117
 
114
- class HexmeshDiscontinuousSpaceTopology(
115
- DiscontinuousSpaceTopologyMixin,
116
- SpaceTopology,
117
- ):
118
- def __init__(self, mesh: Hexmesh, shape: ShapeFunction):
119
- super().__init__(mesh, shape.NODES_PER_ELEMENT)
120
-
121
-
122
- class HexmeshBasisSpace(ShapeBasisSpace):
123
- def __init__(self, topology: HexmeshSpaceTopology, shape: ShapeFunction):
124
- super().__init__(topology, shape)
125
-
126
- self._mesh: Hexmesh = topology.geometry
127
-
128
-
129
- class HexmeshPiecewiseConstantBasis(HexmeshBasisSpace):
130
- def __init__(self, mesh: Hexmesh):
131
- shape = ConstantShapeFunction(mesh.reference_cell(), space_dimension=3)
132
- topology = HexmeshDiscontinuousSpaceTopology(mesh, shape)
133
- super().__init__(shape=shape, topology=topology)
134
-
135
- class Trace(TraceBasisSpace):
136
- @wp.func
137
- def _node_coords_in_element(
138
- side_arg: Hexmesh.SideArg,
139
- basis_arg: HexmeshBasisSpace.BasisArg,
140
- element_index: ElementIndex,
141
- node_index_in_element: int,
142
- ):
143
- return Coords(0.5, 0.5, 0.0)
144
-
145
- def make_node_coords_in_element(self):
146
- return self._node_coords_in_element
147
-
148
- def trace(self):
149
- return HexmeshPiecewiseConstantBasis.Trace(self)
150
-
151
-
152
118
  class HexmeshTripolynomialSpaceTopology(HexmeshSpaceTopology):
153
119
  def __init__(self, mesh: Hexmesh, shape: CubeTripolynomialShapeFunctions):
154
120
  super().__init__(mesh, shape, need_hex_edge_indices=shape.ORDER >= 2, need_hex_face_indices=shape.ORDER >= 2)
@@ -156,7 +122,7 @@ class HexmeshTripolynomialSpaceTopology(HexmeshSpaceTopology):
156
122
  self.element_node_index = self._make_element_node_index()
157
123
 
158
124
  def node_count(self) -> int:
159
- ORDER = self._shape.ORDER
125
+ ORDER = self.shape.ORDER
160
126
  INTERIOR_NODES_PER_EDGE = max(0, ORDER - 1)
161
127
  INTERIOR_NODES_PER_FACE = INTERIOR_NODES_PER_EDGE**2
162
128
  INTERIOR_NODES_PER_CELL = INTERIOR_NODES_PER_EDGE**3
@@ -182,7 +148,7 @@ class HexmeshTripolynomialSpaceTopology(HexmeshSpaceTopology):
182
148
  return rot_i * size + rot_j
183
149
 
184
150
  def _make_element_node_index(self):
185
- ORDER = self._shape.ORDER
151
+ ORDER = self.shape.ORDER
186
152
  INTERIOR_NODES_PER_EDGE = wp.constant(max(0, ORDER - 1))
187
153
  INTERIOR_NODES_PER_FACE = wp.constant(INTERIOR_NODES_PER_EDGE**2)
188
154
  INTERIOR_NODES_PER_CELL = wp.constant(INTERIOR_NODES_PER_EDGE**3)
@@ -194,18 +160,19 @@ class HexmeshTripolynomialSpaceTopology(HexmeshSpaceTopology):
194
160
  element_index: ElementIndex,
195
161
  node_index_in_elt: int,
196
162
  ):
197
- node_type, type_instance, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
163
+ node_type, type_instance, type_index = self.shape.node_type_and_type_index(node_index_in_elt)
198
164
 
199
165
  if node_type == CubeTripolynomialShapeFunctions.VERTEX:
200
- return geo_arg.hex_vertex_indices[element_index, _CUBE_VERTEX_INDICES[type_instance]]
166
+ return geo_arg.hex_vertex_indices[element_index, _CUBE_TO_HEX_VERTEX[type_instance]]
201
167
 
202
168
  offset = topo_arg.vertex_count
203
169
 
204
170
  if node_type == CubeTripolynomialShapeFunctions.EDGE:
205
- edge_index = topo_arg.hex_edge_indices[element_index, type_instance]
171
+ hex_edge = _CUBE_TO_HEX_EDGE[type_instance]
172
+ edge_index = topo_arg.hex_edge_indices[element_index, hex_edge]
206
173
 
207
- v0 = geo_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[type_instance, 0]]
208
- v1 = geo_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[type_instance, 1]]
174
+ v0 = geo_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[hex_edge, 0]]
175
+ v1 = geo_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[hex_edge, 1]]
209
176
 
210
177
  if v0 > v1:
211
178
  type_index = ORDER - 1 - type_index
@@ -232,52 +199,21 @@ class HexmeshTripolynomialSpaceTopology(HexmeshSpaceTopology):
232
199
  return element_node_index
233
200
 
234
201
 
235
- class HexmeshTripolynomialBasisSpace(HexmeshBasisSpace):
236
- def __init__(
237
- self,
238
- mesh: Hexmesh,
239
- degree: int,
240
- family: Polynomial,
241
- ):
242
- if family is None:
243
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
244
-
245
- if not is_closed(family):
246
- raise ValueError("A closed polynomial family is required to define a continuous function space")
247
-
248
- shape = CubeTripolynomialShapeFunctions(degree, family=family)
249
- topology = forward_base_topology(HexmeshTripolynomialSpaceTopology, mesh, shape)
250
-
251
- super().__init__(topology, shape)
252
-
253
-
254
- class HexmeshDGTripolynomialBasisSpace(HexmeshBasisSpace):
202
+ class HexmeshSerendipitySpaceTopology(HexmeshSpaceTopology):
255
203
  def __init__(
256
204
  self,
257
- mesh: Hexmesh,
258
- degree: int,
259
- family: Polynomial,
205
+ grid: Hexmesh,
206
+ shape: CubeSerendipityShapeFunctions,
260
207
  ):
261
- if family is None:
262
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
263
-
264
- shape = CubeTripolynomialShapeFunctions(degree, family=family)
265
- topology = HexmeshDiscontinuousSpaceTopology(mesh, shape)
266
-
267
- super().__init__(topology, shape)
268
-
269
-
270
- class HexmeshSerendipitySpaceTopology(HexmeshSpaceTopology):
271
- def __init__(self, grid: Hexmesh, shape: CubeSerendipityShapeFunctions):
272
208
  super().__init__(grid, shape, need_hex_edge_indices=True, need_hex_face_indices=False)
273
209
 
274
210
  self.element_node_index = self._make_element_node_index()
275
211
 
276
212
  def node_count(self) -> int:
277
- return self.geometry.vertex_count() + (self._shape.ORDER - 1) * self.geometry.edge_count()
213
+ return self.geometry.vertex_count() + (self.shape.ORDER - 1) * self.geometry.edge_count()
278
214
 
279
215
  def _make_element_node_index(self):
280
- ORDER = self._shape.ORDER
216
+ ORDER = self.shape.ORDER
281
217
 
282
218
  @cache.dynamic_func(suffix=self.name)
283
219
  def element_node_index(
@@ -286,17 +222,18 @@ class HexmeshSerendipitySpaceTopology(HexmeshSpaceTopology):
286
222
  element_index: ElementIndex,
287
223
  node_index_in_elt: int,
288
224
  ):
289
- node_type, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
225
+ node_type, type_index = self.shape.node_type_and_type_index(node_index_in_elt)
290
226
 
291
227
  if node_type == CubeSerendipityShapeFunctions.VERTEX:
292
- return cell_arg.hex_vertex_indices[element_index, _CUBE_VERTEX_INDICES[type_index]]
228
+ return cell_arg.hex_vertex_indices[element_index, _CUBE_TO_HEX_VERTEX[type_index]]
293
229
 
294
230
  type_instance, index_in_edge = CubeSerendipityShapeFunctions._cube_edge_index(node_type, type_index)
231
+ hex_edge = _CUBE_TO_HEX_EDGE[type_instance]
295
232
 
296
- edge_index = topo_arg.hex_edge_indices[element_index, type_instance]
233
+ edge_index = topo_arg.hex_edge_indices[element_index, hex_edge]
297
234
 
298
- v0 = cell_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[type_instance, 0]]
299
- v1 = cell_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[type_instance, 1]]
235
+ v0 = cell_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[hex_edge, 0]]
236
+ v1 = cell_arg.hex_vertex_indices[element_index, EDGE_VERTEX_INDICES[hex_edge, 1]]
300
237
 
301
238
  if v0 > v1:
302
239
  index_in_edge = ORDER - 1 - index_in_edge
@@ -306,45 +243,11 @@ class HexmeshSerendipitySpaceTopology(HexmeshSpaceTopology):
306
243
  return element_node_index
307
244
 
308
245
 
309
- class HexmeshSerendipityBasisSpace(HexmeshBasisSpace):
310
- def __init__(
311
- self,
312
- mesh: Hexmesh,
313
- degree: int,
314
- family: Polynomial,
315
- ):
316
- if family is None:
317
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
318
-
319
- shape = CubeSerendipityShapeFunctions(degree, family=family)
320
- topology = forward_base_topology(HexmeshSerendipitySpaceTopology, mesh, shape=shape)
321
-
322
- super().__init__(topology=topology, shape=shape)
246
+ def make_hexmesh_space_topology(mesh: Hexmesh, shape: ShapeFunction):
247
+ if isinstance(shape, CubeSerendipityShapeFunctions):
248
+ return forward_base_topology(HexmeshSerendipitySpaceTopology, mesh, shape)
323
249
 
250
+ if isinstance(shape, CubeTripolynomialShapeFunctions):
251
+ return forward_base_topology(HexmeshTripolynomialSpaceTopology, mesh, shape)
324
252
 
325
- class HexmeshDGSerendipityBasisSpace(HexmeshBasisSpace):
326
- def __init__(
327
- self,
328
- mesh: Hexmesh,
329
- degree: int,
330
- family: Polynomial,
331
- ):
332
- if family is None:
333
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
334
-
335
- shape = CubeSerendipityShapeFunctions(degree, family=family)
336
- topology = HexmeshDiscontinuousSpaceTopology(mesh, shape=shape)
337
-
338
- super().__init__(topology=topology, shape=shape)
339
-
340
-
341
- class HexmeshPolynomialBasisSpace(HexmeshBasisSpace):
342
- def __init__(
343
- self,
344
- mesh: Hexmesh,
345
- degree: int,
346
- ):
347
- shape = CubeNonConformingPolynomialShapeFunctions(degree)
348
- topology = HexmeshDiscontinuousSpaceTopology(mesh, shape)
349
-
350
- super().__init__(topology, shape)
253
+ raise ValueError(f"Unsupported shape function {shape.name}")
@@ -0,0 +1,202 @@
1
+ import warp as wp
2
+ from warp.fem import cache
3
+ from warp.fem.geometry import Nanogrid
4
+ from warp.fem.geometry.nanogrid import _add_axis_flag
5
+ from warp.fem.polynomial import is_closed
6
+ from warp.fem.types import ElementIndex
7
+
8
+ from .shape import (
9
+ CubeSerendipityShapeFunctions,
10
+ CubeTripolynomialShapeFunctions,
11
+ ShapeFunction,
12
+ )
13
+ from .topology import SpaceTopology, forward_base_topology
14
+
15
+
16
+ @wp.struct
17
+ class NanogridTopologyArg:
18
+ vertex_grid: wp.uint64
19
+ face_grid: wp.uint64
20
+ edge_grid: wp.uint64
21
+
22
+ vertex_count: int
23
+ edge_count: int
24
+ face_count: int
25
+
26
+
27
+ class NanogridSpaceTopology(SpaceTopology):
28
+ TopologyArg = NanogridTopologyArg
29
+
30
+ def __init__(
31
+ self,
32
+ grid: Nanogrid,
33
+ shape: ShapeFunction,
34
+ need_edge_indices: bool = True,
35
+ need_face_indices: bool = True,
36
+ ):
37
+ if not is_closed(shape.family):
38
+ raise ValueError("A closed polynomial family is required to define a continuous function space")
39
+
40
+ super().__init__(grid, shape.NODES_PER_ELEMENT)
41
+ self._grid = grid
42
+ self._shape = shape
43
+
44
+ if need_edge_indices:
45
+ self._edge_count = self._grid.edge_count()
46
+ else:
47
+ self._edge_count = 0
48
+
49
+ self._vertex_grid = grid._node_grid
50
+ self._face_grid = grid._face_grid
51
+ self._edge_grid = grid._edge_grid
52
+
53
+ @cache.cached_arg_value
54
+ def topo_arg_value(self, device):
55
+ arg = NanogridTopologyArg()
56
+
57
+ arg.vertex_grid = self._vertex_grid.id
58
+ arg.face_grid = self._face_grid.id
59
+ arg.edge_grid = -1 if self._edge_grid is None else self._edge_grid.id
60
+
61
+ arg.vertex_count = self._grid.vertex_count()
62
+ arg.face_count = self._grid.side_count()
63
+ arg.edge_count = self._edge_count
64
+ return arg
65
+
66
+
67
+ @wp.func
68
+ def _cell_vertex_coord(cell_ijk: wp.vec3i, n: int):
69
+ return cell_ijk + wp.vec3i((n & 4) >> 2, (n & 2) >> 1, n & 1)
70
+
71
+
72
+ @wp.func
73
+ def _cell_edge_coord(cell_ijk: wp.vec3i, axis: int, offset: int):
74
+ e_ijk = cell_ijk
75
+ e_ijk[(axis + 1) % 3] += offset >> 1
76
+ e_ijk[(axis + 2) % 3] += offset & 1
77
+ return _add_axis_flag(e_ijk, axis)
78
+
79
+
80
+ @wp.func
81
+ def _cell_face_coord(cell_ijk: wp.vec3i, axis: int, offset: int):
82
+ f_ijk = cell_ijk
83
+ f_ijk[axis] += offset
84
+ return _add_axis_flag(f_ijk, axis)
85
+
86
+
87
+ class NanogridTripolynomialSpaceTopology(NanogridSpaceTopology):
88
+ def __init__(self, grid: Nanogrid, shape: CubeTripolynomialShapeFunctions):
89
+ super().__init__(grid, shape, need_edge_indices=shape.ORDER >= 2, need_face_indices=shape.ORDER >= 2)
90
+
91
+ self.element_node_index = self._make_element_node_index()
92
+
93
+ def node_count(self) -> int:
94
+ ORDER = self._shape.ORDER
95
+ INTERIOR_NODES_PER_EDGE = max(0, ORDER - 1)
96
+ INTERIOR_NODES_PER_FACE = INTERIOR_NODES_PER_EDGE**2
97
+ INTERIOR_NODES_PER_CELL = INTERIOR_NODES_PER_EDGE**3
98
+
99
+ return (
100
+ self._grid.vertex_count()
101
+ + self._grid.edge_count() * INTERIOR_NODES_PER_EDGE
102
+ + self._grid.side_count() * INTERIOR_NODES_PER_FACE
103
+ + self._grid.cell_count() * INTERIOR_NODES_PER_CELL
104
+ )
105
+
106
+ def _make_element_node_index(self):
107
+ ORDER = self._shape.ORDER
108
+ INTERIOR_NODES_PER_EDGE = wp.constant(max(0, ORDER - 1))
109
+ INTERIOR_NODES_PER_FACE = wp.constant(INTERIOR_NODES_PER_EDGE**2)
110
+ INTERIOR_NODES_PER_CELL = wp.constant(INTERIOR_NODES_PER_EDGE**3)
111
+
112
+ @cache.dynamic_func(suffix=self.name)
113
+ def element_node_index(
114
+ geo_arg: Nanogrid.CellArg,
115
+ topo_arg: NanogridTopologyArg,
116
+ element_index: ElementIndex,
117
+ node_index_in_elt: int,
118
+ ):
119
+ node_type, type_instance, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
120
+
121
+ ijk = geo_arg.cell_ijk[element_index]
122
+
123
+ if node_type == CubeTripolynomialShapeFunctions.VERTEX:
124
+ n_ijk = _cell_vertex_coord(ijk, type_instance)
125
+ return wp.volume_lookup_index(topo_arg.vertex_grid, n_ijk[0], n_ijk[1], n_ijk[2])
126
+
127
+ offset = topo_arg.vertex_count
128
+
129
+ if node_type == CubeTripolynomialShapeFunctions.EDGE:
130
+ axis = type_instance >> 2
131
+ node_offset = type_instance & 3
132
+
133
+ n_ijk = _cell_edge_coord(ijk, axis, node_offset)
134
+
135
+ edge_index = wp.volume_lookup_index(topo_arg.edge_grid, n_ijk[0], n_ijk[1], n_ijk[2])
136
+ return offset + INTERIOR_NODES_PER_EDGE * edge_index + type_index
137
+
138
+ offset += INTERIOR_NODES_PER_EDGE * topo_arg.edge_count
139
+
140
+ if node_type == CubeTripolynomialShapeFunctions.FACE:
141
+ axis = type_instance >> 1
142
+ node_offset = type_instance & 1
143
+
144
+ n_ijk = _cell_face_coord(ijk, axis, node_offset)
145
+
146
+ face_index = wp.volume_lookup_index(topo_arg.face_grid, n_ijk[0], n_ijk[1], n_ijk[2])
147
+ return offset + INTERIOR_NODES_PER_FACE * face_index + type_index
148
+
149
+ offset += INTERIOR_NODES_PER_FACE * topo_arg.face_count
150
+
151
+ return offset + INTERIOR_NODES_PER_CELL * element_index + type_index
152
+
153
+ return element_node_index
154
+
155
+
156
+ class NanogridSerendipitySpaceTopology(NanogridSpaceTopology):
157
+ def __init__(self, grid: Nanogrid, shape: CubeSerendipityShapeFunctions):
158
+ super().__init__(grid, shape, need_edge_indices=True, need_face_indices=False)
159
+
160
+ self.element_node_index = self._make_element_node_index()
161
+
162
+ def node_count(self) -> int:
163
+ return self.geometry.vertex_count() + (self._shape.ORDER - 1) * self.geometry.edge_count()
164
+
165
+ def _make_element_node_index(self):
166
+ ORDER = self._shape.ORDER
167
+
168
+ @cache.dynamic_func(suffix=self.name)
169
+ def element_node_index(
170
+ cell_arg: Nanogrid.CellArg,
171
+ topo_arg: NanogridSpaceTopology.TopologyArg,
172
+ element_index: ElementIndex,
173
+ node_index_in_elt: int,
174
+ ):
175
+ node_type, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
176
+
177
+ ijk = cell_arg.cell_ijk[element_index]
178
+
179
+ if node_type == CubeSerendipityShapeFunctions.VERTEX:
180
+ n_ijk = _cell_vertex_coord(ijk, type_index)
181
+ return wp.volume_lookup_index(topo_arg.vertex_grid, n_ijk[0], n_ijk[1], n_ijk[2])
182
+
183
+ type_instance, index_in_edge = CubeSerendipityShapeFunctions._cube_edge_index(node_type, type_index)
184
+ axis = type_instance >> 2
185
+ node_offset = type_instance & 3
186
+
187
+ n_ijk = _cell_edge_coord(ijk, axis, node_offset)
188
+
189
+ edge_index = wp.volume_lookup_index(topo_arg.edge_grid, n_ijk[0], n_ijk[1], n_ijk[2])
190
+ return topo_arg.vertex_count + (ORDER - 1) * edge_index + index_in_edge
191
+
192
+ return element_node_index
193
+
194
+
195
+ def make_nanogrid_space_topology(grid: Nanogrid, shape: ShapeFunction):
196
+ if isinstance(shape, CubeSerendipityShapeFunctions):
197
+ return forward_base_topology(NanogridSerendipitySpaceTopology, grid, shape)
198
+
199
+ if isinstance(shape, CubeTripolynomialShapeFunctions):
200
+ return forward_base_topology(NanogridTripolynomialSpaceTopology, grid, shape)
201
+
202
+ raise ValueError(f"Unsupported shape function {shape.name}")
@@ -1,18 +1,15 @@
1
1
  import warp as wp
2
2
  from warp.fem import cache
3
3
  from warp.fem.geometry import Quadmesh2D
4
- from warp.fem.polynomial import Polynomial, is_closed
5
- from warp.fem.types import Coords, ElementIndex
4
+ from warp.fem.polynomial import is_closed
5
+ from warp.fem.types import ElementIndex
6
6
 
7
- from .basis_space import ShapeBasisSpace, TraceBasisSpace
8
7
  from .shape import (
9
- ConstantShapeFunction,
10
8
  ShapeFunction,
11
9
  SquareBipolynomialShapeFunctions,
12
- SquareNonConformingPolynomialShapeFunctions,
13
10
  SquareSerendipityShapeFunctions,
14
11
  )
15
- from .topology import DiscontinuousSpaceTopologyMixin, SpaceTopology, forward_base_topology
12
+ from .topology import SpaceTopology, forward_base_topology
16
13
 
17
14
 
18
15
  @wp.struct
@@ -28,6 +25,9 @@ class Quadmesh2DSpaceTopology(SpaceTopology):
28
25
  TopologyArg = Quadmesh2DTopologyArg
29
26
 
30
27
  def __init__(self, mesh: Quadmesh2D, shape: ShapeFunction):
28
+ if not is_closed(shape.family):
29
+ raise ValueError("A closed polynomial family is required to define a continuous function space")
30
+
31
31
  super().__init__(mesh, shape.NODES_PER_ELEMENT)
32
32
  self._mesh = mesh
33
33
  self._shape = shape
@@ -107,44 +107,6 @@ class Quadmesh2DSpaceTopology(SpaceTopology):
107
107
  quad_edge_indices[q1, t1_edge] = e
108
108
 
109
109
 
110
- class Quadmesh2DDiscontinuousSpaceTopology(
111
- DiscontinuousSpaceTopologyMixin,
112
- SpaceTopology,
113
- ):
114
- def __init__(self, mesh: Quadmesh2D, shape: ShapeFunction):
115
- super().__init__(mesh, shape.NODES_PER_ELEMENT)
116
-
117
-
118
- class Quadmesh2DBasisSpace(ShapeBasisSpace):
119
- def __init__(self, topology: Quadmesh2DSpaceTopology, shape: ShapeFunction):
120
- super().__init__(topology, shape)
121
-
122
- self._mesh: Quadmesh2D = topology.geometry
123
-
124
-
125
- class Quadmesh2DPiecewiseConstantBasis(Quadmesh2DBasisSpace):
126
- def __init__(self, mesh: Quadmesh2D):
127
- shape = ConstantShapeFunction(mesh.reference_cell(), space_dimension=2)
128
- topology = Quadmesh2DDiscontinuousSpaceTopology(mesh, shape)
129
- super().__init__(shape=shape, topology=topology)
130
-
131
- class Trace(TraceBasisSpace):
132
- @wp.func
133
- def _node_coords_in_element(
134
- side_arg: Quadmesh2D.SideArg,
135
- basis_arg: Quadmesh2DBasisSpace.BasisArg,
136
- element_index: ElementIndex,
137
- node_index_in_element: int,
138
- ):
139
- return Coords(0.5, 0.0, 0.0)
140
-
141
- def make_node_coords_in_element(self):
142
- return self._node_coords_in_element
143
-
144
- def trace(self):
145
- return Quadmesh2DPiecewiseConstantBasis.Trace(self)
146
-
147
-
148
110
  class Quadmesh2DBipolynomialSpaceTopology(Quadmesh2DSpaceTopology):
149
111
  def __init__(self, mesh: Quadmesh2D, shape: SquareBipolynomialShapeFunctions):
150
112
  super().__init__(mesh, shape)
@@ -236,41 +198,6 @@ class Quadmesh2DBipolynomialSpaceTopology(Quadmesh2DSpaceTopology):
236
198
  return element_node_index
237
199
 
238
200
 
239
- class Quadmesh2DBipolynomialBasisSpace(Quadmesh2DBasisSpace):
240
- def __init__(
241
- self,
242
- mesh: Quadmesh2D,
243
- degree: int,
244
- family: Polynomial,
245
- ):
246
- if family is None:
247
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
248
-
249
- if not is_closed(family):
250
- raise ValueError("A closed polynomial family is required to define a continuous function space")
251
-
252
- shape = SquareBipolynomialShapeFunctions(degree, family=family)
253
- topology = forward_base_topology(Quadmesh2DBipolynomialSpaceTopology, mesh, shape)
254
-
255
- super().__init__(topology, shape)
256
-
257
-
258
- class Quadmesh2DDGBipolynomialBasisSpace(Quadmesh2DBasisSpace):
259
- def __init__(
260
- self,
261
- mesh: Quadmesh2D,
262
- degree: int,
263
- family: Polynomial,
264
- ):
265
- if family is None:
266
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
267
-
268
- shape = SquareBipolynomialShapeFunctions(degree, family=family)
269
- topology = Quadmesh2DDiscontinuousSpaceTopology(mesh, shape)
270
-
271
- super().__init__(topology, shape)
272
-
273
-
274
201
  class Quadmesh2DSerendipitySpaceTopology(Quadmesh2DSpaceTopology):
275
202
  def __init__(self, grid: Quadmesh2D, shape: SquareSerendipityShapeFunctions):
276
203
  super().__init__(grid, shape)
@@ -324,45 +251,11 @@ class Quadmesh2DSerendipitySpaceTopology(Quadmesh2DSpaceTopology):
324
251
  return element_node_index
325
252
 
326
253
 
327
- class Quadmesh2DSerendipityBasisSpace(Quadmesh2DBasisSpace):
328
- def __init__(
329
- self,
330
- mesh: Quadmesh2D,
331
- degree: int,
332
- family: Polynomial,
333
- ):
334
- if family is None:
335
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
254
+ def make_quadmesh_2d_space_topology(mesh: Quadmesh2D, shape: ShapeFunction):
255
+ if isinstance(shape, SquareSerendipityShapeFunctions):
256
+ return forward_base_topology(Quadmesh2DSerendipitySpaceTopology, mesh, shape)
336
257
 
337
- shape = SquareSerendipityShapeFunctions(degree, family=family)
338
- topology = forward_base_topology(Quadmesh2DSerendipitySpaceTopology, mesh, shape=shape)
339
-
340
- super().__init__(topology=topology, shape=shape)
341
-
342
-
343
- class Quadmesh2DDGSerendipityBasisSpace(Quadmesh2DBasisSpace):
344
- def __init__(
345
- self,
346
- mesh: Quadmesh2D,
347
- degree: int,
348
- family: Polynomial,
349
- ):
350
- if family is None:
351
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
352
-
353
- shape = SquareSerendipityShapeFunctions(degree, family=family)
354
- topology = Quadmesh2DDiscontinuousSpaceTopology(mesh, shape=shape)
355
-
356
- super().__init__(topology=topology, shape=shape)
357
-
358
-
359
- class Quadmesh2DPolynomialBasisSpace(Quadmesh2DBasisSpace):
360
- def __init__(
361
- self,
362
- mesh: Quadmesh2D,
363
- degree: int,
364
- ):
365
- shape = SquareNonConformingPolynomialShapeFunctions(degree)
366
- topology = Quadmesh2DDiscontinuousSpaceTopology(mesh, shape)
258
+ if isinstance(shape, SquareBipolynomialShapeFunctions):
259
+ return forward_base_topology(Quadmesh2DBipolynomialSpaceTopology, mesh, shape)
367
260
 
368
- super().__init__(topology, shape)
261
+ raise ValueError(f"Unsupported shape function {shape.name}")
@@ -38,7 +38,10 @@ class SpaceRestriction:
38
38
 
39
39
  NODES_PER_ELEMENT = self.space_topology.NODES_PER_ELEMENT
40
40
 
41
- @cache.dynamic_kernel(suffix=f"{self.domain.name}_{self.space_topology.name}_{self.space_partition.name}")
41
+ @cache.dynamic_kernel(
42
+ suffix=f"{self.domain.name}_{self.space_topology.name}_{self.space_partition.name}",
43
+ kernel_options={"max_unroll": 8},
44
+ )
42
45
  def fill_element_node_indices(
43
46
  element_arg: self.domain.ElementArg,
44
47
  domain_index_arg: self.domain.ElementIndexArg,