warp-lang 1.0.1__py3-none-manylinux2014_x86_64.whl → 1.1.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.
- warp/__init__.py +108 -97
- warp/__init__.pyi +1 -1
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +115 -113
- warp/build_dll.py +383 -375
- warp/builtins.py +3425 -3354
- warp/codegen.py +2878 -2792
- warp/config.py +40 -36
- warp/constants.py +45 -45
- warp/context.py +5194 -5102
- warp/dlpack.py +442 -442
- warp/examples/__init__.py +16 -16
- warp/examples/assets/bear.usd +0 -0
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/assets/cartpole.urdf +110 -110
- warp/examples/assets/crazyflie.usd +0 -0
- warp/examples/assets/cube.usd +0 -0
- warp/examples/assets/nv_ant.xml +92 -92
- warp/examples/assets/nv_humanoid.xml +183 -183
- warp/examples/assets/quadruped.urdf +267 -267
- warp/examples/assets/rocks.nvdb +0 -0
- warp/examples/assets/rocks.usd +0 -0
- warp/examples/assets/sphere.usd +0 -0
- warp/examples/benchmarks/benchmark_api.py +383 -383
- warp/examples/benchmarks/benchmark_cloth.py +278 -279
- warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -88
- warp/examples/benchmarks/benchmark_cloth_jax.py +97 -100
- warp/examples/benchmarks/benchmark_cloth_numba.py +146 -142
- warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -77
- warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -86
- warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -112
- warp/examples/benchmarks/benchmark_cloth_warp.py +146 -146
- warp/examples/benchmarks/benchmark_launches.py +295 -295
- warp/examples/browse.py +29 -28
- warp/examples/core/example_dem.py +234 -221
- warp/examples/core/example_fluid.py +293 -267
- warp/examples/core/example_graph_capture.py +144 -129
- warp/examples/core/example_marching_cubes.py +188 -176
- warp/examples/core/example_mesh.py +174 -154
- warp/examples/core/example_mesh_intersect.py +205 -193
- warp/examples/core/example_nvdb.py +176 -169
- warp/examples/core/example_raycast.py +105 -89
- warp/examples/core/example_raymarch.py +199 -178
- warp/examples/core/example_render_opengl.py +185 -141
- warp/examples/core/example_sph.py +405 -389
- warp/examples/core/example_torch.py +222 -181
- warp/examples/core/example_wave.py +263 -249
- warp/examples/fem/bsr_utils.py +378 -380
- warp/examples/fem/example_apic_fluid.py +407 -391
- warp/examples/fem/example_convection_diffusion.py +182 -168
- warp/examples/fem/example_convection_diffusion_dg.py +219 -209
- warp/examples/fem/example_convection_diffusion_dg0.py +204 -194
- warp/examples/fem/example_deformed_geometry.py +177 -159
- warp/examples/fem/example_diffusion.py +201 -173
- warp/examples/fem/example_diffusion_3d.py +177 -152
- warp/examples/fem/example_diffusion_mgpu.py +221 -214
- warp/examples/fem/example_mixed_elasticity.py +244 -222
- warp/examples/fem/example_navier_stokes.py +259 -243
- warp/examples/fem/example_stokes.py +220 -192
- warp/examples/fem/example_stokes_transfer.py +265 -249
- warp/examples/fem/mesh_utils.py +133 -109
- warp/examples/fem/plot_utils.py +292 -287
- warp/examples/optim/example_bounce.py +260 -248
- warp/examples/optim/example_cloth_throw.py +222 -210
- warp/examples/optim/example_diffray.py +566 -535
- warp/examples/optim/example_drone.py +864 -835
- warp/examples/optim/example_inverse_kinematics.py +176 -169
- warp/examples/optim/example_inverse_kinematics_torch.py +185 -170
- warp/examples/optim/example_spring_cage.py +239 -234
- warp/examples/optim/example_trajectory.py +223 -201
- warp/examples/optim/example_walker.py +306 -292
- warp/examples/sim/example_cartpole.py +139 -128
- warp/examples/sim/example_cloth.py +196 -184
- warp/examples/sim/example_granular.py +124 -113
- warp/examples/sim/example_granular_collision_sdf.py +197 -185
- warp/examples/sim/example_jacobian_ik.py +236 -213
- warp/examples/sim/example_particle_chain.py +118 -106
- warp/examples/sim/example_quadruped.py +193 -179
- warp/examples/sim/example_rigid_chain.py +197 -189
- warp/examples/sim/example_rigid_contact.py +189 -176
- warp/examples/sim/example_rigid_force.py +127 -126
- warp/examples/sim/example_rigid_gyroscopic.py +109 -97
- warp/examples/sim/example_rigid_soft_contact.py +134 -124
- warp/examples/sim/example_soft_body.py +190 -178
- warp/fabric.py +337 -335
- warp/fem/__init__.py +60 -27
- warp/fem/cache.py +401 -388
- warp/fem/dirichlet.py +178 -179
- warp/fem/domain.py +262 -263
- warp/fem/field/__init__.py +100 -101
- warp/fem/field/field.py +148 -149
- warp/fem/field/nodal_field.py +298 -299
- warp/fem/field/restriction.py +22 -21
- warp/fem/field/test.py +180 -181
- warp/fem/field/trial.py +183 -183
- warp/fem/geometry/__init__.py +15 -19
- warp/fem/geometry/closest_point.py +69 -70
- warp/fem/geometry/deformed_geometry.py +270 -271
- warp/fem/geometry/element.py +744 -744
- warp/fem/geometry/geometry.py +184 -186
- warp/fem/geometry/grid_2d.py +380 -373
- warp/fem/geometry/grid_3d.py +441 -435
- warp/fem/geometry/hexmesh.py +953 -953
- warp/fem/geometry/partition.py +374 -376
- warp/fem/geometry/quadmesh_2d.py +532 -532
- warp/fem/geometry/tetmesh.py +840 -840
- warp/fem/geometry/trimesh_2d.py +577 -577
- warp/fem/integrate.py +1630 -1615
- warp/fem/operator.py +190 -191
- warp/fem/polynomial.py +214 -213
- warp/fem/quadrature/__init__.py +2 -2
- warp/fem/quadrature/pic_quadrature.py +243 -245
- warp/fem/quadrature/quadrature.py +295 -294
- warp/fem/space/__init__.py +294 -292
- warp/fem/space/basis_space.py +488 -489
- warp/fem/space/collocated_function_space.py +100 -105
- warp/fem/space/dof_mapper.py +236 -236
- warp/fem/space/function_space.py +148 -145
- warp/fem/space/grid_2d_function_space.py +267 -267
- warp/fem/space/grid_3d_function_space.py +305 -306
- warp/fem/space/hexmesh_function_space.py +350 -352
- warp/fem/space/partition.py +350 -350
- warp/fem/space/quadmesh_2d_function_space.py +368 -369
- warp/fem/space/restriction.py +158 -160
- warp/fem/space/shape/__init__.py +13 -15
- warp/fem/space/shape/cube_shape_function.py +738 -738
- warp/fem/space/shape/shape_function.py +102 -103
- warp/fem/space/shape/square_shape_function.py +611 -611
- warp/fem/space/shape/tet_shape_function.py +565 -567
- warp/fem/space/shape/triangle_shape_function.py +429 -429
- warp/fem/space/tetmesh_function_space.py +294 -292
- warp/fem/space/topology.py +297 -295
- warp/fem/space/trimesh_2d_function_space.py +223 -221
- warp/fem/types.py +77 -77
- warp/fem/utils.py +495 -495
- warp/jax.py +166 -141
- warp/jax_experimental.py +341 -339
- warp/native/array.h +1072 -1025
- warp/native/builtin.h +1560 -1560
- warp/native/bvh.cpp +398 -398
- warp/native/bvh.cu +525 -525
- warp/native/bvh.h +429 -429
- warp/native/clang/clang.cpp +495 -464
- warp/native/crt.cpp +31 -31
- warp/native/crt.h +334 -334
- warp/native/cuda_crt.h +1049 -1049
- warp/native/cuda_util.cpp +549 -540
- warp/native/cuda_util.h +288 -203
- warp/native/cutlass_gemm.cpp +34 -34
- warp/native/cutlass_gemm.cu +372 -372
- warp/native/error.cpp +66 -66
- warp/native/error.h +27 -27
- warp/native/fabric.h +228 -228
- warp/native/hashgrid.cpp +301 -278
- warp/native/hashgrid.cu +78 -77
- warp/native/hashgrid.h +227 -227
- warp/native/initializer_array.h +32 -32
- warp/native/intersect.h +1204 -1204
- warp/native/intersect_adj.h +365 -365
- warp/native/intersect_tri.h +322 -322
- warp/native/marching.cpp +2 -2
- warp/native/marching.cu +497 -497
- warp/native/marching.h +2 -2
- warp/native/mat.h +1498 -1498
- warp/native/matnn.h +333 -333
- warp/native/mesh.cpp +203 -203
- warp/native/mesh.cu +293 -293
- warp/native/mesh.h +1887 -1887
- warp/native/nanovdb/NanoVDB.h +4782 -4782
- warp/native/nanovdb/PNanoVDB.h +2553 -2553
- warp/native/nanovdb/PNanoVDBWrite.h +294 -294
- warp/native/noise.h +850 -850
- warp/native/quat.h +1084 -1084
- warp/native/rand.h +299 -299
- warp/native/range.h +108 -108
- warp/native/reduce.cpp +156 -156
- warp/native/reduce.cu +348 -348
- warp/native/runlength_encode.cpp +61 -61
- warp/native/runlength_encode.cu +46 -46
- warp/native/scan.cpp +30 -30
- warp/native/scan.cu +36 -36
- warp/native/scan.h +7 -7
- warp/native/solid_angle.h +442 -442
- warp/native/sort.cpp +94 -94
- warp/native/sort.cu +97 -97
- warp/native/sort.h +14 -14
- warp/native/sparse.cpp +337 -337
- warp/native/sparse.cu +544 -544
- warp/native/spatial.h +630 -630
- warp/native/svd.h +562 -562
- warp/native/temp_buffer.h +30 -30
- warp/native/vec.h +1132 -1132
- warp/native/volume.cpp +297 -297
- warp/native/volume.cu +32 -32
- warp/native/volume.h +538 -538
- warp/native/volume_builder.cu +425 -425
- warp/native/volume_builder.h +19 -19
- warp/native/warp.cpp +1057 -1052
- warp/native/warp.cu +2943 -2828
- warp/native/warp.h +313 -305
- warp/optim/__init__.py +9 -9
- warp/optim/adam.py +120 -120
- warp/optim/linear.py +1104 -939
- warp/optim/sgd.py +104 -92
- warp/render/__init__.py +10 -10
- warp/render/render_opengl.py +3217 -3204
- warp/render/render_usd.py +768 -749
- warp/render/utils.py +152 -150
- warp/sim/__init__.py +52 -59
- warp/sim/articulation.py +685 -685
- warp/sim/collide.py +1594 -1590
- warp/sim/import_mjcf.py +489 -481
- warp/sim/import_snu.py +220 -221
- warp/sim/import_urdf.py +536 -516
- warp/sim/import_usd.py +887 -881
- warp/sim/inertia.py +316 -317
- warp/sim/integrator.py +234 -233
- warp/sim/integrator_euler.py +1956 -1956
- warp/sim/integrator_featherstone.py +1910 -1991
- warp/sim/integrator_xpbd.py +3294 -3312
- warp/sim/model.py +4473 -4314
- warp/sim/particles.py +113 -112
- warp/sim/render.py +417 -403
- warp/sim/utils.py +413 -410
- warp/sparse.py +1227 -1227
- warp/stubs.py +2109 -2469
- warp/tape.py +1162 -225
- warp/tests/__init__.py +1 -1
- warp/tests/__main__.py +4 -4
- warp/tests/assets/torus.usda +105 -105
- warp/tests/aux_test_class_kernel.py +26 -26
- warp/tests/aux_test_compile_consts_dummy.py +10 -10
- warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -21
- warp/tests/aux_test_dependent.py +22 -22
- warp/tests/aux_test_grad_customs.py +23 -23
- warp/tests/aux_test_reference.py +11 -11
- warp/tests/aux_test_reference_reference.py +10 -10
- warp/tests/aux_test_square.py +17 -17
- warp/tests/aux_test_unresolved_func.py +14 -14
- warp/tests/aux_test_unresolved_symbol.py +14 -14
- warp/tests/disabled_kinematics.py +239 -239
- warp/tests/run_coverage_serial.py +31 -31
- warp/tests/test_adam.py +157 -157
- warp/tests/test_arithmetic.py +1124 -1124
- warp/tests/test_array.py +2417 -2326
- warp/tests/test_array_reduce.py +150 -150
- warp/tests/test_async.py +668 -656
- warp/tests/test_atomic.py +141 -141
- warp/tests/test_bool.py +204 -149
- warp/tests/test_builtins_resolution.py +1292 -1292
- warp/tests/test_bvh.py +164 -171
- warp/tests/test_closest_point_edge_edge.py +228 -228
- warp/tests/test_codegen.py +566 -553
- warp/tests/test_compile_consts.py +97 -101
- warp/tests/test_conditional.py +246 -246
- warp/tests/test_copy.py +232 -215
- warp/tests/test_ctypes.py +632 -632
- warp/tests/test_dense.py +67 -67
- warp/tests/test_devices.py +91 -98
- warp/tests/test_dlpack.py +530 -529
- warp/tests/test_examples.py +400 -378
- warp/tests/test_fabricarray.py +955 -955
- warp/tests/test_fast_math.py +62 -54
- warp/tests/test_fem.py +1277 -1278
- warp/tests/test_fp16.py +130 -130
- warp/tests/test_func.py +338 -337
- warp/tests/test_generics.py +571 -571
- warp/tests/test_grad.py +746 -640
- warp/tests/test_grad_customs.py +333 -336
- warp/tests/test_hash_grid.py +210 -164
- warp/tests/test_import.py +39 -39
- warp/tests/test_indexedarray.py +1134 -1134
- warp/tests/test_intersect.py +67 -67
- warp/tests/test_jax.py +307 -307
- warp/tests/test_large.py +167 -164
- warp/tests/test_launch.py +354 -354
- warp/tests/test_lerp.py +261 -261
- warp/tests/test_linear_solvers.py +191 -171
- warp/tests/test_lvalue.py +421 -493
- warp/tests/test_marching_cubes.py +65 -65
- warp/tests/test_mat.py +1801 -1827
- warp/tests/test_mat_lite.py +115 -115
- warp/tests/test_mat_scalar_ops.py +2907 -2889
- warp/tests/test_math.py +126 -193
- warp/tests/test_matmul.py +500 -499
- warp/tests/test_matmul_lite.py +410 -410
- warp/tests/test_mempool.py +188 -190
- warp/tests/test_mesh.py +284 -324
- warp/tests/test_mesh_query_aabb.py +228 -241
- warp/tests/test_mesh_query_point.py +692 -702
- warp/tests/test_mesh_query_ray.py +292 -303
- warp/tests/test_mlp.py +276 -276
- warp/tests/test_model.py +110 -110
- warp/tests/test_modules_lite.py +39 -39
- warp/tests/test_multigpu.py +163 -163
- warp/tests/test_noise.py +248 -248
- warp/tests/test_operators.py +250 -250
- warp/tests/test_options.py +123 -125
- warp/tests/test_peer.py +133 -137
- warp/tests/test_pinned.py +78 -78
- warp/tests/test_print.py +54 -54
- warp/tests/test_quat.py +2086 -2086
- warp/tests/test_rand.py +288 -288
- warp/tests/test_reload.py +217 -217
- warp/tests/test_rounding.py +179 -179
- warp/tests/test_runlength_encode.py +190 -190
- warp/tests/test_sim_grad.py +243 -0
- warp/tests/test_sim_kinematics.py +91 -97
- warp/tests/test_smoothstep.py +168 -168
- warp/tests/test_snippet.py +305 -266
- warp/tests/test_sparse.py +468 -460
- warp/tests/test_spatial.py +2148 -2148
- warp/tests/test_streams.py +486 -473
- warp/tests/test_struct.py +710 -675
- warp/tests/test_tape.py +173 -148
- warp/tests/test_torch.py +743 -743
- warp/tests/test_transient_module.py +87 -87
- warp/tests/test_types.py +556 -659
- warp/tests/test_utils.py +490 -499
- warp/tests/test_vec.py +1264 -1268
- warp/tests/test_vec_lite.py +73 -73
- warp/tests/test_vec_scalar_ops.py +2099 -2099
- warp/tests/test_verify_fp.py +94 -94
- warp/tests/test_volume.py +737 -736
- warp/tests/test_volume_write.py +255 -265
- warp/tests/unittest_serial.py +37 -37
- warp/tests/unittest_suites.py +363 -359
- warp/tests/unittest_utils.py +603 -578
- warp/tests/unused_test_misc.py +71 -71
- warp/tests/walkthrough_debug.py +85 -85
- warp/thirdparty/appdirs.py +598 -598
- warp/thirdparty/dlpack.py +143 -143
- warp/thirdparty/unittest_parallel.py +566 -561
- warp/torch.py +321 -295
- warp/types.py +4504 -4450
- warp/utils.py +1008 -821
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/LICENSE.md +126 -126
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/METADATA +338 -400
- warp_lang-1.1.0.dist-info/RECORD +352 -0
- warp/examples/assets/cube.usda +0 -42
- warp/examples/assets/sphere.usda +0 -56
- warp/examples/assets/torus.usda +0 -105
- warp_lang-1.0.1.dist-info/RECORD +0 -352
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,429 +1,429 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from warp.fem
|
|
5
|
-
from warp.fem import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _triangle_node_index(tx: int, ty: int, degree: int):
|
|
9
|
-
VERTEX_NODE_COUNT = 3
|
|
10
|
-
SIDE_INTERIOR_NODE_COUNT = degree - 1
|
|
11
|
-
|
|
12
|
-
# Index in similar order to e.g. VTK
|
|
13
|
-
# First vertices, then edge (
|
|
14
|
-
|
|
15
|
-
if tx == 0:
|
|
16
|
-
if ty == 0:
|
|
17
|
-
return 0
|
|
18
|
-
elif ty == degree:
|
|
19
|
-
return 2
|
|
20
|
-
else:
|
|
21
|
-
edge_index = 2
|
|
22
|
-
return VERTEX_NODE_COUNT + SIDE_INTERIOR_NODE_COUNT * edge_index + (SIDE_INTERIOR_NODE_COUNT - ty)
|
|
23
|
-
elif ty == 0:
|
|
24
|
-
if tx == degree:
|
|
25
|
-
return 1
|
|
26
|
-
else:
|
|
27
|
-
edge_index = 0
|
|
28
|
-
return VERTEX_NODE_COUNT + SIDE_INTERIOR_NODE_COUNT * edge_index + tx - 1
|
|
29
|
-
elif tx + ty == degree:
|
|
30
|
-
edge_index = 1
|
|
31
|
-
return VERTEX_NODE_COUNT + SIDE_INTERIOR_NODE_COUNT * edge_index + ty - 1
|
|
32
|
-
|
|
33
|
-
vertex_edge_node_count = 3 * degree
|
|
34
|
-
return vertex_edge_node_count + _triangle_node_index(tx - 1, ty - 1, degree - 3)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class Triangle2DPolynomialShapeFunctions:
|
|
38
|
-
VERTEX = wp.constant(0)
|
|
39
|
-
EDGE = wp.constant(1)
|
|
40
|
-
INTERIOR = wp.constant(2)
|
|
41
|
-
|
|
42
|
-
def __init__(self, degree: int):
|
|
43
|
-
self.ORDER = wp.constant(degree)
|
|
44
|
-
|
|
45
|
-
self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 2) // 2)
|
|
46
|
-
self.NODES_PER_SIDE = wp.constant(degree + 1)
|
|
47
|
-
|
|
48
|
-
triangle_coords = np.empty((self.NODES_PER_ELEMENT, 2), dtype=int)
|
|
49
|
-
|
|
50
|
-
for tx in range(degree + 1):
|
|
51
|
-
for ty in range(degree + 1 - tx):
|
|
52
|
-
index = _triangle_node_index(tx, ty, degree)
|
|
53
|
-
triangle_coords[index] = [tx, ty]
|
|
54
|
-
|
|
55
|
-
CoordTypeVec = wp.mat(dtype=int, shape=(self.NODES_PER_ELEMENT, 2))
|
|
56
|
-
self.NODE_TRIANGLE_COORDS = wp.constant(CoordTypeVec(triangle_coords))
|
|
57
|
-
|
|
58
|
-
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
59
|
-
self._node_triangle_coordinates = self._get_node_triangle_coordinates()
|
|
60
|
-
|
|
61
|
-
@property
|
|
62
|
-
def name(self) -> str:
|
|
63
|
-
return f"Tri_P{self.ORDER}"
|
|
64
|
-
|
|
65
|
-
def _get_node_triangle_coordinates(self):
|
|
66
|
-
NODE_TRIANGLE_COORDS = self.NODE_TRIANGLE_COORDS
|
|
67
|
-
|
|
68
|
-
def node_triangle_coordinates(
|
|
69
|
-
node_index_in_elt: int,
|
|
70
|
-
):
|
|
71
|
-
return wp.vec2i(NODE_TRIANGLE_COORDS[node_index_in_elt, 0], NODE_TRIANGLE_COORDS[node_index_in_elt, 1])
|
|
72
|
-
|
|
73
|
-
return cache.get_func(node_triangle_coordinates, self.name)
|
|
74
|
-
|
|
75
|
-
def _get_node_type_and_type_index(self):
|
|
76
|
-
ORDER = self.ORDER
|
|
77
|
-
|
|
78
|
-
def node_type_and_index(
|
|
79
|
-
node_index_in_elt: int,
|
|
80
|
-
):
|
|
81
|
-
if node_index_in_elt < 3:
|
|
82
|
-
return Triangle2DPolynomialShapeFunctions.VERTEX, node_index_in_elt
|
|
83
|
-
|
|
84
|
-
if node_index_in_elt < 3 * ORDER:
|
|
85
|
-
return Triangle2DPolynomialShapeFunctions.EDGE, (node_index_in_elt - 3)
|
|
86
|
-
|
|
87
|
-
return Triangle2DPolynomialShapeFunctions.INTERIOR, (node_index_in_elt - 3 * ORDER)
|
|
88
|
-
|
|
89
|
-
return cache.get_func(node_type_and_index, self.name)
|
|
90
|
-
|
|
91
|
-
def make_node_coords_in_element(self):
|
|
92
|
-
ORDER = self.ORDER
|
|
93
|
-
|
|
94
|
-
def node_coords_in_element(
|
|
95
|
-
node_index_in_elt: int,
|
|
96
|
-
):
|
|
97
|
-
tri_coords = self._node_triangle_coordinates(node_index_in_elt)
|
|
98
|
-
cx = float(tri_coords[0]) / float(ORDER)
|
|
99
|
-
cy = float(tri_coords[1]) / float(ORDER)
|
|
100
|
-
return Coords(1.0 - cx - cy, cx, cy)
|
|
101
|
-
|
|
102
|
-
return cache.get_func(node_coords_in_element, self.name)
|
|
103
|
-
|
|
104
|
-
def make_node_quadrature_weight(self):
|
|
105
|
-
if self.ORDER == 3:
|
|
106
|
-
# P3 intrisic quadrature
|
|
107
|
-
vertex_weight = 1.0 / 30
|
|
108
|
-
edge_weight = 0.075
|
|
109
|
-
interior_weight = 0.45
|
|
110
|
-
elif self.ORDER == 2:
|
|
111
|
-
# Order 1, but optimized quadrature weights for monomials of order <= 4
|
|
112
|
-
vertex_weight = 0.022335964126
|
|
113
|
-
edge_weight = 0.310997369207
|
|
114
|
-
interior_weight = 0.0
|
|
115
|
-
else:
|
|
116
|
-
vertex_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
117
|
-
edge_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
118
|
-
interior_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
119
|
-
|
|
120
|
-
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
121
|
-
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
122
|
-
INTERIOR_WEIGHT = wp.constant(interior_weight)
|
|
123
|
-
|
|
124
|
-
@cache.dynamic_func(suffix=self.name)
|
|
125
|
-
def node_quadrature_weight(node_index_in_element: int):
|
|
126
|
-
node_type, type_index = self.node_type_and_type_index(node_index_in_element)
|
|
127
|
-
|
|
128
|
-
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
129
|
-
return VERTEX_WEIGHT
|
|
130
|
-
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
131
|
-
return EDGE_WEIGHT
|
|
132
|
-
|
|
133
|
-
return INTERIOR_WEIGHT
|
|
134
|
-
|
|
135
|
-
return node_quadrature_weight
|
|
136
|
-
|
|
137
|
-
def make_trace_node_quadrature_weight(self):
|
|
138
|
-
# Closed Newton-Cotes
|
|
139
|
-
if self.ORDER == 3:
|
|
140
|
-
vertex_weight = 1.0 / 8.0
|
|
141
|
-
edge_weight = 3.0 / 8.0
|
|
142
|
-
elif self.ORDER == 2:
|
|
143
|
-
vertex_weight = 1.0 / 6.0
|
|
144
|
-
edge_weight = 2.0 / 3.0
|
|
145
|
-
else:
|
|
146
|
-
vertex_weight = 1.0 / self.NODES_PER_SIDE
|
|
147
|
-
edge_weight = 1.0 / self.NODES_PER_SIDE
|
|
148
|
-
|
|
149
|
-
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
150
|
-
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
151
|
-
|
|
152
|
-
@cache.dynamic_func(suffix=self.name)
|
|
153
|
-
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
154
|
-
node_type, type_index = self.node_type_and_type_index(node_index_in_element)
|
|
155
|
-
|
|
156
|
-
return wp.select(node_type == Triangle2DPolynomialShapeFunctions.VERTEX, EDGE_WEIGHT, VERTEX_WEIGHT)
|
|
157
|
-
|
|
158
|
-
return trace_node_quadrature_weight
|
|
159
|
-
|
|
160
|
-
def make_element_inner_weight(self):
|
|
161
|
-
ORDER = self.ORDER
|
|
162
|
-
|
|
163
|
-
def element_inner_weight_linear(
|
|
164
|
-
coords: Coords,
|
|
165
|
-
node_index_in_elt: int,
|
|
166
|
-
):
|
|
167
|
-
return coords[node_index_in_elt]
|
|
168
|
-
|
|
169
|
-
def element_inner_weight_quadratic(
|
|
170
|
-
coords: Coords,
|
|
171
|
-
node_index_in_elt: int,
|
|
172
|
-
):
|
|
173
|
-
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
174
|
-
|
|
175
|
-
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
176
|
-
# Vertex
|
|
177
|
-
return coords[type_index] * (2.0 * coords[type_index] - 1.0)
|
|
178
|
-
|
|
179
|
-
# Edge
|
|
180
|
-
c1 = type_index
|
|
181
|
-
c2 = (type_index + 1) % 3
|
|
182
|
-
return 4.0 * coords[c1] * coords[c2]
|
|
183
|
-
|
|
184
|
-
def element_inner_weight_cubic(
|
|
185
|
-
coords: Coords,
|
|
186
|
-
node_index_in_elt: int,
|
|
187
|
-
):
|
|
188
|
-
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
189
|
-
|
|
190
|
-
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
191
|
-
# Vertex
|
|
192
|
-
return 0.5 * coords[type_index] * (3.0 * coords[type_index] - 1.0) * (3.0 * coords[type_index] - 2.0)
|
|
193
|
-
|
|
194
|
-
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
195
|
-
# Edge
|
|
196
|
-
edge = type_index // 2
|
|
197
|
-
k = type_index - 2 * edge
|
|
198
|
-
c1 = (edge + k) % 3
|
|
199
|
-
c2 = (edge + 1 - k) % 3
|
|
200
|
-
|
|
201
|
-
return 4.5 * coords[c1] * coords[c2] * (3.0 * coords[c1] - 1.0)
|
|
202
|
-
|
|
203
|
-
# Interior
|
|
204
|
-
return 27.0 * coords[0] * coords[1] * coords[2]
|
|
205
|
-
|
|
206
|
-
if ORDER == 1:
|
|
207
|
-
return cache.get_func(element_inner_weight_linear, self.name)
|
|
208
|
-
elif ORDER == 2:
|
|
209
|
-
return cache.get_func(element_inner_weight_quadratic, self.name)
|
|
210
|
-
elif ORDER == 3:
|
|
211
|
-
return cache.get_func(element_inner_weight_cubic, self.name)
|
|
212
|
-
|
|
213
|
-
return None
|
|
214
|
-
|
|
215
|
-
def make_element_inner_weight_gradient(self):
|
|
216
|
-
ORDER = self.ORDER
|
|
217
|
-
|
|
218
|
-
def element_inner_weight_gradient_linear(
|
|
219
|
-
coords: Coords,
|
|
220
|
-
node_index_in_elt: int,
|
|
221
|
-
):
|
|
222
|
-
dw_dc = wp.vec3(0.0)
|
|
223
|
-
dw_dc[node_index_in_elt] = 1.0
|
|
224
|
-
|
|
225
|
-
dw_du = wp.vec2(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0])
|
|
226
|
-
return dw_du
|
|
227
|
-
|
|
228
|
-
def element_inner_weight_gradient_quadratic(
|
|
229
|
-
coords: Coords,
|
|
230
|
-
node_index_in_elt: int,
|
|
231
|
-
):
|
|
232
|
-
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
233
|
-
|
|
234
|
-
dw_dc = wp.vec3(0.0)
|
|
235
|
-
|
|
236
|
-
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
237
|
-
# Vertex
|
|
238
|
-
dw_dc[type_index] = 4.0 * coords[type_index] - 1.0
|
|
239
|
-
|
|
240
|
-
else:
|
|
241
|
-
# Edge
|
|
242
|
-
c1 = type_index
|
|
243
|
-
c2 = (type_index + 1) % 3
|
|
244
|
-
dw_dc[c1] = 4.0 * coords[c2]
|
|
245
|
-
dw_dc[c2] = 4.0 * coords[c1]
|
|
246
|
-
|
|
247
|
-
dw_du = wp.vec2(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0])
|
|
248
|
-
return dw_du
|
|
249
|
-
|
|
250
|
-
def element_inner_weight_gradient_cubic(
|
|
251
|
-
coords: Coords,
|
|
252
|
-
node_index_in_elt: int,
|
|
253
|
-
):
|
|
254
|
-
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
255
|
-
|
|
256
|
-
dw_dc = wp.vec3(0.0)
|
|
257
|
-
|
|
258
|
-
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
259
|
-
# Vertex
|
|
260
|
-
dw_dc[type_index] = (
|
|
261
|
-
0.5 * 27.0 * coords[type_index] * coords[type_index] - 9.0 * coords[type_index] + 1.0
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
265
|
-
# Edge
|
|
266
|
-
edge = type_index // 2
|
|
267
|
-
k = type_index - 2 * edge
|
|
268
|
-
c1 = (edge + k) % 3
|
|
269
|
-
c2 = (edge + 1 - k) % 3
|
|
270
|
-
|
|
271
|
-
dw_dc[c1] = 4.5 * coords[c2] * (6.0 * coords[c1] - 1.0)
|
|
272
|
-
dw_dc[c2] = 4.5 * coords[c1] * (3.0 * coords[c1] - 1.0)
|
|
273
|
-
|
|
274
|
-
else:
|
|
275
|
-
# Interior
|
|
276
|
-
dw_dc = wp.vec3(
|
|
277
|
-
27.0 * coords[1] * coords[2], 27.0 * coords[2] * coords[0], 27.0 * coords[0] * coords[1]
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
dw_du = wp.vec2(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0])
|
|
281
|
-
return dw_du
|
|
282
|
-
|
|
283
|
-
if ORDER == 1:
|
|
284
|
-
return cache.get_func(element_inner_weight_gradient_linear, self.name)
|
|
285
|
-
elif ORDER == 2:
|
|
286
|
-
return cache.get_func(element_inner_weight_gradient_quadratic, self.name)
|
|
287
|
-
elif ORDER == 3:
|
|
288
|
-
return cache.get_func(element_inner_weight_gradient_cubic, self.name)
|
|
289
|
-
|
|
290
|
-
return None
|
|
291
|
-
|
|
292
|
-
def element_node_triangulation(self):
|
|
293
|
-
if self.ORDER == 1:
|
|
294
|
-
element_triangles = [[0, 1, 2]]
|
|
295
|
-
if self.ORDER == 2:
|
|
296
|
-
element_triangles = [[0, 3, 5], [3, 1, 4], [2, 5, 4], [3, 4, 5]]
|
|
297
|
-
elif self.ORDER == 3:
|
|
298
|
-
element_triangles = [
|
|
299
|
-
[0, 3, 8],
|
|
300
|
-
[3, 4, 9],
|
|
301
|
-
[4, 1, 5],
|
|
302
|
-
[8, 3, 9],
|
|
303
|
-
[4, 5, 9],
|
|
304
|
-
[8, 9, 7],
|
|
305
|
-
[9, 5, 6],
|
|
306
|
-
[6, 7, 9],
|
|
307
|
-
[7, 6, 2],
|
|
308
|
-
]
|
|
309
|
-
|
|
310
|
-
return np.array(element_triangles)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
class Triangle2DNonConformingPolynomialShapeFunctions:
|
|
314
|
-
def __init__(self, degree: int):
|
|
315
|
-
self._tri_shape = Triangle2DPolynomialShapeFunctions(degree=degree)
|
|
316
|
-
self.ORDER = self._tri_shape.ORDER
|
|
317
|
-
self.NODES_PER_ELEMENT = self._tri_shape.NODES_PER_ELEMENT
|
|
318
|
-
|
|
319
|
-
self.element_node_triangulation = self._tri_shape.element_node_triangulation
|
|
320
|
-
|
|
321
|
-
# Coordinates (a, b, b) of embedded triangle
|
|
322
|
-
if self.ORDER == 1:
|
|
323
|
-
# Order 2
|
|
324
|
-
a = 2.0 / 3.0
|
|
325
|
-
elif self.ORDER == 2:
|
|
326
|
-
# Order 2, optimized for small intrinsic quadrature error up to degree 4
|
|
327
|
-
a = 0.7790771484375001
|
|
328
|
-
elif self.ORDER == 3:
|
|
329
|
-
# Order 3, optimized for small intrinsic quadrature error up to degree 6
|
|
330
|
-
a = 0.8429443359375002
|
|
331
|
-
else:
|
|
332
|
-
a = 1.0
|
|
333
|
-
|
|
334
|
-
b = 0.5 * (1.0 - a)
|
|
335
|
-
self._small_to_big = np.full((3, 3), b) + (a - b) * np.eye(3)
|
|
336
|
-
self._tri_scale = a - b
|
|
337
|
-
|
|
338
|
-
@property
|
|
339
|
-
def name(self) -> str:
|
|
340
|
-
return f"Tri_P{self.ORDER}d"
|
|
341
|
-
|
|
342
|
-
def make_node_quadrature_weight(self):
|
|
343
|
-
# Intrinsic quadrature -- precomputed integral of node shape functions
|
|
344
|
-
# over element. Order equal to self.ORDER
|
|
345
|
-
|
|
346
|
-
if self.ORDER == 2:
|
|
347
|
-
vertex_weight = 0.13743348
|
|
348
|
-
edge_weight = 0.19589985
|
|
349
|
-
interior_weight = 0.0
|
|
350
|
-
elif self.ORDER == 3:
|
|
351
|
-
vertex_weight = 0.07462578
|
|
352
|
-
edge_weight = 0.1019807
|
|
353
|
-
interior_weight = 0.16423881
|
|
354
|
-
else:
|
|
355
|
-
vertex_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
356
|
-
edge_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
357
|
-
interior_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
358
|
-
|
|
359
|
-
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
360
|
-
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
361
|
-
INTERIOR_WEIGHT = wp.constant(interior_weight)
|
|
362
|
-
|
|
363
|
-
@cache.dynamic_func(suffix=self.name)
|
|
364
|
-
def node_quadrature_weight(node_index_in_element: int):
|
|
365
|
-
node_type, type_index = self._tri_shape.node_type_and_type_index(node_index_in_element)
|
|
366
|
-
|
|
367
|
-
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
368
|
-
return VERTEX_WEIGHT
|
|
369
|
-
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
370
|
-
return EDGE_WEIGHT
|
|
371
|
-
|
|
372
|
-
return INTERIOR_WEIGHT
|
|
373
|
-
|
|
374
|
-
return node_quadrature_weight
|
|
375
|
-
|
|
376
|
-
def make_trace_node_quadrature_weight(self):
|
|
377
|
-
# Non-conforming, zero measure on sides
|
|
378
|
-
|
|
379
|
-
@wp.func
|
|
380
|
-
def zero(node_index_in_elt: int):
|
|
381
|
-
return 0.0
|
|
382
|
-
|
|
383
|
-
return zero
|
|
384
|
-
|
|
385
|
-
def make_node_coords_in_element(self):
|
|
386
|
-
node_coords_in_tet = self._tri_shape.make_node_coords_in_element()
|
|
387
|
-
|
|
388
|
-
SMALL_TO_BIG = wp.constant(wp.mat33(self._small_to_big))
|
|
389
|
-
|
|
390
|
-
@cache.dynamic_func(suffix=self.name)
|
|
391
|
-
def node_coords_in_element(
|
|
392
|
-
node_index_in_elt: int,
|
|
393
|
-
):
|
|
394
|
-
tri_coords = node_coords_in_tet(node_index_in_elt)
|
|
395
|
-
return SMALL_TO_BIG * tri_coords
|
|
396
|
-
|
|
397
|
-
return node_coords_in_element
|
|
398
|
-
|
|
399
|
-
def make_element_inner_weight(self):
|
|
400
|
-
tri_inner_weight = self._tri_shape.make_element_inner_weight()
|
|
401
|
-
|
|
402
|
-
BIG_TO_SMALL = wp.constant(wp.mat33(np.linalg.inv(self._small_to_big)))
|
|
403
|
-
|
|
404
|
-
@cache.dynamic_func(suffix=self.name)
|
|
405
|
-
def element_inner_weight(
|
|
406
|
-
coords: Coords,
|
|
407
|
-
node_index_in_elt: int,
|
|
408
|
-
):
|
|
409
|
-
tri_coords = BIG_TO_SMALL * coords
|
|
410
|
-
return tri_inner_weight(tri_coords, node_index_in_elt)
|
|
411
|
-
|
|
412
|
-
return element_inner_weight
|
|
413
|
-
|
|
414
|
-
def make_element_inner_weight_gradient(self):
|
|
415
|
-
tri_inner_weight_gradient = self._tri_shape.make_element_inner_weight_gradient()
|
|
416
|
-
|
|
417
|
-
BIG_TO_SMALL = wp.constant(wp.mat33(np.linalg.inv(self._small_to_big)))
|
|
418
|
-
INV_TRI_SCALE = wp.constant(1.0 / self._tri_scale)
|
|
419
|
-
|
|
420
|
-
@cache.dynamic_func(suffix=self.name)
|
|
421
|
-
def element_inner_weight_gradient(
|
|
422
|
-
coords: Coords,
|
|
423
|
-
node_index_in_elt: int,
|
|
424
|
-
):
|
|
425
|
-
tri_coords = BIG_TO_SMALL * coords
|
|
426
|
-
grad = tri_inner_weight_gradient(tri_coords, node_index_in_elt)
|
|
427
|
-
return INV_TRI_SCALE * grad
|
|
428
|
-
|
|
429
|
-
return element_inner_weight_gradient
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
import warp as wp
|
|
4
|
+
from warp.fem import cache
|
|
5
|
+
from warp.fem.types import Coords
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _triangle_node_index(tx: int, ty: int, degree: int):
|
|
9
|
+
VERTEX_NODE_COUNT = 3
|
|
10
|
+
SIDE_INTERIOR_NODE_COUNT = degree - 1
|
|
11
|
+
|
|
12
|
+
# Index in similar order to e.g. VTK
|
|
13
|
+
# First vertices, then edge (counterclockwise) then interior points (recursively)
|
|
14
|
+
|
|
15
|
+
if tx == 0:
|
|
16
|
+
if ty == 0:
|
|
17
|
+
return 0
|
|
18
|
+
elif ty == degree:
|
|
19
|
+
return 2
|
|
20
|
+
else:
|
|
21
|
+
edge_index = 2
|
|
22
|
+
return VERTEX_NODE_COUNT + SIDE_INTERIOR_NODE_COUNT * edge_index + (SIDE_INTERIOR_NODE_COUNT - ty)
|
|
23
|
+
elif ty == 0:
|
|
24
|
+
if tx == degree:
|
|
25
|
+
return 1
|
|
26
|
+
else:
|
|
27
|
+
edge_index = 0
|
|
28
|
+
return VERTEX_NODE_COUNT + SIDE_INTERIOR_NODE_COUNT * edge_index + tx - 1
|
|
29
|
+
elif tx + ty == degree:
|
|
30
|
+
edge_index = 1
|
|
31
|
+
return VERTEX_NODE_COUNT + SIDE_INTERIOR_NODE_COUNT * edge_index + ty - 1
|
|
32
|
+
|
|
33
|
+
vertex_edge_node_count = 3 * degree
|
|
34
|
+
return vertex_edge_node_count + _triangle_node_index(tx - 1, ty - 1, degree - 3)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Triangle2DPolynomialShapeFunctions:
|
|
38
|
+
VERTEX = wp.constant(0)
|
|
39
|
+
EDGE = wp.constant(1)
|
|
40
|
+
INTERIOR = wp.constant(2)
|
|
41
|
+
|
|
42
|
+
def __init__(self, degree: int):
|
|
43
|
+
self.ORDER = wp.constant(degree)
|
|
44
|
+
|
|
45
|
+
self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 2) // 2)
|
|
46
|
+
self.NODES_PER_SIDE = wp.constant(degree + 1)
|
|
47
|
+
|
|
48
|
+
triangle_coords = np.empty((self.NODES_PER_ELEMENT, 2), dtype=int)
|
|
49
|
+
|
|
50
|
+
for tx in range(degree + 1):
|
|
51
|
+
for ty in range(degree + 1 - tx):
|
|
52
|
+
index = _triangle_node_index(tx, ty, degree)
|
|
53
|
+
triangle_coords[index] = [tx, ty]
|
|
54
|
+
|
|
55
|
+
CoordTypeVec = wp.mat(dtype=int, shape=(self.NODES_PER_ELEMENT, 2))
|
|
56
|
+
self.NODE_TRIANGLE_COORDS = wp.constant(CoordTypeVec(triangle_coords))
|
|
57
|
+
|
|
58
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
59
|
+
self._node_triangle_coordinates = self._get_node_triangle_coordinates()
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def name(self) -> str:
|
|
63
|
+
return f"Tri_P{self.ORDER}"
|
|
64
|
+
|
|
65
|
+
def _get_node_triangle_coordinates(self):
|
|
66
|
+
NODE_TRIANGLE_COORDS = self.NODE_TRIANGLE_COORDS
|
|
67
|
+
|
|
68
|
+
def node_triangle_coordinates(
|
|
69
|
+
node_index_in_elt: int,
|
|
70
|
+
):
|
|
71
|
+
return wp.vec2i(NODE_TRIANGLE_COORDS[node_index_in_elt, 0], NODE_TRIANGLE_COORDS[node_index_in_elt, 1])
|
|
72
|
+
|
|
73
|
+
return cache.get_func(node_triangle_coordinates, self.name)
|
|
74
|
+
|
|
75
|
+
def _get_node_type_and_type_index(self):
|
|
76
|
+
ORDER = self.ORDER
|
|
77
|
+
|
|
78
|
+
def node_type_and_index(
|
|
79
|
+
node_index_in_elt: int,
|
|
80
|
+
):
|
|
81
|
+
if node_index_in_elt < 3:
|
|
82
|
+
return Triangle2DPolynomialShapeFunctions.VERTEX, node_index_in_elt
|
|
83
|
+
|
|
84
|
+
if node_index_in_elt < 3 * ORDER:
|
|
85
|
+
return Triangle2DPolynomialShapeFunctions.EDGE, (node_index_in_elt - 3)
|
|
86
|
+
|
|
87
|
+
return Triangle2DPolynomialShapeFunctions.INTERIOR, (node_index_in_elt - 3 * ORDER)
|
|
88
|
+
|
|
89
|
+
return cache.get_func(node_type_and_index, self.name)
|
|
90
|
+
|
|
91
|
+
def make_node_coords_in_element(self):
|
|
92
|
+
ORDER = self.ORDER
|
|
93
|
+
|
|
94
|
+
def node_coords_in_element(
|
|
95
|
+
node_index_in_elt: int,
|
|
96
|
+
):
|
|
97
|
+
tri_coords = self._node_triangle_coordinates(node_index_in_elt)
|
|
98
|
+
cx = float(tri_coords[0]) / float(ORDER)
|
|
99
|
+
cy = float(tri_coords[1]) / float(ORDER)
|
|
100
|
+
return Coords(1.0 - cx - cy, cx, cy)
|
|
101
|
+
|
|
102
|
+
return cache.get_func(node_coords_in_element, self.name)
|
|
103
|
+
|
|
104
|
+
def make_node_quadrature_weight(self):
|
|
105
|
+
if self.ORDER == 3:
|
|
106
|
+
# P3 intrisic quadrature
|
|
107
|
+
vertex_weight = 1.0 / 30
|
|
108
|
+
edge_weight = 0.075
|
|
109
|
+
interior_weight = 0.45
|
|
110
|
+
elif self.ORDER == 2:
|
|
111
|
+
# Order 1, but optimized quadrature weights for monomials of order <= 4
|
|
112
|
+
vertex_weight = 0.022335964126
|
|
113
|
+
edge_weight = 0.310997369207
|
|
114
|
+
interior_weight = 0.0
|
|
115
|
+
else:
|
|
116
|
+
vertex_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
117
|
+
edge_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
118
|
+
interior_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
119
|
+
|
|
120
|
+
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
121
|
+
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
122
|
+
INTERIOR_WEIGHT = wp.constant(interior_weight)
|
|
123
|
+
|
|
124
|
+
@cache.dynamic_func(suffix=self.name)
|
|
125
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
126
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_element)
|
|
127
|
+
|
|
128
|
+
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
129
|
+
return VERTEX_WEIGHT
|
|
130
|
+
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
131
|
+
return EDGE_WEIGHT
|
|
132
|
+
|
|
133
|
+
return INTERIOR_WEIGHT
|
|
134
|
+
|
|
135
|
+
return node_quadrature_weight
|
|
136
|
+
|
|
137
|
+
def make_trace_node_quadrature_weight(self):
|
|
138
|
+
# Closed Newton-Cotes
|
|
139
|
+
if self.ORDER == 3:
|
|
140
|
+
vertex_weight = 1.0 / 8.0
|
|
141
|
+
edge_weight = 3.0 / 8.0
|
|
142
|
+
elif self.ORDER == 2:
|
|
143
|
+
vertex_weight = 1.0 / 6.0
|
|
144
|
+
edge_weight = 2.0 / 3.0
|
|
145
|
+
else:
|
|
146
|
+
vertex_weight = 1.0 / self.NODES_PER_SIDE
|
|
147
|
+
edge_weight = 1.0 / self.NODES_PER_SIDE
|
|
148
|
+
|
|
149
|
+
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
150
|
+
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
151
|
+
|
|
152
|
+
@cache.dynamic_func(suffix=self.name)
|
|
153
|
+
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
154
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_element)
|
|
155
|
+
|
|
156
|
+
return wp.select(node_type == Triangle2DPolynomialShapeFunctions.VERTEX, EDGE_WEIGHT, VERTEX_WEIGHT)
|
|
157
|
+
|
|
158
|
+
return trace_node_quadrature_weight
|
|
159
|
+
|
|
160
|
+
def make_element_inner_weight(self):
|
|
161
|
+
ORDER = self.ORDER
|
|
162
|
+
|
|
163
|
+
def element_inner_weight_linear(
|
|
164
|
+
coords: Coords,
|
|
165
|
+
node_index_in_elt: int,
|
|
166
|
+
):
|
|
167
|
+
return coords[node_index_in_elt]
|
|
168
|
+
|
|
169
|
+
def element_inner_weight_quadratic(
|
|
170
|
+
coords: Coords,
|
|
171
|
+
node_index_in_elt: int,
|
|
172
|
+
):
|
|
173
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
174
|
+
|
|
175
|
+
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
176
|
+
# Vertex
|
|
177
|
+
return coords[type_index] * (2.0 * coords[type_index] - 1.0)
|
|
178
|
+
|
|
179
|
+
# Edge
|
|
180
|
+
c1 = type_index
|
|
181
|
+
c2 = (type_index + 1) % 3
|
|
182
|
+
return 4.0 * coords[c1] * coords[c2]
|
|
183
|
+
|
|
184
|
+
def element_inner_weight_cubic(
|
|
185
|
+
coords: Coords,
|
|
186
|
+
node_index_in_elt: int,
|
|
187
|
+
):
|
|
188
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
189
|
+
|
|
190
|
+
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
191
|
+
# Vertex
|
|
192
|
+
return 0.5 * coords[type_index] * (3.0 * coords[type_index] - 1.0) * (3.0 * coords[type_index] - 2.0)
|
|
193
|
+
|
|
194
|
+
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
195
|
+
# Edge
|
|
196
|
+
edge = type_index // 2
|
|
197
|
+
k = type_index - 2 * edge
|
|
198
|
+
c1 = (edge + k) % 3
|
|
199
|
+
c2 = (edge + 1 - k) % 3
|
|
200
|
+
|
|
201
|
+
return 4.5 * coords[c1] * coords[c2] * (3.0 * coords[c1] - 1.0)
|
|
202
|
+
|
|
203
|
+
# Interior
|
|
204
|
+
return 27.0 * coords[0] * coords[1] * coords[2]
|
|
205
|
+
|
|
206
|
+
if ORDER == 1:
|
|
207
|
+
return cache.get_func(element_inner_weight_linear, self.name)
|
|
208
|
+
elif ORDER == 2:
|
|
209
|
+
return cache.get_func(element_inner_weight_quadratic, self.name)
|
|
210
|
+
elif ORDER == 3:
|
|
211
|
+
return cache.get_func(element_inner_weight_cubic, self.name)
|
|
212
|
+
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
def make_element_inner_weight_gradient(self):
|
|
216
|
+
ORDER = self.ORDER
|
|
217
|
+
|
|
218
|
+
def element_inner_weight_gradient_linear(
|
|
219
|
+
coords: Coords,
|
|
220
|
+
node_index_in_elt: int,
|
|
221
|
+
):
|
|
222
|
+
dw_dc = wp.vec3(0.0)
|
|
223
|
+
dw_dc[node_index_in_elt] = 1.0
|
|
224
|
+
|
|
225
|
+
dw_du = wp.vec2(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0])
|
|
226
|
+
return dw_du
|
|
227
|
+
|
|
228
|
+
def element_inner_weight_gradient_quadratic(
|
|
229
|
+
coords: Coords,
|
|
230
|
+
node_index_in_elt: int,
|
|
231
|
+
):
|
|
232
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
233
|
+
|
|
234
|
+
dw_dc = wp.vec3(0.0)
|
|
235
|
+
|
|
236
|
+
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
237
|
+
# Vertex
|
|
238
|
+
dw_dc[type_index] = 4.0 * coords[type_index] - 1.0
|
|
239
|
+
|
|
240
|
+
else:
|
|
241
|
+
# Edge
|
|
242
|
+
c1 = type_index
|
|
243
|
+
c2 = (type_index + 1) % 3
|
|
244
|
+
dw_dc[c1] = 4.0 * coords[c2]
|
|
245
|
+
dw_dc[c2] = 4.0 * coords[c1]
|
|
246
|
+
|
|
247
|
+
dw_du = wp.vec2(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0])
|
|
248
|
+
return dw_du
|
|
249
|
+
|
|
250
|
+
def element_inner_weight_gradient_cubic(
|
|
251
|
+
coords: Coords,
|
|
252
|
+
node_index_in_elt: int,
|
|
253
|
+
):
|
|
254
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
255
|
+
|
|
256
|
+
dw_dc = wp.vec3(0.0)
|
|
257
|
+
|
|
258
|
+
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
259
|
+
# Vertex
|
|
260
|
+
dw_dc[type_index] = (
|
|
261
|
+
0.5 * 27.0 * coords[type_index] * coords[type_index] - 9.0 * coords[type_index] + 1.0
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
265
|
+
# Edge
|
|
266
|
+
edge = type_index // 2
|
|
267
|
+
k = type_index - 2 * edge
|
|
268
|
+
c1 = (edge + k) % 3
|
|
269
|
+
c2 = (edge + 1 - k) % 3
|
|
270
|
+
|
|
271
|
+
dw_dc[c1] = 4.5 * coords[c2] * (6.0 * coords[c1] - 1.0)
|
|
272
|
+
dw_dc[c2] = 4.5 * coords[c1] * (3.0 * coords[c1] - 1.0)
|
|
273
|
+
|
|
274
|
+
else:
|
|
275
|
+
# Interior
|
|
276
|
+
dw_dc = wp.vec3(
|
|
277
|
+
27.0 * coords[1] * coords[2], 27.0 * coords[2] * coords[0], 27.0 * coords[0] * coords[1]
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
dw_du = wp.vec2(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0])
|
|
281
|
+
return dw_du
|
|
282
|
+
|
|
283
|
+
if ORDER == 1:
|
|
284
|
+
return cache.get_func(element_inner_weight_gradient_linear, self.name)
|
|
285
|
+
elif ORDER == 2:
|
|
286
|
+
return cache.get_func(element_inner_weight_gradient_quadratic, self.name)
|
|
287
|
+
elif ORDER == 3:
|
|
288
|
+
return cache.get_func(element_inner_weight_gradient_cubic, self.name)
|
|
289
|
+
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
def element_node_triangulation(self):
|
|
293
|
+
if self.ORDER == 1:
|
|
294
|
+
element_triangles = [[0, 1, 2]]
|
|
295
|
+
if self.ORDER == 2:
|
|
296
|
+
element_triangles = [[0, 3, 5], [3, 1, 4], [2, 5, 4], [3, 4, 5]]
|
|
297
|
+
elif self.ORDER == 3:
|
|
298
|
+
element_triangles = [
|
|
299
|
+
[0, 3, 8],
|
|
300
|
+
[3, 4, 9],
|
|
301
|
+
[4, 1, 5],
|
|
302
|
+
[8, 3, 9],
|
|
303
|
+
[4, 5, 9],
|
|
304
|
+
[8, 9, 7],
|
|
305
|
+
[9, 5, 6],
|
|
306
|
+
[6, 7, 9],
|
|
307
|
+
[7, 6, 2],
|
|
308
|
+
]
|
|
309
|
+
|
|
310
|
+
return np.array(element_triangles)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class Triangle2DNonConformingPolynomialShapeFunctions:
|
|
314
|
+
def __init__(self, degree: int):
|
|
315
|
+
self._tri_shape = Triangle2DPolynomialShapeFunctions(degree=degree)
|
|
316
|
+
self.ORDER = self._tri_shape.ORDER
|
|
317
|
+
self.NODES_PER_ELEMENT = self._tri_shape.NODES_PER_ELEMENT
|
|
318
|
+
|
|
319
|
+
self.element_node_triangulation = self._tri_shape.element_node_triangulation
|
|
320
|
+
|
|
321
|
+
# Coordinates (a, b, b) of embedded triangle
|
|
322
|
+
if self.ORDER == 1:
|
|
323
|
+
# Order 2
|
|
324
|
+
a = 2.0 / 3.0
|
|
325
|
+
elif self.ORDER == 2:
|
|
326
|
+
# Order 2, optimized for small intrinsic quadrature error up to degree 4
|
|
327
|
+
a = 0.7790771484375001
|
|
328
|
+
elif self.ORDER == 3:
|
|
329
|
+
# Order 3, optimized for small intrinsic quadrature error up to degree 6
|
|
330
|
+
a = 0.8429443359375002
|
|
331
|
+
else:
|
|
332
|
+
a = 1.0
|
|
333
|
+
|
|
334
|
+
b = 0.5 * (1.0 - a)
|
|
335
|
+
self._small_to_big = np.full((3, 3), b) + (a - b) * np.eye(3)
|
|
336
|
+
self._tri_scale = a - b
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
def name(self) -> str:
|
|
340
|
+
return f"Tri_P{self.ORDER}d"
|
|
341
|
+
|
|
342
|
+
def make_node_quadrature_weight(self):
|
|
343
|
+
# Intrinsic quadrature -- precomputed integral of node shape functions
|
|
344
|
+
# over element. Order equal to self.ORDER
|
|
345
|
+
|
|
346
|
+
if self.ORDER == 2:
|
|
347
|
+
vertex_weight = 0.13743348
|
|
348
|
+
edge_weight = 0.19589985
|
|
349
|
+
interior_weight = 0.0
|
|
350
|
+
elif self.ORDER == 3:
|
|
351
|
+
vertex_weight = 0.07462578
|
|
352
|
+
edge_weight = 0.1019807
|
|
353
|
+
interior_weight = 0.16423881
|
|
354
|
+
else:
|
|
355
|
+
vertex_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
356
|
+
edge_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
357
|
+
interior_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
358
|
+
|
|
359
|
+
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
360
|
+
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
361
|
+
INTERIOR_WEIGHT = wp.constant(interior_weight)
|
|
362
|
+
|
|
363
|
+
@cache.dynamic_func(suffix=self.name)
|
|
364
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
365
|
+
node_type, type_index = self._tri_shape.node_type_and_type_index(node_index_in_element)
|
|
366
|
+
|
|
367
|
+
if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
|
|
368
|
+
return VERTEX_WEIGHT
|
|
369
|
+
elif node_type == Triangle2DPolynomialShapeFunctions.EDGE:
|
|
370
|
+
return EDGE_WEIGHT
|
|
371
|
+
|
|
372
|
+
return INTERIOR_WEIGHT
|
|
373
|
+
|
|
374
|
+
return node_quadrature_weight
|
|
375
|
+
|
|
376
|
+
def make_trace_node_quadrature_weight(self):
|
|
377
|
+
# Non-conforming, zero measure on sides
|
|
378
|
+
|
|
379
|
+
@wp.func
|
|
380
|
+
def zero(node_index_in_elt: int):
|
|
381
|
+
return 0.0
|
|
382
|
+
|
|
383
|
+
return zero
|
|
384
|
+
|
|
385
|
+
def make_node_coords_in_element(self):
|
|
386
|
+
node_coords_in_tet = self._tri_shape.make_node_coords_in_element()
|
|
387
|
+
|
|
388
|
+
SMALL_TO_BIG = wp.constant(wp.mat33(self._small_to_big))
|
|
389
|
+
|
|
390
|
+
@cache.dynamic_func(suffix=self.name)
|
|
391
|
+
def node_coords_in_element(
|
|
392
|
+
node_index_in_elt: int,
|
|
393
|
+
):
|
|
394
|
+
tri_coords = node_coords_in_tet(node_index_in_elt)
|
|
395
|
+
return SMALL_TO_BIG * tri_coords
|
|
396
|
+
|
|
397
|
+
return node_coords_in_element
|
|
398
|
+
|
|
399
|
+
def make_element_inner_weight(self):
|
|
400
|
+
tri_inner_weight = self._tri_shape.make_element_inner_weight()
|
|
401
|
+
|
|
402
|
+
BIG_TO_SMALL = wp.constant(wp.mat33(np.linalg.inv(self._small_to_big)))
|
|
403
|
+
|
|
404
|
+
@cache.dynamic_func(suffix=self.name)
|
|
405
|
+
def element_inner_weight(
|
|
406
|
+
coords: Coords,
|
|
407
|
+
node_index_in_elt: int,
|
|
408
|
+
):
|
|
409
|
+
tri_coords = BIG_TO_SMALL * coords
|
|
410
|
+
return tri_inner_weight(tri_coords, node_index_in_elt)
|
|
411
|
+
|
|
412
|
+
return element_inner_weight
|
|
413
|
+
|
|
414
|
+
def make_element_inner_weight_gradient(self):
|
|
415
|
+
tri_inner_weight_gradient = self._tri_shape.make_element_inner_weight_gradient()
|
|
416
|
+
|
|
417
|
+
BIG_TO_SMALL = wp.constant(wp.mat33(np.linalg.inv(self._small_to_big)))
|
|
418
|
+
INV_TRI_SCALE = wp.constant(1.0 / self._tri_scale)
|
|
419
|
+
|
|
420
|
+
@cache.dynamic_func(suffix=self.name)
|
|
421
|
+
def element_inner_weight_gradient(
|
|
422
|
+
coords: Coords,
|
|
423
|
+
node_index_in_elt: int,
|
|
424
|
+
):
|
|
425
|
+
tri_coords = BIG_TO_SMALL * coords
|
|
426
|
+
grad = tri_inner_weight_gradient(tri_coords, node_index_in_elt)
|
|
427
|
+
return INV_TRI_SCALE * grad
|
|
428
|
+
|
|
429
|
+
return element_inner_weight_gradient
|