warp-lang 1.4.1__py3-none-macosx_10_13_universal2.whl → 1.5.0__py3-none-macosx_10_13_universal2.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.
- warp/__init__.py +4 -0
- warp/autograd.py +43 -8
- warp/bin/libwarp-clang.dylib +0 -0
- warp/bin/libwarp.dylib +0 -0
- warp/build.py +21 -2
- warp/build_dll.py +23 -6
- warp/builtins.py +1920 -111
- warp/codegen.py +186 -62
- warp/config.py +2 -2
- warp/context.py +322 -73
- warp/examples/assets/pixel.jpg +0 -0
- warp/examples/benchmarks/benchmark_cloth_paddle.py +86 -0
- warp/examples/benchmarks/benchmark_gemm.py +121 -0
- warp/examples/benchmarks/benchmark_interop_paddle.py +158 -0
- warp/examples/benchmarks/benchmark_tile.py +179 -0
- warp/examples/core/example_dem.py +2 -1
- warp/examples/core/example_mesh_intersect.py +3 -3
- warp/examples/fem/example_adaptive_grid.py +37 -10
- warp/examples/fem/example_apic_fluid.py +3 -2
- warp/examples/fem/example_convection_diffusion_dg.py +4 -5
- warp/examples/fem/example_deformed_geometry.py +1 -1
- warp/examples/fem/example_diffusion_3d.py +47 -4
- warp/examples/fem/example_distortion_energy.py +220 -0
- warp/examples/fem/example_magnetostatics.py +127 -85
- warp/examples/fem/example_nonconforming_contact.py +5 -5
- warp/examples/fem/example_stokes.py +3 -1
- warp/examples/fem/example_streamlines.py +12 -19
- warp/examples/fem/utils.py +38 -15
- warp/examples/optim/example_walker.py +2 -2
- warp/examples/sim/example_cloth.py +2 -25
- warp/examples/sim/example_jacobian_ik.py +6 -2
- warp/examples/sim/example_quadruped.py +2 -1
- warp/examples/tile/example_tile_convolution.py +58 -0
- warp/examples/tile/example_tile_fft.py +47 -0
- warp/examples/tile/example_tile_filtering.py +105 -0
- warp/examples/tile/example_tile_matmul.py +79 -0
- warp/examples/tile/example_tile_mlp.py +375 -0
- warp/fem/__init__.py +8 -0
- warp/fem/cache.py +16 -12
- warp/fem/dirichlet.py +1 -1
- warp/fem/domain.py +44 -1
- warp/fem/field/__init__.py +1 -2
- warp/fem/field/field.py +31 -19
- warp/fem/field/nodal_field.py +101 -49
- warp/fem/field/virtual.py +794 -0
- warp/fem/geometry/__init__.py +2 -2
- warp/fem/geometry/deformed_geometry.py +3 -105
- warp/fem/geometry/element.py +13 -0
- warp/fem/geometry/geometry.py +165 -5
- warp/fem/geometry/grid_2d.py +3 -6
- warp/fem/geometry/grid_3d.py +31 -28
- warp/fem/geometry/hexmesh.py +3 -46
- warp/fem/geometry/nanogrid.py +3 -2
- warp/fem/geometry/{quadmesh_2d.py → quadmesh.py} +280 -159
- warp/fem/geometry/tetmesh.py +2 -43
- warp/fem/geometry/{trimesh_2d.py → trimesh.py} +354 -186
- warp/fem/integrate.py +683 -261
- warp/fem/linalg.py +404 -0
- warp/fem/operator.py +101 -18
- warp/fem/polynomial.py +5 -5
- warp/fem/quadrature/quadrature.py +45 -21
- warp/fem/space/__init__.py +45 -11
- warp/fem/space/basis_function_space.py +451 -0
- warp/fem/space/basis_space.py +58 -11
- warp/fem/space/function_space.py +146 -5
- warp/fem/space/grid_2d_function_space.py +80 -66
- warp/fem/space/grid_3d_function_space.py +113 -68
- warp/fem/space/hexmesh_function_space.py +96 -108
- warp/fem/space/nanogrid_function_space.py +62 -110
- warp/fem/space/quadmesh_function_space.py +208 -0
- warp/fem/space/shape/__init__.py +45 -7
- warp/fem/space/shape/cube_shape_function.py +328 -54
- warp/fem/space/shape/shape_function.py +10 -1
- warp/fem/space/shape/square_shape_function.py +328 -60
- warp/fem/space/shape/tet_shape_function.py +269 -19
- warp/fem/space/shape/triangle_shape_function.py +238 -19
- warp/fem/space/tetmesh_function_space.py +69 -37
- warp/fem/space/topology.py +38 -0
- warp/fem/space/trimesh_function_space.py +179 -0
- warp/fem/utils.py +6 -331
- warp/jax_experimental.py +3 -1
- warp/native/array.h +55 -40
- warp/native/builtin.h +124 -43
- warp/native/bvh.h +4 -0
- warp/native/coloring.cpp +600 -0
- warp/native/cuda_util.cpp +14 -0
- warp/native/cuda_util.h +2 -1
- warp/native/fabric.h +8 -0
- warp/native/hashgrid.h +4 -0
- warp/native/marching.cu +8 -0
- warp/native/mat.h +14 -3
- warp/native/mathdx.cpp +59 -0
- warp/native/mesh.h +4 -0
- warp/native/range.h +13 -1
- warp/native/reduce.cpp +9 -1
- warp/native/reduce.cu +7 -0
- warp/native/runlength_encode.cpp +9 -1
- warp/native/runlength_encode.cu +7 -1
- warp/native/scan.cpp +8 -0
- warp/native/scan.cu +8 -0
- warp/native/scan.h +8 -1
- warp/native/sparse.cpp +8 -0
- warp/native/sparse.cu +8 -0
- warp/native/temp_buffer.h +7 -0
- warp/native/tile.h +1857 -0
- warp/native/tile_gemm.h +341 -0
- warp/native/tile_reduce.h +210 -0
- warp/native/volume_builder.cu +8 -0
- warp/native/volume_builder.h +8 -0
- warp/native/warp.cpp +10 -2
- warp/native/warp.cu +369 -15
- warp/native/warp.h +12 -2
- warp/optim/adam.py +39 -4
- warp/paddle.py +29 -12
- warp/render/render_opengl.py +137 -65
- warp/sim/graph_coloring.py +292 -0
- warp/sim/integrator_euler.py +4 -2
- warp/sim/integrator_featherstone.py +115 -44
- warp/sim/integrator_vbd.py +6 -0
- warp/sim/model.py +90 -17
- warp/stubs.py +651 -85
- warp/tape.py +12 -7
- warp/tests/assets/pixel.npy +0 -0
- warp/tests/aux_test_instancing_gc.py +18 -0
- warp/tests/test_array.py +207 -48
- warp/tests/test_closest_point_edge_edge.py +8 -8
- warp/tests/test_codegen.py +120 -1
- warp/tests/test_codegen_instancing.py +30 -0
- warp/tests/test_collision.py +110 -0
- warp/tests/test_coloring.py +241 -0
- warp/tests/test_context.py +34 -0
- warp/tests/test_examples.py +18 -4
- warp/tests/test_fabricarray.py +33 -0
- warp/tests/test_fem.py +453 -113
- warp/tests/test_func.py +48 -1
- warp/tests/test_generics.py +52 -0
- warp/tests/test_iter.py +68 -0
- warp/tests/test_mat_scalar_ops.py +1 -1
- warp/tests/test_mesh_query_point.py +5 -4
- warp/tests/test_module_hashing.py +23 -0
- warp/tests/test_paddle.py +27 -87
- warp/tests/test_print.py +191 -1
- warp/tests/test_spatial.py +1 -1
- warp/tests/test_tile.py +700 -0
- warp/tests/test_tile_mathdx.py +144 -0
- warp/tests/test_tile_mlp.py +383 -0
- warp/tests/test_tile_reduce.py +374 -0
- warp/tests/test_tile_shared_memory.py +190 -0
- warp/tests/test_vbd.py +12 -20
- warp/tests/test_volume.py +43 -0
- warp/tests/unittest_suites.py +23 -2
- warp/tests/unittest_utils.py +4 -0
- warp/types.py +339 -73
- warp/utils.py +22 -1
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/METADATA +33 -7
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/RECORD +159 -132
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/WHEEL +1 -1
- warp/fem/field/test.py +0 -180
- warp/fem/field/trial.py +0 -183
- warp/fem/space/collocated_function_space.py +0 -102
- warp/fem/space/quadmesh_2d_function_space.py +0 -261
- warp/fem/space/trimesh_2d_function_space.py +0 -153
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/top_level.txt +0 -0
warp/fem/space/basis_space.py
CHANGED
|
@@ -13,10 +13,10 @@ from .topology import RegularDiscontinuousSpaceTopology, SpaceTopology
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class BasisSpace:
|
|
16
|
-
"""Interface class for defining a
|
|
16
|
+
"""Interface class for defining a shape function space over a geometry.
|
|
17
17
|
|
|
18
18
|
A basis space makes it easy to define multiple function spaces sharing the same basis (and thus nodes) but with different valuation functions;
|
|
19
|
-
however, it is not a required
|
|
19
|
+
however, it is not a required component of a function space.
|
|
20
20
|
|
|
21
21
|
See also: :func:`make_polynomial_basis_space`, :func:`make_collocated_function_space`
|
|
22
22
|
"""
|
|
@@ -40,6 +40,11 @@ class BasisSpace:
|
|
|
40
40
|
"""Underlying geometry of the basis space"""
|
|
41
41
|
return self._topology.geometry
|
|
42
42
|
|
|
43
|
+
@property
|
|
44
|
+
def value(self) -> ShapeFunction.Value:
|
|
45
|
+
"""Value type for the underlying shape functions"""
|
|
46
|
+
raise NotImplementedError()
|
|
47
|
+
|
|
43
48
|
def basis_arg_value(self, device) -> "BasisArg":
|
|
44
49
|
"""Value for the argument structure to be passed to device functions"""
|
|
45
50
|
return BasisSpace.BasisArg()
|
|
@@ -122,6 +127,20 @@ class BasisSpace:
|
|
|
122
127
|
def trace(self) -> "TraceBasisSpace":
|
|
123
128
|
return TraceBasisSpace(self)
|
|
124
129
|
|
|
130
|
+
@property
|
|
131
|
+
def weight_type(self):
|
|
132
|
+
if self.value is ShapeFunction.Value.Scalar:
|
|
133
|
+
return float
|
|
134
|
+
|
|
135
|
+
return cache.cached_vec_type(length=self.geometry.cell_dimension, dtype=float)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def weight_gradient_type(self):
|
|
139
|
+
if self.value is ShapeFunction.Value.Scalar:
|
|
140
|
+
return wp.vec(length=self.geometry.cell_dimension, dtype=float)
|
|
141
|
+
|
|
142
|
+
return cache.cached_mat_type(shape=(self.geometry.cell_dimension, self.geometry.cell_dimension), dtype=float)
|
|
143
|
+
|
|
125
144
|
|
|
126
145
|
class ShapeBasisSpace(BasisSpace):
|
|
127
146
|
"""Base class for defining shape-function-based basis spaces."""
|
|
@@ -130,6 +149,10 @@ class ShapeBasisSpace(BasisSpace):
|
|
|
130
149
|
super().__init__(topology)
|
|
131
150
|
self._shape = shape
|
|
132
151
|
|
|
152
|
+
if self.value is not ShapeFunction.Value.Scalar:
|
|
153
|
+
self.BasisArg = self.topology.TopologyArg
|
|
154
|
+
self.basis_arg_value = self.topology.topo_arg_value
|
|
155
|
+
|
|
133
156
|
self.ORDER = self._shape.ORDER
|
|
134
157
|
|
|
135
158
|
if hasattr(shape, "element_node_triangulation"):
|
|
@@ -148,6 +171,10 @@ class ShapeBasisSpace(BasisSpace):
|
|
|
148
171
|
"""Shape functions used for defining individual element basis"""
|
|
149
172
|
return self._shape
|
|
150
173
|
|
|
174
|
+
@property
|
|
175
|
+
def value(self) -> ShapeFunction.Value:
|
|
176
|
+
return self.shape.value
|
|
177
|
+
|
|
151
178
|
@property
|
|
152
179
|
def name(self):
|
|
153
180
|
return f"{self.topology.name}_{self._shape.name}"
|
|
@@ -169,6 +196,9 @@ class ShapeBasisSpace(BasisSpace):
|
|
|
169
196
|
def make_node_quadrature_weight(self):
|
|
170
197
|
shape_node_quadrature_weight = self._shape.make_node_quadrature_weight()
|
|
171
198
|
|
|
199
|
+
if shape_node_quadrature_weight is None:
|
|
200
|
+
return None
|
|
201
|
+
|
|
172
202
|
@cache.dynamic_func(suffix=self.name)
|
|
173
203
|
def node_quadrature_weight(
|
|
174
204
|
elt_arg: self.geometry.CellArg,
|
|
@@ -191,7 +221,11 @@ class ShapeBasisSpace(BasisSpace):
|
|
|
191
221
|
coords: Coords,
|
|
192
222
|
node_index_in_elt: int,
|
|
193
223
|
):
|
|
194
|
-
|
|
224
|
+
if wp.static(self.value == ShapeFunction.Value.Scalar):
|
|
225
|
+
return shape_element_inner_weight(coords, node_index_in_elt)
|
|
226
|
+
else:
|
|
227
|
+
sign = self.topology.element_node_sign(elt_arg, basis_arg, element_index, node_index_in_elt)
|
|
228
|
+
return sign * shape_element_inner_weight(coords, node_index_in_elt)
|
|
195
229
|
|
|
196
230
|
return element_inner_weight
|
|
197
231
|
|
|
@@ -206,13 +240,20 @@ class ShapeBasisSpace(BasisSpace):
|
|
|
206
240
|
coords: Coords,
|
|
207
241
|
node_index_in_elt: int,
|
|
208
242
|
):
|
|
209
|
-
|
|
243
|
+
if wp.static(self.value == ShapeFunction.Value.Scalar):
|
|
244
|
+
return shape_element_inner_weight_gradient(coords, node_index_in_elt)
|
|
245
|
+
else:
|
|
246
|
+
sign = self.topology.element_node_sign(elt_arg, basis_arg, element_index, node_index_in_elt)
|
|
247
|
+
return sign * shape_element_inner_weight_gradient(coords, node_index_in_elt)
|
|
210
248
|
|
|
211
249
|
return element_inner_weight_gradient
|
|
212
250
|
|
|
213
251
|
def make_trace_node_quadrature_weight(self, trace_basis):
|
|
214
252
|
shape_trace_node_quadrature_weight = self._shape.make_trace_node_quadrature_weight()
|
|
215
253
|
|
|
254
|
+
if shape_trace_node_quadrature_weight is None:
|
|
255
|
+
return None
|
|
256
|
+
|
|
216
257
|
@cache.dynamic_func(suffix=self.name)
|
|
217
258
|
def trace_node_quadrature_weight(
|
|
218
259
|
geo_side_arg: trace_basis.geometry.SideArg,
|
|
@@ -275,6 +316,10 @@ class TraceBasisSpace(BasisSpace):
|
|
|
275
316
|
def name(self):
|
|
276
317
|
return f"{self._basis.name}_Trace"
|
|
277
318
|
|
|
319
|
+
@property
|
|
320
|
+
def value(self) -> ShapeFunction.Value:
|
|
321
|
+
return self._basis.value
|
|
322
|
+
|
|
278
323
|
def make_node_coords_in_element(self):
|
|
279
324
|
node_coords_in_cell = self._basis.make_node_coords_in_element()
|
|
280
325
|
|
|
@@ -316,7 +361,7 @@ class TraceBasisSpace(BasisSpace):
|
|
|
316
361
|
):
|
|
317
362
|
cell_index, index_in_cell = self.topology.inner_cell_index(geo_side_arg, element_index, node_index_in_elt)
|
|
318
363
|
if cell_index == NULL_ELEMENT_INDEX:
|
|
319
|
-
return 0.0
|
|
364
|
+
return self.weight_type(0.0)
|
|
320
365
|
|
|
321
366
|
cell_coords = self.geometry.side_inner_cell_coords(geo_side_arg, element_index, coords)
|
|
322
367
|
|
|
@@ -344,7 +389,7 @@ class TraceBasisSpace(BasisSpace):
|
|
|
344
389
|
):
|
|
345
390
|
cell_index, index_in_cell = self.topology.outer_cell_index(geo_side_arg, element_index, node_index_in_elt)
|
|
346
391
|
if cell_index == NULL_ELEMENT_INDEX:
|
|
347
|
-
return 0.0
|
|
392
|
+
return self.weight_type(0.0)
|
|
348
393
|
|
|
349
394
|
cell_coords = self.geometry.side_outer_cell_coords(geo_side_arg, element_index, coords)
|
|
350
395
|
|
|
@@ -361,7 +406,6 @@ class TraceBasisSpace(BasisSpace):
|
|
|
361
406
|
|
|
362
407
|
def make_element_inner_weight_gradient(self):
|
|
363
408
|
cell_inner_weight_gradient = self._basis.make_element_inner_weight_gradient()
|
|
364
|
-
grad_vec_type = wp.vec(length=self.geometry.dimension, dtype=float)
|
|
365
409
|
|
|
366
410
|
@cache.dynamic_func(suffix=self._basis.name)
|
|
367
411
|
def trace_element_inner_weight_gradient(
|
|
@@ -373,7 +417,7 @@ class TraceBasisSpace(BasisSpace):
|
|
|
373
417
|
):
|
|
374
418
|
cell_index, index_in_cell = self.topology.inner_cell_index(geo_side_arg, element_index, node_index_in_elt)
|
|
375
419
|
if cell_index == NULL_ELEMENT_INDEX:
|
|
376
|
-
return
|
|
420
|
+
return self.weight_gradient_type(0.0)
|
|
377
421
|
|
|
378
422
|
cell_coords = self.geometry.side_inner_cell_coords(geo_side_arg, element_index, coords)
|
|
379
423
|
geo_cell_arg = self.geometry.side_to_cell_arg(geo_side_arg)
|
|
@@ -383,7 +427,6 @@ class TraceBasisSpace(BasisSpace):
|
|
|
383
427
|
|
|
384
428
|
def make_element_outer_weight_gradient(self):
|
|
385
429
|
cell_outer_weight_gradient = self._basis.make_element_outer_weight_gradient()
|
|
386
|
-
grad_vec_type = wp.vec(length=self.geometry.dimension, dtype=float)
|
|
387
430
|
|
|
388
431
|
@cache.dynamic_func(suffix=self._basis.name)
|
|
389
432
|
def trace_element_outer_weight_gradient(
|
|
@@ -395,7 +438,7 @@ class TraceBasisSpace(BasisSpace):
|
|
|
395
438
|
):
|
|
396
439
|
cell_index, index_in_cell = self.topology.outer_cell_index(geo_side_arg, element_index, node_index_in_elt)
|
|
397
440
|
if cell_index == NULL_ELEMENT_INDEX:
|
|
398
|
-
return
|
|
441
|
+
return self.weight_gradient_type(0.0)
|
|
399
442
|
|
|
400
443
|
cell_coords = self.geometry.side_outer_cell_coords(geo_side_arg, element_index, coords)
|
|
401
444
|
geo_cell_arg = self.geometry.side_to_cell_arg(geo_side_arg)
|
|
@@ -528,6 +571,10 @@ class PointBasisSpace(BasisSpace):
|
|
|
528
571
|
def name(self):
|
|
529
572
|
return f"{self._quadrature.name}_Point"
|
|
530
573
|
|
|
574
|
+
@property
|
|
575
|
+
def value(self) -> ShapeFunction.Value:
|
|
576
|
+
return ShapeFunction.Value.Scalar
|
|
577
|
+
|
|
531
578
|
def make_node_coords_in_element(self):
|
|
532
579
|
@cache.dynamic_func(suffix=self.name)
|
|
533
580
|
def node_coords_in_element(
|
|
@@ -571,7 +618,7 @@ class PointBasisSpace(BasisSpace):
|
|
|
571
618
|
return element_inner_weight
|
|
572
619
|
|
|
573
620
|
def make_element_inner_weight_gradient(self):
|
|
574
|
-
gradient_vec = cache.cached_vec_type(length=self.geometry.
|
|
621
|
+
gradient_vec = cache.cached_vec_type(length=self.geometry.cell_dimension, dtype=float)
|
|
575
622
|
|
|
576
623
|
@cache.dynamic_func(suffix=self.name)
|
|
577
624
|
def element_inner_weight_gradient(
|
warp/fem/space/function_space.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
import warp as wp
|
|
4
|
+
from warp.fem import cache
|
|
2
5
|
from warp.fem.geometry import Geometry
|
|
3
|
-
from warp.fem.types import Coords,
|
|
6
|
+
from warp.fem.types import Coords, ElementIndex, ElementKind, Sample, make_free_sample
|
|
4
7
|
|
|
5
8
|
from .topology import SpaceTopology
|
|
6
9
|
|
|
@@ -8,19 +11,39 @@ from .topology import SpaceTopology
|
|
|
8
11
|
class FunctionSpace:
|
|
9
12
|
"""
|
|
10
13
|
Interface class for function spaces, i.e. geometry + interpolation basis
|
|
14
|
+
|
|
15
|
+
The value of a function `f` at a position `x` is generally computed as
|
|
16
|
+
``f(x) = L(x)[sum_i f_i N_i(x)]``
|
|
17
|
+
with:
|
|
18
|
+
- ``f_i`` the value of the ith node's degrees-of-freedom (dof)
|
|
19
|
+
- ``N_i(x)`` the weight associated to the node at `x`
|
|
20
|
+
- ``L(x)`` local linear transformation from node-space to world-space
|
|
11
21
|
"""
|
|
12
22
|
|
|
13
23
|
dtype: type
|
|
14
24
|
"""Value type of the interpolation functions"""
|
|
15
25
|
|
|
26
|
+
dof_dtype: type
|
|
27
|
+
"""Data type of the degrees of freedom of each node"""
|
|
28
|
+
|
|
16
29
|
SpaceArg: wp.codegen.Struct
|
|
17
30
|
"""Structure containing arguments to be passed to device function"""
|
|
18
31
|
|
|
32
|
+
LocalValueMap: type
|
|
33
|
+
"""Type of the local map for transforming vector-valued functions from reference to world space"""
|
|
34
|
+
|
|
19
35
|
VALUE_DOF_COUNT: int
|
|
36
|
+
"""Number of degrees of freedom per value, as a Warp constant"""
|
|
37
|
+
|
|
38
|
+
NODE_DOF_COUNT: int
|
|
20
39
|
"""Number of degrees of freedom per node, as a Warp constant"""
|
|
21
40
|
|
|
41
|
+
ORDER: int
|
|
42
|
+
"""Polynomial degree of the function space, used to determine integration order"""
|
|
43
|
+
|
|
22
44
|
def __init__(self, topology: SpaceTopology):
|
|
23
45
|
self._topology = topology
|
|
46
|
+
self.ElementArg = self.topology.ElementArg
|
|
24
47
|
|
|
25
48
|
if self._topology.is_trace:
|
|
26
49
|
self.element_inner_reference_gradient_transform = self.geometry.side_inner_inverse_deformation_gradient
|
|
@@ -31,7 +54,7 @@ class FunctionSpace:
|
|
|
31
54
|
|
|
32
55
|
def node_count(self) -> int:
|
|
33
56
|
"""Number of nodes in the interpolation basis"""
|
|
34
|
-
|
|
57
|
+
return self.topology.node_count()
|
|
35
58
|
|
|
36
59
|
def space_arg_value(self, device) -> wp.codegen.StructInstance:
|
|
37
60
|
"""Value of the arguments to be passed to device functions"""
|
|
@@ -60,7 +83,7 @@ class FunctionSpace:
|
|
|
60
83
|
@property
|
|
61
84
|
def degree(self) -> int:
|
|
62
85
|
"""Maximum polynomial degree of the underlying basis"""
|
|
63
|
-
|
|
86
|
+
return self.ORDER
|
|
64
87
|
|
|
65
88
|
@property
|
|
66
89
|
def name(self):
|
|
@@ -83,9 +106,50 @@ class FunctionSpace:
|
|
|
83
106
|
"""
|
|
84
107
|
raise NotImplementedError
|
|
85
108
|
|
|
109
|
+
def gradient_valid(self) -> bool:
|
|
110
|
+
"""Whether gradient operator can be computed. Only for scalar and vector fields as higher-order tensors are not support yet"""
|
|
111
|
+
return not wp.types.type_is_matrix(self.dtype)
|
|
112
|
+
|
|
113
|
+
def divergence_valid(self) -> bool:
|
|
114
|
+
"""Whether divergence of this field can be computed. Only for vector and tensor fields with same dimension as embedding geometry"""
|
|
115
|
+
if wp.types.type_is_vector(self.dtype):
|
|
116
|
+
return wp.types.type_length(self.dtype) == self.geometry.dimension
|
|
117
|
+
if wp.types.type_is_matrix(self.dtype):
|
|
118
|
+
return self.dtype._shape_[0] == self.geometry.dimension
|
|
119
|
+
return False
|
|
120
|
+
|
|
86
121
|
@staticmethod
|
|
87
|
-
def
|
|
88
|
-
"""
|
|
122
|
+
def node_basis_element(dof_coord: int):
|
|
123
|
+
"""Basis element for node degrees of freedom.
|
|
124
|
+
|
|
125
|
+
Assumes 0 <= dof_coord < NODE_DOF_COUNT
|
|
126
|
+
"""
|
|
127
|
+
raise NotImplementedError
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def value_basis_element(dof_coord: int):
|
|
131
|
+
"""Basis element for the function space values
|
|
132
|
+
|
|
133
|
+
Assumes 0 <= dof_coord < VALUE_DOF_COUNT
|
|
134
|
+
"""
|
|
135
|
+
raise NotImplementedError
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def local_value_map_inner(
|
|
139
|
+
elt_arg: "SpaceTopology.ElementArg",
|
|
140
|
+
element_index: ElementIndex,
|
|
141
|
+
coords: Coords,
|
|
142
|
+
):
|
|
143
|
+
"""Builds the local value map transforming from node to world space"""
|
|
144
|
+
raise NotImplementedError
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def local_value_map_outer(
|
|
148
|
+
elt_arg: "SpaceTopology.ElementArg",
|
|
149
|
+
element_index: ElementIndex,
|
|
150
|
+
coords: Coords,
|
|
151
|
+
):
|
|
152
|
+
"""Builds the local value map transforming vector-valued from node to world space"""
|
|
89
153
|
raise NotImplementedError
|
|
90
154
|
|
|
91
155
|
@staticmethod
|
|
@@ -151,3 +215,80 @@ class FunctionSpace:
|
|
|
151
215
|
):
|
|
152
216
|
"""Outer weight gradient w.r.t reference space for a node at given coordinates"""
|
|
153
217
|
raise NotImplementedError
|
|
218
|
+
|
|
219
|
+
def space_value(
|
|
220
|
+
dof_value: "FunctionSpace.dof_dtype",
|
|
221
|
+
node_weight: Any,
|
|
222
|
+
local_value_map: "FunctionSpace.LocalValueMap",
|
|
223
|
+
):
|
|
224
|
+
"""
|
|
225
|
+
Assembles the world-space value of the function space
|
|
226
|
+
Args:
|
|
227
|
+
- dof_value: node value in the degrees-of-freedom basis
|
|
228
|
+
- node_weight: weight associated to the node, as given per `element_(inn|out)er_weight`
|
|
229
|
+
- local_value_map: local transformation from node space to world space, as given per `local_map_value_(inn|out)er`
|
|
230
|
+
"""
|
|
231
|
+
raise NotADirectoryError
|
|
232
|
+
|
|
233
|
+
def space_gradient(
|
|
234
|
+
dof_value: "FunctionSpace.dof_dtype",
|
|
235
|
+
node_weight: Any,
|
|
236
|
+
local_value_map: "FunctionSpace.LocalValueMap",
|
|
237
|
+
grad_transform: Any,
|
|
238
|
+
):
|
|
239
|
+
"""
|
|
240
|
+
Assembles the world-space gradient of the function space
|
|
241
|
+
Args:
|
|
242
|
+
- dof_value: node value in the degrees-of-freedom basis
|
|
243
|
+
- node_weight_gradient: gradient of the weight associated to the node, as given per `element_(inn|out)er_weight_gradient`
|
|
244
|
+
- local_value_map: local transformation from node space to world space, as given per `local_map_value_(inn|out)er`
|
|
245
|
+
- grad_transform: transform mapping the reference space gradient to worls-space gradient (inverse deformation gradient)
|
|
246
|
+
"""
|
|
247
|
+
raise NotImplementedError
|
|
248
|
+
|
|
249
|
+
def space_divergence(
|
|
250
|
+
dof_value: "FunctionSpace.dof_dtype",
|
|
251
|
+
node_weight: Any,
|
|
252
|
+
local_value_map: "FunctionSpace.LocalValueMap",
|
|
253
|
+
grad_transform: Any,
|
|
254
|
+
):
|
|
255
|
+
""" "
|
|
256
|
+
Assembles the world-space divergence of the function space
|
|
257
|
+
Args:
|
|
258
|
+
- dof_value: node value in the degrees-of-freedom basis
|
|
259
|
+
- node_weight_gradient: gradient of the weight associated to the node, as given per `element_(inn|out)er_weight_gradient`
|
|
260
|
+
- local_value_map: local transformation from node space to world space, as given per `local_map_value_(inn|out)er`
|
|
261
|
+
- grad_transform: transform mapping the reference space gradient to worls-space gradient (inverse deformation gradient)
|
|
262
|
+
"""
|
|
263
|
+
raise NotImplementedError
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def node_dof_value(
|
|
267
|
+
elt_arg: "FunctionSpace.ElementArg",
|
|
268
|
+
space_arg: "FunctionSpace.SpaceArg",
|
|
269
|
+
element_index: ElementIndex,
|
|
270
|
+
node_index_in_elt: int,
|
|
271
|
+
space_value: "FunctionSpace.dtype",
|
|
272
|
+
):
|
|
273
|
+
"""Converts space value to node degrees of freedom"""
|
|
274
|
+
raise NotImplementedError
|
|
275
|
+
|
|
276
|
+
def _make_side_inner_inverse_deformation_gradient(self):
|
|
277
|
+
@cache.dynamic_func(suffix=self.name)
|
|
278
|
+
def side_inner_inverse_deformation_gradient(args: self.ElementArg, s: Sample):
|
|
279
|
+
cell_index = self.side_inner_cell_index(args, s.element_index)
|
|
280
|
+
cell_coords = self.side_inner_cell_coords(args, s.element_index, s.element_coords)
|
|
281
|
+
cell_arg = self.side_to_cell_arg(args)
|
|
282
|
+
return self.geometry.cell_inverse_deformation_gradient(cell_arg, make_free_sample(cell_index, cell_coords))
|
|
283
|
+
|
|
284
|
+
return side_inner_inverse_deformation_gradient
|
|
285
|
+
|
|
286
|
+
def _make_side_outer_inverse_deformation_gradient(self):
|
|
287
|
+
@cache.dynamic_func(suffix=self.name)
|
|
288
|
+
def side_outer_inverse_deformation_gradient(args: self.ElementArg, s: Sample):
|
|
289
|
+
cell_index = self.side_outer_cell_index(args, s.element_index)
|
|
290
|
+
cell_coords = self.side_outer_cell_coords(args, s.element_index, s.element_coords)
|
|
291
|
+
cell_arg = self.side_to_cell_arg(args)
|
|
292
|
+
return self.geometry.cell_inverse_deformation_gradient(cell_arg, make_free_sample(cell_index, cell_coords))
|
|
293
|
+
|
|
294
|
+
return side_outer_inverse_deformation_gradient
|
|
@@ -4,23 +4,83 @@ import warp as wp
|
|
|
4
4
|
from warp.fem import cache
|
|
5
5
|
from warp.fem.geometry import Grid2D
|
|
6
6
|
from warp.fem.polynomial import is_closed
|
|
7
|
-
from warp.fem.types import ElementIndex
|
|
7
|
+
from warp.fem.types import NULL_NODE_INDEX, ElementIndex
|
|
8
8
|
|
|
9
|
-
from .shape import
|
|
10
|
-
ShapeFunction,
|
|
11
|
-
SquareBipolynomialShapeFunctions,
|
|
12
|
-
SquareSerendipityShapeFunctions,
|
|
13
|
-
)
|
|
9
|
+
from .shape import SquareBipolynomialShapeFunctions, SquareShapeFunction
|
|
14
10
|
from .topology import SpaceTopology, forward_base_topology
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
class Grid2DSpaceTopology(SpaceTopology):
|
|
18
|
-
def __init__(self, grid: Grid2D, shape:
|
|
19
|
-
if not is_closed(shape.family):
|
|
20
|
-
raise ValueError("A closed polynomial family is required to define a continuous function space")
|
|
21
|
-
|
|
22
|
-
super().__init__(grid, shape.NODES_PER_ELEMENT)
|
|
14
|
+
def __init__(self, grid: Grid2D, shape: SquareShapeFunction):
|
|
23
15
|
self._shape = shape
|
|
16
|
+
super().__init__(grid, shape.NODES_PER_ELEMENT)
|
|
17
|
+
|
|
18
|
+
self.element_node_index = self._make_element_node_index()
|
|
19
|
+
|
|
20
|
+
TopologyArg = Grid2D.SideArg
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def name(self):
|
|
24
|
+
return f"{self.geometry.name}_{self._shape.name}"
|
|
25
|
+
|
|
26
|
+
def topo_arg_value(self, device):
|
|
27
|
+
return self.geometry.side_arg_value(device)
|
|
28
|
+
|
|
29
|
+
def node_count(self) -> int:
|
|
30
|
+
return (
|
|
31
|
+
self.geometry.vertex_count() * self._shape.VERTEX_NODE_COUNT
|
|
32
|
+
+ self.geometry.side_count() * self._shape.EDGE_NODE_COUNT
|
|
33
|
+
+ self.geometry.cell_count() * self._shape.INTERIOR_NODE_COUNT
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def _make_element_node_index(self):
|
|
37
|
+
VERTEX_NODE_COUNT = self._shape.VERTEX_NODE_COUNT
|
|
38
|
+
EDGE_NODE_COUNT = self._shape.EDGE_NODE_COUNT
|
|
39
|
+
INTERIOR_NODE_COUNT = self._shape.INTERIOR_NODE_COUNT
|
|
40
|
+
|
|
41
|
+
@cache.dynamic_func(suffix=self.name)
|
|
42
|
+
def element_node_index(
|
|
43
|
+
cell_arg: Grid2D.CellArg,
|
|
44
|
+
topo_arg: Grid2D.SideArg,
|
|
45
|
+
element_index: ElementIndex,
|
|
46
|
+
node_index_in_elt: int,
|
|
47
|
+
):
|
|
48
|
+
node_type, type_instance, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
|
|
49
|
+
|
|
50
|
+
if wp.static(VERTEX_NODE_COUNT > 0):
|
|
51
|
+
if node_type == SquareShapeFunction.VERTEX:
|
|
52
|
+
return (
|
|
53
|
+
Grid2DSpaceTopology._vertex_index(cell_arg, element_index, type_instance) * VERTEX_NODE_COUNT
|
|
54
|
+
+ type_index
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
res = cell_arg.res
|
|
58
|
+
vertex_count = (res[0] + 1) * (res[1] + 1)
|
|
59
|
+
global_offset = vertex_count
|
|
60
|
+
|
|
61
|
+
if wp.static(INTERIOR_NODE_COUNT > 0):
|
|
62
|
+
if node_type == SquareShapeFunction.INTERIOR:
|
|
63
|
+
return global_offset + element_index * INTERIOR_NODE_COUNT + type_index
|
|
64
|
+
|
|
65
|
+
cell_count = res[0] * res[1]
|
|
66
|
+
global_offset += INTERIOR_NODE_COUNT * cell_count
|
|
67
|
+
|
|
68
|
+
if wp.static(EDGE_NODE_COUNT > 0):
|
|
69
|
+
axis = 1 - (node_type - SquareShapeFunction.EDGE_X)
|
|
70
|
+
|
|
71
|
+
cell = Grid2D.get_cell(cell_arg.res, element_index)
|
|
72
|
+
origin = wp.vec2i(cell[Grid2D.ROTATION[axis, 0]] + type_instance, cell[Grid2D.ROTATION[axis, 1]])
|
|
73
|
+
|
|
74
|
+
side = Grid2D.Side(axis, origin)
|
|
75
|
+
side_index = Grid2D.side_index(topo_arg, side)
|
|
76
|
+
|
|
77
|
+
vertex_count = (res[0] + 1) * (res[1] + 1)
|
|
78
|
+
|
|
79
|
+
return global_offset + EDGE_NODE_COUNT * side_index + type_index
|
|
80
|
+
|
|
81
|
+
return NULL_NODE_INDEX # unreachable
|
|
82
|
+
|
|
83
|
+
return element_node_index
|
|
24
84
|
|
|
25
85
|
@wp.func
|
|
26
86
|
def _vertex_coords(vidx_in_cell: int):
|
|
@@ -37,10 +97,10 @@ class Grid2DSpaceTopology(SpaceTopology):
|
|
|
37
97
|
return Grid2D._from_2d_index(x_stride, corner)
|
|
38
98
|
|
|
39
99
|
|
|
40
|
-
class GridBipolynomialSpaceTopology(
|
|
100
|
+
class GridBipolynomialSpaceTopology(SpaceTopology):
|
|
41
101
|
def __init__(self, grid: Grid2D, shape: SquareBipolynomialShapeFunctions):
|
|
42
|
-
super().__init__(grid, shape)
|
|
43
|
-
|
|
102
|
+
super().__init__(grid, shape.NODES_PER_ELEMENT)
|
|
103
|
+
self._shape = shape
|
|
44
104
|
self.element_node_index = self._make_element_node_index()
|
|
45
105
|
|
|
46
106
|
def node_count(self) -> int:
|
|
@@ -52,7 +112,7 @@ class GridBipolynomialSpaceTopology(Grid2DSpaceTopology):
|
|
|
52
112
|
@cache.dynamic_func(suffix=self.name)
|
|
53
113
|
def element_node_index(
|
|
54
114
|
cell_arg: Grid2D.CellArg,
|
|
55
|
-
topo_arg:
|
|
115
|
+
topo_arg: self.TopologyArg,
|
|
56
116
|
element_index: ElementIndex,
|
|
57
117
|
node_index_in_elt: int,
|
|
58
118
|
):
|
|
@@ -92,57 +152,11 @@ class GridBipolynomialSpaceTopology(Grid2DSpaceTopology):
|
|
|
92
152
|
return np.meshgrid(X, Y, indexing="ij")
|
|
93
153
|
|
|
94
154
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
super().__init__(grid, shape)
|
|
98
|
-
|
|
99
|
-
self.element_node_index = self._make_element_node_index()
|
|
100
|
-
|
|
101
|
-
TopologyArg = Grid2D.SideArg
|
|
102
|
-
|
|
103
|
-
def topo_arg_value(self, device):
|
|
104
|
-
return self.geometry.side_arg_value(device)
|
|
105
|
-
|
|
106
|
-
def node_count(self) -> int:
|
|
107
|
-
return self.geometry.vertex_count() + (self._shape.ORDER - 1) * self.geometry.side_count()
|
|
108
|
-
|
|
109
|
-
def _make_element_node_index(self):
|
|
110
|
-
ORDER = self._shape.ORDER
|
|
111
|
-
|
|
112
|
-
@cache.dynamic_func(suffix=self.name)
|
|
113
|
-
def element_node_index(
|
|
114
|
-
cell_arg: Grid2D.CellArg,
|
|
115
|
-
topo_arg: Grid2D.SideArg,
|
|
116
|
-
element_index: ElementIndex,
|
|
117
|
-
node_index_in_elt: int,
|
|
118
|
-
):
|
|
119
|
-
node_type, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
|
|
120
|
-
|
|
121
|
-
if node_type == SquareSerendipityShapeFunctions.VERTEX:
|
|
122
|
-
return Grid2DSpaceTopology._vertex_index(cell_arg, element_index, type_index)
|
|
123
|
-
|
|
124
|
-
side_offset, index_in_side = SquareSerendipityShapeFunctions.side_offset_and_index(type_index)
|
|
125
|
-
axis = 1 - (node_type - SquareSerendipityShapeFunctions.EDGE_X)
|
|
126
|
-
|
|
127
|
-
cell = Grid2D.get_cell(cell_arg.res, element_index)
|
|
128
|
-
origin = wp.vec2i(cell[Grid2D.ROTATION[axis, 0]] + side_offset, cell[Grid2D.ROTATION[axis, 1]])
|
|
129
|
-
|
|
130
|
-
side = Grid2D.Side(axis, origin)
|
|
131
|
-
side_index = Grid2D.side_index(topo_arg, side)
|
|
132
|
-
|
|
133
|
-
res = cell_arg.res
|
|
134
|
-
vertex_count = (res[0] + 1) * (res[1] + 1)
|
|
135
|
-
|
|
136
|
-
return vertex_count + (ORDER - 1) * side_index + index_in_side
|
|
137
|
-
|
|
138
|
-
return element_node_index
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def make_grid_2d_space_topology(grid: Grid2D, shape: ShapeFunction):
|
|
142
|
-
if isinstance(shape, SquareSerendipityShapeFunctions):
|
|
143
|
-
return forward_base_topology(GridSerendipitySpaceTopology, grid, shape)
|
|
144
|
-
|
|
145
|
-
if isinstance(shape, SquareBipolynomialShapeFunctions):
|
|
155
|
+
def make_grid_2d_space_topology(grid: Grid2D, shape: SquareShapeFunction):
|
|
156
|
+
if isinstance(shape, SquareBipolynomialShapeFunctions) and is_closed(shape.family):
|
|
146
157
|
return forward_base_topology(GridBipolynomialSpaceTopology, grid, shape)
|
|
147
158
|
|
|
159
|
+
if isinstance(shape, SquareShapeFunction):
|
|
160
|
+
return forward_base_topology(Grid2DSpaceTopology, grid, shape)
|
|
161
|
+
|
|
148
162
|
raise ValueError(f"Unsupported shape function {shape.name}")
|