warp-lang 1.1.0__py3-none-manylinux2014_x86_64.whl → 1.2.1__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 +422 -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 +526 -85
  211. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/METADATA +61 -31
  212. warp_lang-1.2.1.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.1.dist-info}/LICENSE.md +0 -0
  217. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/WHEEL +0 -0
  218. {warp_lang-1.1.0.dist-info → warp_lang-1.2.1.dist-info}/top_level.txt +0 -0
@@ -9,53 +9,24 @@ import warp.fem.polynomial as _polynomial
9
9
 
10
10
  from .function_space import FunctionSpace
11
11
  from .topology import SpaceTopology
12
- from .basis_space import BasisSpace, PointBasisSpace
12
+ from .basis_space import BasisSpace, PointBasisSpace, ShapeBasisSpace, make_discontinuous_basis_space
13
13
  from .collocated_function_space import CollocatedFunctionSpace
14
+ from .shape import ElementBasis, get_shape_function
15
+
16
+ from .grid_2d_function_space import make_grid_2d_space_topology
17
+
18
+ from .grid_3d_function_space import make_grid_3d_space_topology
19
+
20
+ from .trimesh_2d_function_space import make_trimesh_2d_space_topology
21
+
22
+ from .tetmesh_function_space import make_tetmesh_space_topology
23
+
24
+ from .quadmesh_2d_function_space import make_quadmesh_2d_space_topology
25
+
26
+ from .hexmesh_function_space import make_hexmesh_space_topology
27
+
28
+ from .nanogrid_function_space import make_nanogrid_space_topology
14
29
 
15
- from .grid_2d_function_space import (
16
- GridPiecewiseConstantBasis,
17
- GridBipolynomialBasisSpace,
18
- GridDGBipolynomialBasisSpace,
19
- GridSerendipityBasisSpace,
20
- GridDGSerendipityBasisSpace,
21
- GridDGPolynomialBasisSpace,
22
- )
23
- from .grid_3d_function_space import (
24
- GridTripolynomialBasisSpace,
25
- GridDGTripolynomialBasisSpace,
26
- Grid3DPiecewiseConstantBasis,
27
- Grid3DSerendipityBasisSpace,
28
- Grid3DDGSerendipityBasisSpace,
29
- Grid3DDGPolynomialBasisSpace,
30
- )
31
- from .trimesh_2d_function_space import (
32
- Trimesh2DPiecewiseConstantBasis,
33
- Trimesh2DPolynomialBasisSpace,
34
- Trimesh2DDGPolynomialBasisSpace,
35
- Trimesh2DNonConformingPolynomialBasisSpace,
36
- )
37
- from .tetmesh_function_space import (
38
- TetmeshPiecewiseConstantBasis,
39
- TetmeshPolynomialBasisSpace,
40
- TetmeshDGPolynomialBasisSpace,
41
- TetmeshNonConformingPolynomialBasisSpace,
42
- )
43
- from .quadmesh_2d_function_space import (
44
- Quadmesh2DPiecewiseConstantBasis,
45
- Quadmesh2DBipolynomialBasisSpace,
46
- Quadmesh2DDGBipolynomialBasisSpace,
47
- Quadmesh2DSerendipityBasisSpace,
48
- Quadmesh2DDGSerendipityBasisSpace,
49
- Quadmesh2DPolynomialBasisSpace,
50
- )
51
- from .hexmesh_function_space import (
52
- HexmeshPiecewiseConstantBasis,
53
- HexmeshTripolynomialBasisSpace,
54
- HexmeshDGTripolynomialBasisSpace,
55
- HexmeshSerendipityBasisSpace,
56
- HexmeshDGSerendipityBasisSpace,
57
- HexmeshPolynomialBasisSpace,
58
- )
59
30
 
60
31
  from .partition import SpacePartition, make_space_partition
61
32
  from .restriction import SpaceRestriction
@@ -105,17 +76,6 @@ def make_space_restriction(
105
76
  )
106
77
 
107
78
 
108
- class ElementBasis(Enum):
109
- """Choice of basis function to equip individual elements"""
110
-
111
- LAGRANGE = 0
112
- """Lagrange basis functions :math:`P_k` for simplices, tensor products :math:`Q_k` for squares and cubes"""
113
- SERENDIPITY = 1
114
- """Serendipity elements :math:`S_k`, corresponding to Lagrange nodes with interior points removed (for degree <= 3)"""
115
- NONCONFORMING_POLYNOMIAL = 2
116
- """Simplex Lagrange basis functions :math:`P_{kd}` embedded into non conforming reference elements (e.g. squares or cubes). Discontinuous only."""
117
-
118
-
119
79
  def make_polynomial_basis_space(
120
80
  geo: _geometry.Geometry,
121
81
  degree: int = 1,
@@ -141,110 +101,35 @@ def make_polynomial_basis_space(
141
101
 
142
102
  if element_basis is None:
143
103
  element_basis = ElementBasis.LAGRANGE
104
+ elif element_basis == ElementBasis.SERENDIPITY and degree == 1:
105
+ # Degree-1 serendipity is always equivalent to Lagrange
106
+ element_basis = ElementBasis.LAGRANGE
107
+
108
+ shape = get_shape_function(geo.reference_cell(), geo.dimension, degree, element_basis, family)
109
+
110
+ if discontinuous or degree == 0 or element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
111
+ return make_discontinuous_basis_space(geo, shape)
144
112
 
113
+ topology = None
145
114
  if isinstance(base_geo, _geometry.Grid2D):
146
- if degree == 0:
147
- return GridPiecewiseConstantBasis(geo)
148
-
149
- if element_basis == ElementBasis.SERENDIPITY and degree > 1:
150
- if discontinuous:
151
- return GridDGSerendipityBasisSpace(geo, degree=degree, family=family)
152
- else:
153
- return GridSerendipityBasisSpace(geo, degree=degree, family=family)
154
-
155
- if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
156
- return GridDGPolynomialBasisSpace(geo, degree=degree)
157
-
158
- if discontinuous:
159
- return GridDGBipolynomialBasisSpace(geo, degree=degree, family=family)
160
- else:
161
- return GridBipolynomialBasisSpace(geo, degree=degree, family=family)
162
-
163
- if isinstance(base_geo, _geometry.Grid3D):
164
- if degree == 0:
165
- return Grid3DPiecewiseConstantBasis(geo)
166
-
167
- if element_basis == ElementBasis.SERENDIPITY and degree > 1:
168
- if discontinuous:
169
- return Grid3DDGSerendipityBasisSpace(geo, degree=degree, family=family)
170
- else:
171
- return Grid3DSerendipityBasisSpace(geo, degree=degree, family=family)
172
-
173
- if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
174
- return Grid3DDGPolynomialBasisSpace(geo, degree=degree)
175
-
176
- if discontinuous:
177
- return GridDGTripolynomialBasisSpace(geo, degree=degree, family=family)
178
- else:
179
- return GridTripolynomialBasisSpace(geo, degree=degree, family=family)
180
-
181
- if isinstance(base_geo, _geometry.Trimesh2D):
182
- if degree == 0:
183
- return Trimesh2DPiecewiseConstantBasis(geo)
184
-
185
- if element_basis == ElementBasis.SERENDIPITY and degree > 2:
186
- raise NotImplementedError("Serendipity variant not implemented yet")
187
-
188
- if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
189
- return Trimesh2DNonConformingPolynomialBasisSpace(geo, degree=degree)
190
-
191
- if discontinuous:
192
- return Trimesh2DDGPolynomialBasisSpace(geo, degree=degree)
193
- else:
194
- return Trimesh2DPolynomialBasisSpace(geo, degree=degree)
195
-
196
- if isinstance(base_geo, _geometry.Tetmesh):
197
- if degree == 0:
198
- return TetmeshPiecewiseConstantBasis(geo)
199
-
200
- if element_basis == ElementBasis.SERENDIPITY and degree > 2:
201
- raise NotImplementedError("Serendipity variant not implemented yet")
202
-
203
- if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
204
- return TetmeshNonConformingPolynomialBasisSpace(geo, degree=degree)
205
-
206
- if discontinuous:
207
- return TetmeshDGPolynomialBasisSpace(geo, degree=degree)
208
- else:
209
- return TetmeshPolynomialBasisSpace(geo, degree=degree)
210
-
211
- if isinstance(base_geo, _geometry.Quadmesh2D):
212
- if degree == 0:
213
- return Quadmesh2DPiecewiseConstantBasis(geo)
214
-
215
- if element_basis == ElementBasis.SERENDIPITY and degree > 1:
216
- if discontinuous:
217
- return Quadmesh2DDGSerendipityBasisSpace(geo, degree=degree, family=family)
218
- else:
219
- return Quadmesh2DSerendipityBasisSpace(geo, degree=degree, family=family)
220
-
221
- if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
222
- return Quadmesh2DPolynomialBasisSpace(geo, degree=degree)
223
-
224
- if discontinuous:
225
- return Quadmesh2DDGBipolynomialBasisSpace(geo, degree=degree, family=family)
226
- else:
227
- return Quadmesh2DBipolynomialBasisSpace(geo, degree=degree, family=family)
228
-
229
- if isinstance(base_geo, _geometry.Hexmesh):
230
- if degree == 0:
231
- return HexmeshPiecewiseConstantBasis(geo)
232
-
233
- if element_basis == ElementBasis.SERENDIPITY and degree > 1:
234
- if discontinuous:
235
- return HexmeshDGSerendipityBasisSpace(geo, degree=degree, family=family)
236
- else:
237
- return HexmeshSerendipityBasisSpace(geo, degree=degree, family=family)
238
-
239
- if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
240
- return HexmeshPolynomialBasisSpace(geo, degree=degree)
241
-
242
- if discontinuous:
243
- return HexmeshDGTripolynomialBasisSpace(geo, degree=degree, family=family)
244
- else:
245
- return HexmeshTripolynomialBasisSpace(geo, degree=degree, family=family)
246
-
247
- raise NotImplementedError()
115
+ topology = make_grid_2d_space_topology(geo, shape)
116
+ elif isinstance(base_geo, _geometry.Grid3D):
117
+ topology = make_grid_3d_space_topology(geo, shape)
118
+ elif isinstance(base_geo, _geometry.Trimesh2D):
119
+ topology = make_trimesh_2d_space_topology(geo, shape)
120
+ elif isinstance(base_geo, _geometry.Tetmesh):
121
+ topology = make_tetmesh_space_topology(geo, shape)
122
+ elif isinstance(base_geo, _geometry.Quadmesh2D):
123
+ topology = make_quadmesh_2d_space_topology(geo, shape)
124
+ elif isinstance(base_geo, _geometry.Hexmesh):
125
+ topology = make_hexmesh_space_topology(geo, shape)
126
+ elif isinstance(base_geo, _geometry.Nanogrid):
127
+ topology = make_nanogrid_space_topology(geo, shape)
128
+
129
+ if topology is None:
130
+ raise NotImplementedError(f"Unsupported geometry type {geo.name}")
131
+
132
+ return ShapeBasisSpace(topology, shape)
248
133
 
249
134
 
250
135
  def make_collocated_function_space(
@@ -394,6 +394,40 @@ class TraceBasisSpace(BasisSpace):
394
394
  return self._topo == other._topo
395
395
 
396
396
 
397
+ class PiecewiseConstantBasisSpace(ShapeBasisSpace):
398
+ class Trace(TraceBasisSpace):
399
+ def make_node_coords_in_element(self):
400
+ # Makes the single node visible to all sides; useful for interpolating on boundaries
401
+ # For higher-order non-conforming elements direct interpolation on boundary is not possible,
402
+ # need to do proper integration then solve with mass matrix
403
+
404
+ CENTER_COORDS = Coords(self.geometry.reference_side().center())
405
+
406
+ @cache.dynamic_func(suffix=self._basis.name)
407
+ def trace_node_coords_in_element(
408
+ geo_side_arg: self.geometry.SideArg,
409
+ basis_arg: self.BasisArg,
410
+ element_index: ElementIndex,
411
+ node_index_in_elt: int,
412
+ ):
413
+ return CENTER_COORDS
414
+
415
+ return trace_node_coords_in_element
416
+
417
+ def trace(self):
418
+ return PiecewiseConstantBasisSpace.Trace(self)
419
+
420
+
421
+ def make_discontinuous_basis_space(geometry: Geometry, shape: ShapeFunction):
422
+ topology = DiscontinuousSpaceTopology(geometry, shape.NODES_PER_ELEMENT)
423
+
424
+ if shape.NODES_PER_ELEMENT == 1:
425
+ # piecewise-constant space
426
+ return PiecewiseConstantBasisSpace(topology=topology, shape=shape)
427
+
428
+ return ShapeBasisSpace(topology=topology, shape=shape)
429
+
430
+
397
431
  class PointBasisSpace(BasisSpace):
398
432
  """An unstructured :class:`BasisSpace` that is non-zero at a finite set of points only.
399
433
 
@@ -36,7 +36,7 @@ class CollocatedFunctionSpace(FunctionSpace):
36
36
  self.element_outer_weight_gradient = self._basis.make_element_outer_weight_gradient()
37
37
 
38
38
  # For backward compatibility
39
- if hasattr(basis, "node_grid"):
39
+ if hasattr(basis.topology, "node_grid"):
40
40
  self.node_grid = basis.node_grid
41
41
  if hasattr(basis, "node_triangulation"):
42
42
  self.node_triangulation = basis.node_triangulation
@@ -3,22 +3,22 @@ import numpy as np
3
3
  import warp as wp
4
4
  from warp.fem import cache
5
5
  from warp.fem.geometry import Grid2D
6
- from warp.fem.polynomial import Polynomial, is_closed
7
- from warp.fem.types import Coords, ElementIndex
6
+ from warp.fem.polynomial import is_closed
7
+ from warp.fem.types import ElementIndex
8
8
 
9
- from .basis_space import ShapeBasisSpace, TraceBasisSpace
10
9
  from .shape import (
11
- ConstantShapeFunction,
12
10
  ShapeFunction,
13
11
  SquareBipolynomialShapeFunctions,
14
- SquareNonConformingPolynomialShapeFunctions,
15
12
  SquareSerendipityShapeFunctions,
16
13
  )
17
- from .topology import DiscontinuousSpaceTopologyMixin, SpaceTopology, forward_base_topology
14
+ from .topology import SpaceTopology, forward_base_topology
18
15
 
19
16
 
20
17
  class Grid2DSpaceTopology(SpaceTopology):
21
18
  def __init__(self, grid: Grid2D, shape: ShapeFunction):
19
+ if not is_closed(shape.family):
20
+ raise ValueError("A closed polynomial family is required to define a continuous function space")
21
+
22
22
  super().__init__(grid, shape.NODES_PER_ELEMENT)
23
23
  self._shape = shape
24
24
 
@@ -37,53 +37,6 @@ class Grid2DSpaceTopology(SpaceTopology):
37
37
  return Grid2D._from_2d_index(x_stride, corner)
38
38
 
39
39
 
40
- class Grid2DDiscontinuousSpaceTopology(
41
- DiscontinuousSpaceTopologyMixin,
42
- Grid2DSpaceTopology,
43
- ):
44
- pass
45
-
46
-
47
- class Grid2DBasisSpace(ShapeBasisSpace):
48
- def __init__(self, topology: Grid2DSpaceTopology, shape: ShapeFunction):
49
- super().__init__(topology, shape)
50
-
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)
59
-
60
- if isinstance(grid, Grid2D):
61
- self.node_grid = self._node_grid
62
-
63
- def _node_grid(self):
64
- res = self._grid.res
65
-
66
- X = (np.arange(0, res[0], dtype=float) + 0.5) * self._grid.cell_size[0] + self._grid.origin[0]
67
- Y = (np.arange(0, res[1], dtype=float) + 0.5) * self._grid.cell_size[1] + self._grid.origin[1]
68
- return np.meshgrid(X, Y, indexing="ij")
69
-
70
- class Trace(TraceBasisSpace):
71
- @wp.func
72
- def _node_coords_in_element(
73
- side_arg: Grid2D.SideArg,
74
- basis_arg: Grid2DBasisSpace.BasisArg,
75
- element_index: ElementIndex,
76
- node_index_in_element: int,
77
- ):
78
- return Coords(0.5, 0.0, 0.0)
79
-
80
- def make_node_coords_in_element(self):
81
- return self._node_coords_in_element
82
-
83
- def trace(self):
84
- return GridPiecewiseConstantBasis.Trace(self)
85
-
86
-
87
40
  class GridBipolynomialSpaceTopology(Grid2DSpaceTopology):
88
41
  def __init__(self, grid: Grid2D, shape: SquareBipolynomialShapeFunctions):
89
42
  super().__init__(grid, shape)
@@ -119,30 +72,8 @@ class GridBipolynomialSpaceTopology(Grid2DSpaceTopology):
119
72
 
120
73
  return element_node_index
121
74
 
122
-
123
- class GridBipolynomialBasisSpace(Grid2DBasisSpace):
124
- def __init__(
125
- self,
126
- grid: Grid2D,
127
- degree: int,
128
- family: Polynomial,
129
- ):
130
- if family is None:
131
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
132
-
133
- if not is_closed(family):
134
- raise ValueError("A closed polynomial family is required to define a continuous function space")
135
-
136
- shape = SquareBipolynomialShapeFunctions(degree, family=family)
137
- topology = forward_base_topology(GridBipolynomialSpaceTopology, grid, shape)
138
-
139
- super().__init__(topology, shape)
140
-
141
- if isinstance(grid, Grid2D):
142
- self.node_grid = self._node_grid
143
-
144
75
  def _node_grid(self):
145
- res = self._grid.res
76
+ res = self.geometry.res
146
77
 
147
78
  cell_coords = np.array(self._shape.LOBATTO_COORDS)[:-1]
148
79
 
@@ -161,22 +92,6 @@ class GridBipolynomialBasisSpace(Grid2DBasisSpace):
161
92
  return np.meshgrid(X, Y, indexing="ij")
162
93
 
163
94
 
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
95
  class GridSerendipitySpaceTopology(Grid2DSpaceTopology):
181
96
  def __init__(self, grid: Grid2D, shape: SquareSerendipityShapeFunctions):
182
97
  super().__init__(grid, shape)
@@ -223,45 +138,11 @@ class GridSerendipitySpaceTopology(Grid2DSpaceTopology):
223
138
  return element_node_index
224
139
 
225
140
 
226
- class GridSerendipityBasisSpace(Grid2DBasisSpace):
227
- def __init__(
228
- self,
229
- grid: Grid2D,
230
- degree: int,
231
- family: Polynomial,
232
- ):
233
- if family is None:
234
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
235
-
236
- shape = SquareSerendipityShapeFunctions(degree, family=family)
237
- topology = forward_base_topology(GridSerendipitySpaceTopology, grid, shape=shape)
238
-
239
- super().__init__(topology=topology, shape=shape)
240
-
241
-
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
251
-
252
- shape = SquareSerendipityShapeFunctions(degree, family=family)
253
- topology = Grid2DDiscontinuousSpaceTopology(grid, shape=shape)
254
-
255
- super().__init__(topology=topology, shape=shape)
256
-
141
+ def make_grid_2d_space_topology(grid: Grid2D, shape: ShapeFunction):
142
+ if isinstance(shape, SquareSerendipityShapeFunctions):
143
+ return forward_base_topology(GridSerendipitySpaceTopology, grid, shape)
257
144
 
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)
145
+ if isinstance(shape, SquareBipolynomialShapeFunctions):
146
+ return forward_base_topology(GridBipolynomialSpaceTopology, grid, shape)
266
147
 
267
- super().__init__(topology=topology, shape=shape)
148
+ raise ValueError(f"Unsupported shape function {shape.name}")
@@ -3,23 +3,25 @@ import numpy as np
3
3
  import warp as wp
4
4
  from warp.fem import cache
5
5
  from warp.fem.geometry import Grid3D
6
- from warp.fem.polynomial import Polynomial, is_closed
7
- from warp.fem.types import Coords, ElementIndex
6
+ from warp.fem.polynomial import is_closed
7
+ from warp.fem.types import ElementIndex
8
8
 
9
- from .basis_space import ShapeBasisSpace, TraceBasisSpace
10
- from .shape import ConstantShapeFunction, ShapeFunction
11
- from .shape.cube_shape_function import (
12
- CubeNonConformingPolynomialShapeFunctions,
9
+ from .shape import (
13
10
  CubeSerendipityShapeFunctions,
14
11
  CubeTripolynomialShapeFunctions,
12
+ ShapeFunction,
15
13
  )
16
- from .topology import DiscontinuousSpaceTopologyMixin, SpaceTopology, forward_base_topology
14
+ from .topology import SpaceTopology, forward_base_topology
17
15
 
18
16
 
19
17
  class Grid3DSpaceTopology(SpaceTopology):
20
18
  def __init__(self, grid: Grid3D, shape: ShapeFunction):
19
+ if not is_closed(shape.family):
20
+ raise ValueError("A closed polynomial family is required to define a continuous function space")
21
+
21
22
  super().__init__(grid, shape.NODES_PER_ELEMENT)
22
23
  self._shape = shape
24
+ self._grid = grid
23
25
 
24
26
  @wp.func
25
27
  def _vertex_coords(vidx_in_cell: int):
@@ -37,52 +39,6 @@ class Grid3DSpaceTopology(SpaceTopology):
37
39
  return Grid3D._from_3d_index(strides, corner)
38
40
 
39
41
 
40
- class Grid3DDiscontinuousSpaceTopology(
41
- DiscontinuousSpaceTopologyMixin,
42
- Grid3DSpaceTopology,
43
- ):
44
- pass
45
-
46
-
47
- class Grid3DBasisSpace(ShapeBasisSpace):
48
- def __init__(self, topology: Grid3DSpaceTopology, shape: ShapeFunction):
49
- super().__init__(topology, shape)
50
-
51
- self._grid: Grid3D = topology.geometry
52
-
53
-
54
- class Grid3DPiecewiseConstantBasis(Grid3DBasisSpace):
55
- def __init__(self, grid: Grid3D):
56
- shape = ConstantShapeFunction(grid.reference_cell(), space_dimension=3)
57
- topology = Grid3DDiscontinuousSpaceTopology(grid, shape)
58
- super().__init__(shape=shape, topology=topology)
59
-
60
- if isinstance(grid, Grid3D):
61
- self.node_grid = self._node_grid
62
-
63
- def _node_grid(self):
64
- X = (np.arange(0, self.geometry.res[0], dtype=float) + 0.5) * self._grid.cell_size[0] + self._grid.bounds_lo[0]
65
- Y = (np.arange(0, self.geometry.res[1], dtype=float) + 0.5) * self._grid.cell_size[1] + self._grid.bounds_lo[1]
66
- Z = (np.arange(0, self.geometry.res[2], dtype=float) + 0.5) * self._grid.cell_size[2] + self._grid.bounds_lo[2]
67
- return np.meshgrid(X, Y, Z, indexing="ij")
68
-
69
- class Trace(TraceBasisSpace):
70
- @wp.func
71
- def _node_coords_in_element(
72
- side_arg: Grid3D.SideArg,
73
- basis_arg: Grid3DBasisSpace.BasisArg,
74
- element_index: ElementIndex,
75
- node_index_in_element: int,
76
- ):
77
- return Coords(0.5, 0.5, 0.0)
78
-
79
- def make_node_coords_in_element(self):
80
- return self._node_coords_in_element
81
-
82
- def trace(self):
83
- return Grid3DPiecewiseConstantBasis.Trace(self)
84
-
85
-
86
42
  class GridTripolynomialSpaceTopology(Grid3DSpaceTopology):
87
43
  def __init__(self, grid: Grid3D, shape: CubeTripolynomialShapeFunctions):
88
44
  super().__init__(grid, shape)
@@ -123,30 +79,8 @@ class GridTripolynomialSpaceTopology(Grid3DSpaceTopology):
123
79
 
124
80
  return element_node_index
125
81
 
126
-
127
- class GridTripolynomialBasisSpace(Grid3DBasisSpace):
128
- def __init__(
129
- self,
130
- grid: Grid3D,
131
- degree: int,
132
- family: Polynomial,
133
- ):
134
- if family is None:
135
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
136
-
137
- if not is_closed(family):
138
- raise ValueError("A closed polynomial family is required to define a continuous function space")
139
-
140
- shape = CubeTripolynomialShapeFunctions(degree, family=family)
141
- topology = forward_base_topology(GridTripolynomialSpaceTopology, grid, shape)
142
-
143
- super().__init__(topology, shape)
144
-
145
- if isinstance(grid, Grid3D):
146
- self.node_grid = self._node_grid
147
-
148
82
  def _node_grid(self):
149
- res = self._grid.res
83
+ res = self.geometry.res
150
84
 
151
85
  cell_coords = np.array(self._shape.LOBATTO_COORDS)[:-1]
152
86
 
@@ -171,44 +105,6 @@ class GridTripolynomialBasisSpace(Grid3DBasisSpace):
171
105
  return np.meshgrid(X, Y, Z, indexing="ij")
172
106
 
173
107
 
174
- class GridDGTripolynomialBasisSpace(Grid3DBasisSpace):
175
- def __init__(
176
- self,
177
- grid: Grid3D,
178
- degree: int,
179
- family: Polynomial,
180
- ):
181
- if family is None:
182
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
183
-
184
- shape = CubeTripolynomialShapeFunctions(degree, family=family)
185
- topology = Grid3DDiscontinuousSpaceTopology(grid, shape)
186
-
187
- super().__init__(shape=shape, topology=topology)
188
-
189
- def node_grid(self):
190
- res = self._grid.res
191
-
192
- cell_coords = np.array(self._shape.LOBATTO_COORDS)
193
-
194
- grid_coords_x = np.repeat(np.arange(0, res[0], dtype=float), len(cell_coords)) + np.tile(
195
- cell_coords, reps=res[0]
196
- )
197
- X = grid_coords_x * self._grid.cell_size[0] + self._grid.origin[0]
198
-
199
- grid_coords_y = np.repeat(np.arange(0, res[1], dtype=float), len(cell_coords)) + np.tile(
200
- cell_coords, reps=res[1]
201
- )
202
- Y = grid_coords_y * self._grid.cell_size[1] + self._grid.origin[1]
203
-
204
- grid_coords_z = np.repeat(np.arange(0, res[2], dtype=float), len(cell_coords)) + np.tile(
205
- cell_coords, reps=res[2]
206
- )
207
- Z = grid_coords_z * self._grid.cell_size[2] + self._grid.origin[2]
208
-
209
- return np.meshgrid(X, Y, Z, indexing="ij")
210
-
211
-
212
108
  class Grid3DSerendipitySpaceTopology(Grid3DSpaceTopology):
213
109
  def __init__(self, grid: Grid3D, shape: CubeSerendipityShapeFunctions):
214
110
  super().__init__(grid, shape)
@@ -261,45 +157,11 @@ class Grid3DSerendipitySpaceTopology(Grid3DSpaceTopology):
261
157
  return element_node_index
262
158
 
263
159
 
264
- class Grid3DSerendipityBasisSpace(Grid3DBasisSpace):
265
- def __init__(
266
- self,
267
- grid: Grid3D,
268
- degree: int,
269
- family: Polynomial,
270
- ):
271
- if family is None:
272
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
273
-
274
- shape = CubeSerendipityShapeFunctions(degree, family=family)
275
- topology = forward_base_topology(Grid3DSerendipitySpaceTopology, grid, shape=shape)
276
-
277
- super().__init__(topology=topology, shape=shape)
278
-
279
-
280
- class Grid3DDGSerendipityBasisSpace(Grid3DBasisSpace):
281
- def __init__(
282
- self,
283
- grid: Grid3D,
284
- degree: int,
285
- family: Polynomial,
286
- ):
287
- if family is None:
288
- family = Polynomial.LOBATTO_GAUSS_LEGENDRE
289
-
290
- shape = CubeSerendipityShapeFunctions(degree, family=family)
291
- topology = Grid3DDiscontinuousSpaceTopology(grid, shape=shape)
292
-
293
- super().__init__(topology=topology, shape=shape)
294
-
160
+ def make_grid_3d_space_topology(grid: Grid3D, shape: ShapeFunction):
161
+ if isinstance(shape, CubeSerendipityShapeFunctions):
162
+ return forward_base_topology(Grid3DSerendipitySpaceTopology, grid, shape)
295
163
 
296
- class Grid3DDGPolynomialBasisSpace(Grid3DBasisSpace):
297
- def __init__(
298
- self,
299
- grid: Grid3D,
300
- degree: int,
301
- ):
302
- shape = CubeNonConformingPolynomialShapeFunctions(degree)
303
- topology = Grid3DDiscontinuousSpaceTopology(grid, shape=shape)
164
+ if isinstance(shape, CubeTripolynomialShapeFunctions):
165
+ return forward_base_topology(GridTripolynomialSpaceTopology, grid, shape)
304
166
 
305
- super().__init__(topology=topology, shape=shape)
167
+ raise ValueError(f"Unsupported shape function {shape.name}")