warp-lang 1.7.0__py3-none-manylinux_2_28_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 +139 -0
- warp/__init__.pyi +1 -0
- warp/autograd.py +1142 -0
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +557 -0
- warp/build_dll.py +405 -0
- warp/builtins.py +6855 -0
- warp/codegen.py +3969 -0
- warp/config.py +158 -0
- warp/constants.py +57 -0
- warp/context.py +6812 -0
- warp/dlpack.py +462 -0
- warp/examples/__init__.py +24 -0
- warp/examples/assets/bear.usd +0 -0
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/assets/cartpole.urdf +110 -0
- warp/examples/assets/crazyflie.usd +0 -0
- warp/examples/assets/cube.usd +0 -0
- warp/examples/assets/nonuniform.usd +0 -0
- warp/examples/assets/nv_ant.xml +92 -0
- warp/examples/assets/nv_humanoid.xml +183 -0
- warp/examples/assets/nvidia_logo.png +0 -0
- warp/examples/assets/pixel.jpg +0 -0
- warp/examples/assets/quadruped.urdf +268 -0
- warp/examples/assets/rocks.nvdb +0 -0
- warp/examples/assets/rocks.usd +0 -0
- warp/examples/assets/sphere.usd +0 -0
- warp/examples/assets/square_cloth.usd +0 -0
- warp/examples/benchmarks/benchmark_api.py +389 -0
- warp/examples/benchmarks/benchmark_cloth.py +296 -0
- warp/examples/benchmarks/benchmark_cloth_cupy.py +96 -0
- warp/examples/benchmarks/benchmark_cloth_jax.py +105 -0
- warp/examples/benchmarks/benchmark_cloth_numba.py +161 -0
- warp/examples/benchmarks/benchmark_cloth_numpy.py +85 -0
- warp/examples/benchmarks/benchmark_cloth_paddle.py +94 -0
- warp/examples/benchmarks/benchmark_cloth_pytorch.py +94 -0
- warp/examples/benchmarks/benchmark_cloth_taichi.py +120 -0
- warp/examples/benchmarks/benchmark_cloth_warp.py +153 -0
- warp/examples/benchmarks/benchmark_gemm.py +164 -0
- warp/examples/benchmarks/benchmark_interop_paddle.py +166 -0
- warp/examples/benchmarks/benchmark_interop_torch.py +166 -0
- warp/examples/benchmarks/benchmark_launches.py +301 -0
- warp/examples/benchmarks/benchmark_tile_load_store.py +103 -0
- warp/examples/browse.py +37 -0
- warp/examples/core/example_cupy.py +86 -0
- warp/examples/core/example_dem.py +241 -0
- warp/examples/core/example_fluid.py +299 -0
- warp/examples/core/example_graph_capture.py +150 -0
- warp/examples/core/example_marching_cubes.py +194 -0
- warp/examples/core/example_mesh.py +180 -0
- warp/examples/core/example_mesh_intersect.py +211 -0
- warp/examples/core/example_nvdb.py +182 -0
- warp/examples/core/example_raycast.py +111 -0
- warp/examples/core/example_raymarch.py +205 -0
- warp/examples/core/example_render_opengl.py +193 -0
- warp/examples/core/example_sample_mesh.py +300 -0
- warp/examples/core/example_sph.py +411 -0
- warp/examples/core/example_torch.py +211 -0
- warp/examples/core/example_wave.py +269 -0
- warp/examples/fem/example_adaptive_grid.py +286 -0
- warp/examples/fem/example_apic_fluid.py +423 -0
- warp/examples/fem/example_burgers.py +261 -0
- warp/examples/fem/example_convection_diffusion.py +178 -0
- warp/examples/fem/example_convection_diffusion_dg.py +204 -0
- warp/examples/fem/example_deformed_geometry.py +172 -0
- warp/examples/fem/example_diffusion.py +196 -0
- warp/examples/fem/example_diffusion_3d.py +225 -0
- warp/examples/fem/example_diffusion_mgpu.py +220 -0
- warp/examples/fem/example_distortion_energy.py +228 -0
- warp/examples/fem/example_magnetostatics.py +240 -0
- warp/examples/fem/example_mixed_elasticity.py +291 -0
- warp/examples/fem/example_navier_stokes.py +261 -0
- warp/examples/fem/example_nonconforming_contact.py +298 -0
- warp/examples/fem/example_stokes.py +213 -0
- warp/examples/fem/example_stokes_transfer.py +262 -0
- warp/examples/fem/example_streamlines.py +352 -0
- warp/examples/fem/utils.py +1000 -0
- warp/examples/interop/example_jax_callable.py +116 -0
- warp/examples/interop/example_jax_ffi_callback.py +132 -0
- warp/examples/interop/example_jax_kernel.py +205 -0
- warp/examples/optim/example_bounce.py +266 -0
- warp/examples/optim/example_cloth_throw.py +228 -0
- warp/examples/optim/example_diffray.py +561 -0
- warp/examples/optim/example_drone.py +870 -0
- warp/examples/optim/example_fluid_checkpoint.py +497 -0
- warp/examples/optim/example_inverse_kinematics.py +182 -0
- warp/examples/optim/example_inverse_kinematics_torch.py +191 -0
- warp/examples/optim/example_softbody_properties.py +400 -0
- warp/examples/optim/example_spring_cage.py +245 -0
- warp/examples/optim/example_trajectory.py +227 -0
- warp/examples/sim/example_cartpole.py +143 -0
- warp/examples/sim/example_cloth.py +225 -0
- warp/examples/sim/example_cloth_self_contact.py +322 -0
- warp/examples/sim/example_granular.py +130 -0
- warp/examples/sim/example_granular_collision_sdf.py +202 -0
- warp/examples/sim/example_jacobian_ik.py +244 -0
- warp/examples/sim/example_particle_chain.py +124 -0
- warp/examples/sim/example_quadruped.py +203 -0
- warp/examples/sim/example_rigid_chain.py +203 -0
- warp/examples/sim/example_rigid_contact.py +195 -0
- warp/examples/sim/example_rigid_force.py +133 -0
- warp/examples/sim/example_rigid_gyroscopic.py +115 -0
- warp/examples/sim/example_rigid_soft_contact.py +140 -0
- warp/examples/sim/example_soft_body.py +196 -0
- warp/examples/tile/example_tile_cholesky.py +87 -0
- warp/examples/tile/example_tile_convolution.py +66 -0
- warp/examples/tile/example_tile_fft.py +55 -0
- warp/examples/tile/example_tile_filtering.py +113 -0
- warp/examples/tile/example_tile_matmul.py +85 -0
- warp/examples/tile/example_tile_mlp.py +383 -0
- warp/examples/tile/example_tile_nbody.py +199 -0
- warp/examples/tile/example_tile_walker.py +327 -0
- warp/fabric.py +355 -0
- warp/fem/__init__.py +106 -0
- warp/fem/adaptivity.py +508 -0
- warp/fem/cache.py +572 -0
- warp/fem/dirichlet.py +202 -0
- warp/fem/domain.py +411 -0
- warp/fem/field/__init__.py +125 -0
- warp/fem/field/field.py +619 -0
- warp/fem/field/nodal_field.py +326 -0
- warp/fem/field/restriction.py +37 -0
- warp/fem/field/virtual.py +848 -0
- warp/fem/geometry/__init__.py +32 -0
- warp/fem/geometry/adaptive_nanogrid.py +857 -0
- warp/fem/geometry/closest_point.py +84 -0
- warp/fem/geometry/deformed_geometry.py +221 -0
- warp/fem/geometry/element.py +776 -0
- warp/fem/geometry/geometry.py +362 -0
- warp/fem/geometry/grid_2d.py +392 -0
- warp/fem/geometry/grid_3d.py +452 -0
- warp/fem/geometry/hexmesh.py +911 -0
- warp/fem/geometry/nanogrid.py +571 -0
- warp/fem/geometry/partition.py +389 -0
- warp/fem/geometry/quadmesh.py +663 -0
- warp/fem/geometry/tetmesh.py +855 -0
- warp/fem/geometry/trimesh.py +806 -0
- warp/fem/integrate.py +2335 -0
- warp/fem/linalg.py +419 -0
- warp/fem/operator.py +293 -0
- warp/fem/polynomial.py +229 -0
- warp/fem/quadrature/__init__.py +17 -0
- warp/fem/quadrature/pic_quadrature.py +299 -0
- warp/fem/quadrature/quadrature.py +591 -0
- warp/fem/space/__init__.py +228 -0
- warp/fem/space/basis_function_space.py +468 -0
- warp/fem/space/basis_space.py +667 -0
- warp/fem/space/dof_mapper.py +251 -0
- warp/fem/space/function_space.py +309 -0
- warp/fem/space/grid_2d_function_space.py +177 -0
- warp/fem/space/grid_3d_function_space.py +227 -0
- warp/fem/space/hexmesh_function_space.py +257 -0
- warp/fem/space/nanogrid_function_space.py +201 -0
- warp/fem/space/partition.py +367 -0
- warp/fem/space/quadmesh_function_space.py +223 -0
- warp/fem/space/restriction.py +179 -0
- warp/fem/space/shape/__init__.py +143 -0
- warp/fem/space/shape/cube_shape_function.py +1105 -0
- warp/fem/space/shape/shape_function.py +133 -0
- warp/fem/space/shape/square_shape_function.py +926 -0
- warp/fem/space/shape/tet_shape_function.py +834 -0
- warp/fem/space/shape/triangle_shape_function.py +672 -0
- warp/fem/space/tetmesh_function_space.py +271 -0
- warp/fem/space/topology.py +424 -0
- warp/fem/space/trimesh_function_space.py +194 -0
- warp/fem/types.py +99 -0
- warp/fem/utils.py +420 -0
- warp/jax.py +187 -0
- warp/jax_experimental/__init__.py +16 -0
- warp/jax_experimental/custom_call.py +351 -0
- warp/jax_experimental/ffi.py +698 -0
- warp/jax_experimental/xla_ffi.py +602 -0
- warp/math.py +244 -0
- warp/native/array.h +1145 -0
- warp/native/builtin.h +1800 -0
- warp/native/bvh.cpp +492 -0
- warp/native/bvh.cu +791 -0
- warp/native/bvh.h +554 -0
- warp/native/clang/clang.cpp +536 -0
- warp/native/coloring.cpp +613 -0
- warp/native/crt.cpp +51 -0
- warp/native/crt.h +362 -0
- warp/native/cuda_crt.h +1058 -0
- warp/native/cuda_util.cpp +646 -0
- warp/native/cuda_util.h +307 -0
- warp/native/error.cpp +77 -0
- warp/native/error.h +36 -0
- warp/native/exports.h +1878 -0
- warp/native/fabric.h +245 -0
- warp/native/hashgrid.cpp +311 -0
- warp/native/hashgrid.cu +87 -0
- warp/native/hashgrid.h +240 -0
- warp/native/initializer_array.h +41 -0
- warp/native/intersect.h +1230 -0
- warp/native/intersect_adj.h +375 -0
- warp/native/intersect_tri.h +339 -0
- warp/native/marching.cpp +19 -0
- warp/native/marching.cu +514 -0
- warp/native/marching.h +19 -0
- warp/native/mat.h +2220 -0
- warp/native/mathdx.cpp +87 -0
- warp/native/matnn.h +343 -0
- warp/native/mesh.cpp +266 -0
- warp/native/mesh.cu +404 -0
- warp/native/mesh.h +1980 -0
- warp/native/nanovdb/GridHandle.h +366 -0
- warp/native/nanovdb/HostBuffer.h +590 -0
- warp/native/nanovdb/NanoVDB.h +6624 -0
- warp/native/nanovdb/PNanoVDB.h +3390 -0
- warp/native/noise.h +859 -0
- warp/native/quat.h +1371 -0
- warp/native/rand.h +342 -0
- warp/native/range.h +139 -0
- warp/native/reduce.cpp +174 -0
- warp/native/reduce.cu +364 -0
- warp/native/runlength_encode.cpp +79 -0
- warp/native/runlength_encode.cu +61 -0
- warp/native/scan.cpp +47 -0
- warp/native/scan.cu +53 -0
- warp/native/scan.h +23 -0
- warp/native/solid_angle.h +466 -0
- warp/native/sort.cpp +251 -0
- warp/native/sort.cu +277 -0
- warp/native/sort.h +33 -0
- warp/native/sparse.cpp +378 -0
- warp/native/sparse.cu +524 -0
- warp/native/spatial.h +657 -0
- warp/native/svd.h +702 -0
- warp/native/temp_buffer.h +46 -0
- warp/native/tile.h +2584 -0
- warp/native/tile_reduce.h +264 -0
- warp/native/vec.h +1426 -0
- warp/native/volume.cpp +501 -0
- warp/native/volume.cu +67 -0
- warp/native/volume.h +969 -0
- warp/native/volume_builder.cu +477 -0
- warp/native/volume_builder.h +52 -0
- warp/native/volume_impl.h +70 -0
- warp/native/warp.cpp +1082 -0
- warp/native/warp.cu +3636 -0
- warp/native/warp.h +381 -0
- warp/optim/__init__.py +17 -0
- warp/optim/adam.py +163 -0
- warp/optim/linear.py +1137 -0
- warp/optim/sgd.py +112 -0
- warp/paddle.py +407 -0
- warp/render/__init__.py +18 -0
- warp/render/render_opengl.py +3518 -0
- warp/render/render_usd.py +784 -0
- warp/render/utils.py +160 -0
- warp/sim/__init__.py +65 -0
- warp/sim/articulation.py +793 -0
- warp/sim/collide.py +2395 -0
- warp/sim/graph_coloring.py +300 -0
- warp/sim/import_mjcf.py +790 -0
- warp/sim/import_snu.py +227 -0
- warp/sim/import_urdf.py +579 -0
- warp/sim/import_usd.py +894 -0
- warp/sim/inertia.py +324 -0
- warp/sim/integrator.py +242 -0
- warp/sim/integrator_euler.py +1997 -0
- warp/sim/integrator_featherstone.py +2101 -0
- warp/sim/integrator_vbd.py +2048 -0
- warp/sim/integrator_xpbd.py +3292 -0
- warp/sim/model.py +4791 -0
- warp/sim/particles.py +121 -0
- warp/sim/render.py +427 -0
- warp/sim/utils.py +428 -0
- warp/sparse.py +2057 -0
- warp/stubs.py +3333 -0
- warp/tape.py +1203 -0
- warp/tests/__init__.py +1 -0
- warp/tests/__main__.py +4 -0
- warp/tests/assets/curlnoise_golden.npy +0 -0
- warp/tests/assets/mlp_golden.npy +0 -0
- warp/tests/assets/pixel.npy +0 -0
- warp/tests/assets/pnoise_golden.npy +0 -0
- warp/tests/assets/spiky.usd +0 -0
- warp/tests/assets/test_grid.nvdb +0 -0
- warp/tests/assets/test_index_grid.nvdb +0 -0
- warp/tests/assets/test_int32_grid.nvdb +0 -0
- warp/tests/assets/test_vec_grid.nvdb +0 -0
- warp/tests/assets/torus.nvdb +0 -0
- warp/tests/assets/torus.usda +105 -0
- warp/tests/aux_test_class_kernel.py +34 -0
- warp/tests/aux_test_compile_consts_dummy.py +18 -0
- warp/tests/aux_test_conditional_unequal_types_kernels.py +29 -0
- warp/tests/aux_test_dependent.py +29 -0
- warp/tests/aux_test_grad_customs.py +29 -0
- warp/tests/aux_test_instancing_gc.py +26 -0
- warp/tests/aux_test_module_unload.py +23 -0
- warp/tests/aux_test_name_clash1.py +40 -0
- warp/tests/aux_test_name_clash2.py +40 -0
- warp/tests/aux_test_reference.py +9 -0
- warp/tests/aux_test_reference_reference.py +8 -0
- warp/tests/aux_test_square.py +16 -0
- warp/tests/aux_test_unresolved_func.py +22 -0
- warp/tests/aux_test_unresolved_symbol.py +22 -0
- warp/tests/cuda/__init__.py +0 -0
- warp/tests/cuda/test_async.py +676 -0
- warp/tests/cuda/test_ipc.py +124 -0
- warp/tests/cuda/test_mempool.py +233 -0
- warp/tests/cuda/test_multigpu.py +169 -0
- warp/tests/cuda/test_peer.py +139 -0
- warp/tests/cuda/test_pinned.py +84 -0
- warp/tests/cuda/test_streams.py +634 -0
- warp/tests/geometry/__init__.py +0 -0
- warp/tests/geometry/test_bvh.py +200 -0
- warp/tests/geometry/test_hash_grid.py +221 -0
- warp/tests/geometry/test_marching_cubes.py +74 -0
- warp/tests/geometry/test_mesh.py +316 -0
- warp/tests/geometry/test_mesh_query_aabb.py +399 -0
- warp/tests/geometry/test_mesh_query_point.py +932 -0
- warp/tests/geometry/test_mesh_query_ray.py +311 -0
- warp/tests/geometry/test_volume.py +1103 -0
- warp/tests/geometry/test_volume_write.py +346 -0
- warp/tests/interop/__init__.py +0 -0
- warp/tests/interop/test_dlpack.py +729 -0
- warp/tests/interop/test_jax.py +371 -0
- warp/tests/interop/test_paddle.py +800 -0
- warp/tests/interop/test_torch.py +1001 -0
- warp/tests/run_coverage_serial.py +39 -0
- warp/tests/sim/__init__.py +0 -0
- warp/tests/sim/disabled_kinematics.py +244 -0
- warp/tests/sim/flaky_test_sim_grad.py +290 -0
- warp/tests/sim/test_collision.py +604 -0
- warp/tests/sim/test_coloring.py +258 -0
- warp/tests/sim/test_model.py +224 -0
- warp/tests/sim/test_sim_grad_bounce_linear.py +212 -0
- warp/tests/sim/test_sim_kinematics.py +98 -0
- warp/tests/sim/test_vbd.py +597 -0
- warp/tests/test_adam.py +163 -0
- warp/tests/test_arithmetic.py +1096 -0
- warp/tests/test_array.py +2972 -0
- warp/tests/test_array_reduce.py +156 -0
- warp/tests/test_assert.py +250 -0
- warp/tests/test_atomic.py +153 -0
- warp/tests/test_bool.py +220 -0
- warp/tests/test_builtins_resolution.py +1298 -0
- warp/tests/test_closest_point_edge_edge.py +327 -0
- warp/tests/test_codegen.py +810 -0
- warp/tests/test_codegen_instancing.py +1495 -0
- warp/tests/test_compile_consts.py +215 -0
- warp/tests/test_conditional.py +252 -0
- warp/tests/test_context.py +42 -0
- warp/tests/test_copy.py +238 -0
- warp/tests/test_ctypes.py +638 -0
- warp/tests/test_dense.py +73 -0
- warp/tests/test_devices.py +97 -0
- warp/tests/test_examples.py +482 -0
- warp/tests/test_fabricarray.py +996 -0
- warp/tests/test_fast_math.py +74 -0
- warp/tests/test_fem.py +2003 -0
- warp/tests/test_fp16.py +136 -0
- warp/tests/test_func.py +454 -0
- warp/tests/test_future_annotations.py +98 -0
- warp/tests/test_generics.py +656 -0
- warp/tests/test_grad.py +893 -0
- warp/tests/test_grad_customs.py +339 -0
- warp/tests/test_grad_debug.py +341 -0
- warp/tests/test_implicit_init.py +411 -0
- warp/tests/test_import.py +45 -0
- warp/tests/test_indexedarray.py +1140 -0
- warp/tests/test_intersect.py +73 -0
- warp/tests/test_iter.py +76 -0
- warp/tests/test_large.py +177 -0
- warp/tests/test_launch.py +411 -0
- warp/tests/test_lerp.py +151 -0
- warp/tests/test_linear_solvers.py +193 -0
- warp/tests/test_lvalue.py +427 -0
- warp/tests/test_mat.py +2089 -0
- warp/tests/test_mat_lite.py +122 -0
- warp/tests/test_mat_scalar_ops.py +2913 -0
- warp/tests/test_math.py +178 -0
- warp/tests/test_mlp.py +282 -0
- warp/tests/test_module_hashing.py +258 -0
- warp/tests/test_modules_lite.py +44 -0
- warp/tests/test_noise.py +252 -0
- warp/tests/test_operators.py +299 -0
- warp/tests/test_options.py +129 -0
- warp/tests/test_overwrite.py +551 -0
- warp/tests/test_print.py +339 -0
- warp/tests/test_quat.py +2315 -0
- warp/tests/test_rand.py +339 -0
- warp/tests/test_reload.py +302 -0
- warp/tests/test_rounding.py +185 -0
- warp/tests/test_runlength_encode.py +196 -0
- warp/tests/test_scalar_ops.py +105 -0
- warp/tests/test_smoothstep.py +108 -0
- warp/tests/test_snippet.py +318 -0
- warp/tests/test_sparse.py +582 -0
- warp/tests/test_spatial.py +2229 -0
- warp/tests/test_special_values.py +361 -0
- warp/tests/test_static.py +592 -0
- warp/tests/test_struct.py +734 -0
- warp/tests/test_tape.py +204 -0
- warp/tests/test_transient_module.py +93 -0
- warp/tests/test_triangle_closest_point.py +145 -0
- warp/tests/test_types.py +562 -0
- warp/tests/test_utils.py +588 -0
- warp/tests/test_vec.py +1487 -0
- warp/tests/test_vec_lite.py +80 -0
- warp/tests/test_vec_scalar_ops.py +2327 -0
- warp/tests/test_verify_fp.py +100 -0
- warp/tests/tile/__init__.py +0 -0
- warp/tests/tile/test_tile.py +780 -0
- warp/tests/tile/test_tile_load.py +407 -0
- warp/tests/tile/test_tile_mathdx.py +208 -0
- warp/tests/tile/test_tile_mlp.py +402 -0
- warp/tests/tile/test_tile_reduce.py +447 -0
- warp/tests/tile/test_tile_shared_memory.py +247 -0
- warp/tests/tile/test_tile_view.py +173 -0
- warp/tests/unittest_serial.py +47 -0
- warp/tests/unittest_suites.py +427 -0
- warp/tests/unittest_utils.py +468 -0
- warp/tests/walkthrough_debug.py +93 -0
- warp/thirdparty/__init__.py +0 -0
- warp/thirdparty/appdirs.py +598 -0
- warp/thirdparty/dlpack.py +145 -0
- warp/thirdparty/unittest_parallel.py +570 -0
- warp/torch.py +391 -0
- warp/types.py +5230 -0
- warp/utils.py +1137 -0
- warp_lang-1.7.0.dist-info/METADATA +516 -0
- warp_lang-1.7.0.dist-info/RECORD +429 -0
- warp_lang-1.7.0.dist-info/WHEEL +5 -0
- warp_lang-1.7.0.dist-info/licenses/LICENSE.md +202 -0
- warp_lang-1.7.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,834 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
import warp as wp
|
|
19
|
+
from warp.fem import cache
|
|
20
|
+
from warp.fem.types import Coords
|
|
21
|
+
|
|
22
|
+
from .shape_function import ShapeFunction
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _tet_node_index(tx: int, ty: int, tz: int, degree: int):
|
|
26
|
+
from .triangle_shape_function import _triangle_node_index
|
|
27
|
+
|
|
28
|
+
VERTEX_NODE_COUNT = 4
|
|
29
|
+
EDGE_INTERIOR_NODE_COUNT = degree - 1
|
|
30
|
+
VERTEX_EDGE_NODE_COUNT = VERTEX_NODE_COUNT + 6 * EDGE_INTERIOR_NODE_COUNT
|
|
31
|
+
FACE_INTERIOR_NODE_COUNT = (degree - 1) * (degree - 2) // 2
|
|
32
|
+
VERTEX_EDGE_FACE_NODE_COUNT = VERTEX_EDGE_NODE_COUNT + 4 * FACE_INTERIOR_NODE_COUNT
|
|
33
|
+
|
|
34
|
+
# Index in similar order to e.g. VTK
|
|
35
|
+
# First vertices, then edges (counterclockwise), then faces, then interior points (recursively)
|
|
36
|
+
|
|
37
|
+
if tx == 0:
|
|
38
|
+
if ty == 0:
|
|
39
|
+
if tz == 0:
|
|
40
|
+
return 0
|
|
41
|
+
elif tz == degree:
|
|
42
|
+
return 3
|
|
43
|
+
else:
|
|
44
|
+
# 0-3 edge
|
|
45
|
+
edge_index = 3
|
|
46
|
+
return VERTEX_NODE_COUNT + EDGE_INTERIOR_NODE_COUNT * edge_index + (tz - 1)
|
|
47
|
+
elif tz == 0:
|
|
48
|
+
if ty == degree:
|
|
49
|
+
return 2
|
|
50
|
+
else:
|
|
51
|
+
# 2-0 edge
|
|
52
|
+
edge_index = 2
|
|
53
|
+
return VERTEX_NODE_COUNT + EDGE_INTERIOR_NODE_COUNT * edge_index + (EDGE_INTERIOR_NODE_COUNT - ty)
|
|
54
|
+
elif tz + ty == degree:
|
|
55
|
+
# 2-3 edge
|
|
56
|
+
edge_index = 5
|
|
57
|
+
return VERTEX_NODE_COUNT + EDGE_INTERIOR_NODE_COUNT * edge_index + (tz - 1)
|
|
58
|
+
else:
|
|
59
|
+
# 2-3-0 face
|
|
60
|
+
face_index = 2
|
|
61
|
+
return (
|
|
62
|
+
VERTEX_EDGE_NODE_COUNT
|
|
63
|
+
+ FACE_INTERIOR_NODE_COUNT * face_index
|
|
64
|
+
+ _triangle_node_index(degree - 1 - ty - tz, tz - 1, degree - 3)
|
|
65
|
+
)
|
|
66
|
+
elif ty == 0:
|
|
67
|
+
if tz == 0:
|
|
68
|
+
if tx == degree:
|
|
69
|
+
return 1
|
|
70
|
+
else:
|
|
71
|
+
# 0-1 edge
|
|
72
|
+
edge_index = 0
|
|
73
|
+
return VERTEX_NODE_COUNT + EDGE_INTERIOR_NODE_COUNT * edge_index + (tx - 1)
|
|
74
|
+
elif tz + tx == degree:
|
|
75
|
+
# 1-3 edge
|
|
76
|
+
edge_index = 4
|
|
77
|
+
return VERTEX_NODE_COUNT + EDGE_INTERIOR_NODE_COUNT * edge_index + (tz - 1)
|
|
78
|
+
else:
|
|
79
|
+
# 3-0-1 face
|
|
80
|
+
face_index = 3
|
|
81
|
+
return (
|
|
82
|
+
VERTEX_EDGE_NODE_COUNT
|
|
83
|
+
+ FACE_INTERIOR_NODE_COUNT * face_index
|
|
84
|
+
+ _triangle_node_index(tx - 1, tz - 1, degree - 3)
|
|
85
|
+
)
|
|
86
|
+
elif tz == 0:
|
|
87
|
+
if tx + ty == degree:
|
|
88
|
+
# 1-2 edge
|
|
89
|
+
edge_index = 1
|
|
90
|
+
return VERTEX_NODE_COUNT + EDGE_INTERIOR_NODE_COUNT * edge_index + (ty - 1)
|
|
91
|
+
else:
|
|
92
|
+
# 0-1-2 face
|
|
93
|
+
face_index = 0
|
|
94
|
+
return (
|
|
95
|
+
VERTEX_EDGE_NODE_COUNT
|
|
96
|
+
+ FACE_INTERIOR_NODE_COUNT * face_index
|
|
97
|
+
+ _triangle_node_index(tx - 1, ty - 1, degree - 3)
|
|
98
|
+
)
|
|
99
|
+
elif tx + ty + tz == degree:
|
|
100
|
+
# 1-2-3 face
|
|
101
|
+
face_index = 1
|
|
102
|
+
return (
|
|
103
|
+
VERTEX_EDGE_NODE_COUNT
|
|
104
|
+
+ FACE_INTERIOR_NODE_COUNT * face_index
|
|
105
|
+
+ _triangle_node_index(tx - 1, tz - 1, degree - 3)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return VERTEX_EDGE_FACE_NODE_COUNT + _tet_node_index(tx - 1, ty - 1, tz - 1, degree - 4)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class TetrahedronShapeFunction(ShapeFunction):
|
|
112
|
+
VERTEX = wp.constant(0)
|
|
113
|
+
EDGE = wp.constant(1)
|
|
114
|
+
FACE = wp.constant(2)
|
|
115
|
+
INTERIOR = wp.constant(3)
|
|
116
|
+
|
|
117
|
+
VERTEX_NODE_COUNT: int
|
|
118
|
+
"""Number of shape function nodes per vertex"""
|
|
119
|
+
|
|
120
|
+
EDGE_NODE_COUNT: int
|
|
121
|
+
"""Number of shape function nodes per tet edge (excluding vertex nodes)"""
|
|
122
|
+
|
|
123
|
+
FACE_NODE_COUNT: int
|
|
124
|
+
"""Number of shape function nodes per tet face (excluding edge and vertex nodes)"""
|
|
125
|
+
|
|
126
|
+
INTERIOR_NODE_COUNT: int
|
|
127
|
+
"""Number of shape function nodes per tet (excluding face, edge and vertex nodes)"""
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def node_type_and_index(node_index_in_elt: int):
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
@wp.func
|
|
134
|
+
def edge_vidx(edge: int):
|
|
135
|
+
if edge < 3:
|
|
136
|
+
c1 = edge
|
|
137
|
+
c2 = (edge + 1) % 3
|
|
138
|
+
else:
|
|
139
|
+
c1 = edge - 3
|
|
140
|
+
c2 = 3
|
|
141
|
+
return c1, c2
|
|
142
|
+
|
|
143
|
+
@wp.func
|
|
144
|
+
def opposite_edge_vidx(edge: int):
|
|
145
|
+
if edge < 3:
|
|
146
|
+
e1 = (edge + 2) % 3
|
|
147
|
+
e2 = 3
|
|
148
|
+
else:
|
|
149
|
+
e1 = (edge - 2) % 3
|
|
150
|
+
e2 = (edge - 1) % 3
|
|
151
|
+
return e1, e2
|
|
152
|
+
|
|
153
|
+
@wp.func
|
|
154
|
+
def _vertex_coords(vidx: int):
|
|
155
|
+
return wp.vec3(
|
|
156
|
+
float(vidx == 1),
|
|
157
|
+
float(vidx == 2),
|
|
158
|
+
float(vidx == 3),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class TetrahedronPolynomialShapeFunctions(TetrahedronShapeFunction):
|
|
163
|
+
def __init__(self, degree: int):
|
|
164
|
+
self.ORDER = wp.constant(degree)
|
|
165
|
+
|
|
166
|
+
self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 2) * (degree + 3) // 6)
|
|
167
|
+
self.NODES_PER_SIDE = wp.constant((degree + 1) * (degree + 2) // 2)
|
|
168
|
+
|
|
169
|
+
self.VERTEX_NODE_COUNT = wp.constant(1)
|
|
170
|
+
self.EDGE_NODE_COUNT = wp.constant(degree - 1)
|
|
171
|
+
self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 2) * (degree + 3) // 6)
|
|
172
|
+
self.NODES_PER_SIDE = wp.constant((degree + 1) * (degree + 2) // 2)
|
|
173
|
+
|
|
174
|
+
self.SIDE_NODE_COUNT = wp.constant(self.NODES_PER_ELEMENT - 3 * (self.VERTEX_NODE_COUNT + self.EDGE_NODE_COUNT))
|
|
175
|
+
self.INTERIOR_NODE_COUNT = wp.constant(
|
|
176
|
+
self.NODES_PER_ELEMENT - 3 * (self.VERTEX_NODE_COUNT + self.EDGE_NODE_COUNT)
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
self.VERTEX_NODE_COUNT = wp.constant(1)
|
|
180
|
+
self.EDGE_NODE_COUNT = wp.constant(degree - 1)
|
|
181
|
+
self.FACE_NODE_COUNT = wp.constant(max(0, degree - 2) * max(0, degree - 1) // 2)
|
|
182
|
+
self.INERIOR_NODE_COUNT = wp.constant(max(0, degree - 1) * max(0, degree - 2) * max(0, degree - 3) // 6)
|
|
183
|
+
|
|
184
|
+
tet_coords = np.empty((self.NODES_PER_ELEMENT, 3), dtype=int)
|
|
185
|
+
|
|
186
|
+
for tx in range(degree + 1):
|
|
187
|
+
for ty in range(degree + 1 - tx):
|
|
188
|
+
for tz in range(degree + 1 - tx - ty):
|
|
189
|
+
index = _tet_node_index(tx, ty, tz, degree)
|
|
190
|
+
tet_coords[index] = [tx, ty, tz]
|
|
191
|
+
|
|
192
|
+
CoordTypeVec = wp.mat(dtype=int, shape=(self.NODES_PER_ELEMENT, 3))
|
|
193
|
+
self.NODE_TET_COORDS = wp.constant(CoordTypeVec(tet_coords))
|
|
194
|
+
|
|
195
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
196
|
+
self._node_tet_coordinates = self._get_node_tet_coordinates()
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def name(self) -> str:
|
|
200
|
+
return f"Tet_P{self.ORDER}"
|
|
201
|
+
|
|
202
|
+
def _get_node_tet_coordinates(self):
|
|
203
|
+
NODE_TET_COORDS = self.NODE_TET_COORDS
|
|
204
|
+
|
|
205
|
+
def node_tet_coordinates(
|
|
206
|
+
node_index_in_elt: int,
|
|
207
|
+
):
|
|
208
|
+
return NODE_TET_COORDS[node_index_in_elt]
|
|
209
|
+
|
|
210
|
+
return cache.get_func(node_tet_coordinates, self.name)
|
|
211
|
+
|
|
212
|
+
def _get_node_type_and_type_index(self):
|
|
213
|
+
ORDER = self.ORDER
|
|
214
|
+
|
|
215
|
+
def node_type_and_index(
|
|
216
|
+
node_index_in_elt: int,
|
|
217
|
+
):
|
|
218
|
+
if node_index_in_elt < 4:
|
|
219
|
+
return TetrahedronPolynomialShapeFunctions.VERTEX, node_index_in_elt
|
|
220
|
+
|
|
221
|
+
if node_index_in_elt < (6 * ORDER - 2):
|
|
222
|
+
return TetrahedronPolynomialShapeFunctions.EDGE, (node_index_in_elt - 4)
|
|
223
|
+
|
|
224
|
+
if node_index_in_elt < (2 * ORDER * ORDER + 2):
|
|
225
|
+
return TetrahedronPolynomialShapeFunctions.FACE, (node_index_in_elt - (6 * ORDER - 2))
|
|
226
|
+
|
|
227
|
+
return TetrahedronPolynomialShapeFunctions.INTERIOR, (node_index_in_elt - (2 * ORDER * ORDER + 2))
|
|
228
|
+
|
|
229
|
+
return cache.get_func(node_type_and_index, self.name)
|
|
230
|
+
|
|
231
|
+
def make_node_coords_in_element(self):
|
|
232
|
+
ORDER = self.ORDER
|
|
233
|
+
|
|
234
|
+
def node_coords_in_element(
|
|
235
|
+
node_index_in_elt: int,
|
|
236
|
+
):
|
|
237
|
+
tet_coords = self._node_tet_coordinates(node_index_in_elt)
|
|
238
|
+
cx = float(tet_coords[0]) / float(ORDER)
|
|
239
|
+
cy = float(tet_coords[1]) / float(ORDER)
|
|
240
|
+
cz = float(tet_coords[2]) / float(ORDER)
|
|
241
|
+
return Coords(cx, cy, cz)
|
|
242
|
+
|
|
243
|
+
return cache.get_func(node_coords_in_element, self.name)
|
|
244
|
+
|
|
245
|
+
def make_node_quadrature_weight(self):
|
|
246
|
+
if self.ORDER == 3:
|
|
247
|
+
# Order 1, but optimized quadrature weights for monomials of order <= 6
|
|
248
|
+
vertex_weight = 0.007348845656
|
|
249
|
+
edge_weight = 0.020688129855
|
|
250
|
+
face_weight = 0.180586764778
|
|
251
|
+
interior_weight = 0.0
|
|
252
|
+
else:
|
|
253
|
+
vertex_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
254
|
+
edge_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
255
|
+
face_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
256
|
+
interior_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
257
|
+
|
|
258
|
+
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
259
|
+
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
260
|
+
FACE_WEIGHT = wp.constant(face_weight)
|
|
261
|
+
INTERIOR_WEIGHT = wp.constant(interior_weight)
|
|
262
|
+
|
|
263
|
+
@cache.dynamic_func(suffix=self.name)
|
|
264
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
265
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_element)
|
|
266
|
+
|
|
267
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
268
|
+
return VERTEX_WEIGHT
|
|
269
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
270
|
+
return EDGE_WEIGHT
|
|
271
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.FACE:
|
|
272
|
+
return FACE_WEIGHT
|
|
273
|
+
|
|
274
|
+
return INTERIOR_WEIGHT
|
|
275
|
+
|
|
276
|
+
return node_quadrature_weight
|
|
277
|
+
|
|
278
|
+
def make_trace_node_quadrature_weight(self):
|
|
279
|
+
if self.ORDER == 3:
|
|
280
|
+
# P3 intrinsic quadrature
|
|
281
|
+
vertex_weight = 1.0 / 30
|
|
282
|
+
edge_weight = 0.075
|
|
283
|
+
interior_weight = 0.45
|
|
284
|
+
elif self.ORDER == 2:
|
|
285
|
+
# Order 1, but optimized quadrature weights for monomials of order <= 4
|
|
286
|
+
vertex_weight = 0.022335964126
|
|
287
|
+
edge_weight = 0.310997369207
|
|
288
|
+
interior_weight = 0.0
|
|
289
|
+
else:
|
|
290
|
+
vertex_weight = 1.0 / self.NODES_PER_SIDE
|
|
291
|
+
edge_weight = 1.0 / self.NODES_PER_SIDE
|
|
292
|
+
interior_weight = 1.0 / self.NODES_PER_SIDE
|
|
293
|
+
|
|
294
|
+
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
295
|
+
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
296
|
+
FACE_INTERIOR_WEIGHT = wp.constant(interior_weight)
|
|
297
|
+
|
|
298
|
+
@cache.dynamic_func(suffix=self.name)
|
|
299
|
+
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
300
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_element)
|
|
301
|
+
|
|
302
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
303
|
+
return VERTEX_WEIGHT
|
|
304
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
305
|
+
return EDGE_WEIGHT
|
|
306
|
+
|
|
307
|
+
return FACE_INTERIOR_WEIGHT
|
|
308
|
+
|
|
309
|
+
return trace_node_quadrature_weight
|
|
310
|
+
|
|
311
|
+
def make_element_inner_weight(self):
|
|
312
|
+
ORDER = self.ORDER
|
|
313
|
+
|
|
314
|
+
def element_inner_weight_linear(
|
|
315
|
+
coords: Coords,
|
|
316
|
+
node_index_in_elt: int,
|
|
317
|
+
):
|
|
318
|
+
if node_index_in_elt < 0 or node_index_in_elt >= 4:
|
|
319
|
+
return 0.0
|
|
320
|
+
|
|
321
|
+
tet_coords = wp.vec4(1.0 - coords[0] - coords[1] - coords[2], coords[0], coords[1], coords[2])
|
|
322
|
+
return tet_coords[node_index_in_elt]
|
|
323
|
+
|
|
324
|
+
def element_inner_weight_quadratic(
|
|
325
|
+
coords: Coords,
|
|
326
|
+
node_index_in_elt: int,
|
|
327
|
+
):
|
|
328
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
329
|
+
|
|
330
|
+
tet_coords = wp.vec4(1.0 - coords[0] - coords[1] - coords[2], coords[0], coords[1], coords[2])
|
|
331
|
+
|
|
332
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
333
|
+
# Vertex
|
|
334
|
+
return tet_coords[type_index] * (2.0 * tet_coords[type_index] - 1.0)
|
|
335
|
+
|
|
336
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
337
|
+
# Edge
|
|
338
|
+
c1, c2 = TetrahedronShapeFunction.edge_vidx(type_index)
|
|
339
|
+
return 4.0 * tet_coords[c1] * tet_coords[c2]
|
|
340
|
+
|
|
341
|
+
return 0.0
|
|
342
|
+
|
|
343
|
+
def element_inner_weight_cubic(
|
|
344
|
+
coords: Coords,
|
|
345
|
+
node_index_in_elt: int,
|
|
346
|
+
):
|
|
347
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
348
|
+
|
|
349
|
+
tet_coords = wp.vec4(1.0 - coords[0] - coords[1] - coords[2], coords[0], coords[1], coords[2])
|
|
350
|
+
|
|
351
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
352
|
+
# Vertex
|
|
353
|
+
return (
|
|
354
|
+
0.5
|
|
355
|
+
* tet_coords[type_index]
|
|
356
|
+
* (3.0 * tet_coords[type_index] - 1.0)
|
|
357
|
+
* (3.0 * tet_coords[type_index] - 2.0)
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
361
|
+
# Edge
|
|
362
|
+
edge = type_index // 2
|
|
363
|
+
edge_node = type_index - 2 * edge
|
|
364
|
+
|
|
365
|
+
if edge < 3:
|
|
366
|
+
c1 = (edge + edge_node) % 3
|
|
367
|
+
c2 = (edge + 1 - edge_node) % 3
|
|
368
|
+
elif edge_node == 0:
|
|
369
|
+
c1 = edge - 3
|
|
370
|
+
c2 = 3
|
|
371
|
+
else:
|
|
372
|
+
c1 = 3
|
|
373
|
+
c2 = edge - 3
|
|
374
|
+
|
|
375
|
+
return 4.5 * tet_coords[c1] * tet_coords[c2] * (3.0 * tet_coords[c1] - 1.0)
|
|
376
|
+
|
|
377
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.FACE:
|
|
378
|
+
# Interior
|
|
379
|
+
c1 = type_index
|
|
380
|
+
c2 = (c1 + 1) % 4
|
|
381
|
+
c3 = (c1 + 2) % 4
|
|
382
|
+
return 27.0 * tet_coords[c1] * tet_coords[c2] * tet_coords[c3]
|
|
383
|
+
|
|
384
|
+
return 0.0
|
|
385
|
+
|
|
386
|
+
if ORDER == 1:
|
|
387
|
+
return cache.get_func(element_inner_weight_linear, self.name)
|
|
388
|
+
elif ORDER == 2:
|
|
389
|
+
return cache.get_func(element_inner_weight_quadratic, self.name)
|
|
390
|
+
elif ORDER == 3:
|
|
391
|
+
return cache.get_func(element_inner_weight_cubic, self.name)
|
|
392
|
+
|
|
393
|
+
return None
|
|
394
|
+
|
|
395
|
+
def make_element_inner_weight_gradient(self):
|
|
396
|
+
ORDER = self.ORDER
|
|
397
|
+
|
|
398
|
+
def element_inner_weight_gradient_linear(
|
|
399
|
+
coords: Coords,
|
|
400
|
+
node_index_in_elt: int,
|
|
401
|
+
):
|
|
402
|
+
if node_index_in_elt < 0 or node_index_in_elt >= 4:
|
|
403
|
+
return wp.vec3(0.0)
|
|
404
|
+
|
|
405
|
+
dw_dc = wp.vec4(0.0)
|
|
406
|
+
dw_dc[node_index_in_elt] = 1.0
|
|
407
|
+
|
|
408
|
+
dw_du = wp.vec3(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0], dw_dc[3] - dw_dc[0])
|
|
409
|
+
|
|
410
|
+
return dw_du
|
|
411
|
+
|
|
412
|
+
def element_inner_weight_gradient_quadratic(
|
|
413
|
+
coords: Coords,
|
|
414
|
+
node_index_in_elt: int,
|
|
415
|
+
):
|
|
416
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
417
|
+
|
|
418
|
+
tet_coords = wp.vec4(1.0 - coords[0] - coords[1] - coords[2], coords[0], coords[1], coords[2])
|
|
419
|
+
dw_dc = wp.vec4(0.0)
|
|
420
|
+
|
|
421
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
422
|
+
# Vertex
|
|
423
|
+
dw_dc[type_index] = 4.0 * tet_coords[type_index] - 1.0
|
|
424
|
+
|
|
425
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
426
|
+
# Edge
|
|
427
|
+
c1, c2 = TetrahedronShapeFunction.edge_vidx(type_index)
|
|
428
|
+
dw_dc[c1] = 4.0 * tet_coords[c2]
|
|
429
|
+
dw_dc[c2] = 4.0 * tet_coords[c1]
|
|
430
|
+
|
|
431
|
+
dw_du = wp.vec3(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0], dw_dc[3] - dw_dc[0])
|
|
432
|
+
return dw_du
|
|
433
|
+
|
|
434
|
+
def element_inner_weight_gradient_cubic(
|
|
435
|
+
coords: Coords,
|
|
436
|
+
node_index_in_elt: int,
|
|
437
|
+
):
|
|
438
|
+
node_type, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
439
|
+
|
|
440
|
+
tet_coords = wp.vec4(1.0 - coords[0] - coords[1] - coords[2], coords[0], coords[1], coords[2])
|
|
441
|
+
|
|
442
|
+
dw_dc = wp.vec4(0.0)
|
|
443
|
+
|
|
444
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
445
|
+
# Vertex
|
|
446
|
+
dw_dc[type_index] = (
|
|
447
|
+
0.5 * 27.0 * tet_coords[type_index] * tet_coords[type_index] - 9.0 * tet_coords[type_index] + 1.0
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
451
|
+
# Edge
|
|
452
|
+
edge = type_index // 2
|
|
453
|
+
edge_node = type_index - 2 * edge
|
|
454
|
+
|
|
455
|
+
if edge < 3:
|
|
456
|
+
c1 = (edge + edge_node) % 3
|
|
457
|
+
c2 = (edge + 1 - edge_node) % 3
|
|
458
|
+
elif edge_node == 0:
|
|
459
|
+
c1 = edge - 3
|
|
460
|
+
c2 = 3
|
|
461
|
+
else:
|
|
462
|
+
c1 = 3
|
|
463
|
+
c2 = edge - 3
|
|
464
|
+
|
|
465
|
+
dw_dc[c1] = 4.5 * tet_coords[c2] * (6.0 * tet_coords[c1] - 1.0)
|
|
466
|
+
dw_dc[c2] = 4.5 * tet_coords[c1] * (3.0 * tet_coords[c1] - 1.0)
|
|
467
|
+
|
|
468
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.FACE:
|
|
469
|
+
# Interior
|
|
470
|
+
c1 = type_index
|
|
471
|
+
c2 = (c1 + 1) % 4
|
|
472
|
+
c3 = (c1 + 2) % 4
|
|
473
|
+
|
|
474
|
+
dw_dc[c1] = 27.0 * tet_coords[c2] * tet_coords[c3]
|
|
475
|
+
dw_dc[c2] = 27.0 * tet_coords[c3] * tet_coords[c1]
|
|
476
|
+
dw_dc[c3] = 27.0 * tet_coords[c1] * tet_coords[c2]
|
|
477
|
+
|
|
478
|
+
dw_du = wp.vec3(dw_dc[1] - dw_dc[0], dw_dc[2] - dw_dc[0], dw_dc[3] - dw_dc[0])
|
|
479
|
+
return dw_du
|
|
480
|
+
|
|
481
|
+
if ORDER == 1:
|
|
482
|
+
return cache.get_func(element_inner_weight_gradient_linear, self.name)
|
|
483
|
+
elif ORDER == 2:
|
|
484
|
+
return cache.get_func(element_inner_weight_gradient_quadratic, self.name)
|
|
485
|
+
elif ORDER == 3:
|
|
486
|
+
return cache.get_func(element_inner_weight_gradient_cubic, self.name)
|
|
487
|
+
|
|
488
|
+
return None
|
|
489
|
+
|
|
490
|
+
def element_node_tets(self):
|
|
491
|
+
if self.ORDER == 1:
|
|
492
|
+
element_tets = [[0, 1, 2, 3]]
|
|
493
|
+
if self.ORDER == 2:
|
|
494
|
+
element_tets = [
|
|
495
|
+
[0, 4, 6, 7],
|
|
496
|
+
[1, 5, 4, 8],
|
|
497
|
+
[2, 6, 5, 9],
|
|
498
|
+
[3, 7, 8, 9],
|
|
499
|
+
[4, 5, 6, 8],
|
|
500
|
+
[8, 7, 9, 6],
|
|
501
|
+
[6, 5, 9, 8],
|
|
502
|
+
[6, 8, 7, 4],
|
|
503
|
+
]
|
|
504
|
+
elif self.ORDER == 3:
|
|
505
|
+
raise NotImplementedError()
|
|
506
|
+
|
|
507
|
+
return np.array(element_tets)
|
|
508
|
+
|
|
509
|
+
def element_vtk_cells(self):
|
|
510
|
+
cells = np.arange(self.NODES_PER_ELEMENT)
|
|
511
|
+
if self.ORDER == 1:
|
|
512
|
+
cell_type = 10 # VTK_TETRA
|
|
513
|
+
else:
|
|
514
|
+
cell_type = 71 # VTK_LAGRANGE_TETRAHEDRON
|
|
515
|
+
return cells[np.newaxis, :], np.array([cell_type], dtype=np.int8)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
class TetrahedronNonConformingPolynomialShapeFunctions(ShapeFunction):
|
|
519
|
+
def __init__(self, degree: int):
|
|
520
|
+
self._tet_shape = TetrahedronPolynomialShapeFunctions(degree=degree)
|
|
521
|
+
self.ORDER = self._tet_shape.ORDER
|
|
522
|
+
self.NODES_PER_ELEMENT = self._tet_shape.NODES_PER_ELEMENT
|
|
523
|
+
|
|
524
|
+
self.element_node_tets = self._tet_shape.element_node_tets
|
|
525
|
+
self.element_vtk_cells = self._tet_shape.element_vtk_cells
|
|
526
|
+
|
|
527
|
+
if self.ORDER == 1:
|
|
528
|
+
self._TET_SCALE = 0.4472135955 # so v at 0.5854101966249680 (order 2)
|
|
529
|
+
elif self.ORDER == 2:
|
|
530
|
+
self._TET_SCALE = 0.6123779296874996 # optimized for low intrinsic quadrature error of deg 4
|
|
531
|
+
elif self.ORDER == 3:
|
|
532
|
+
self._TET_SCALE = 0.7153564453124999 # optimized for low intrinsic quadrature error of deg 6
|
|
533
|
+
else:
|
|
534
|
+
self._TET_SCALE = 1.0
|
|
535
|
+
|
|
536
|
+
self._TET_SCALE = wp.constant(self._TET_SCALE)
|
|
537
|
+
self._TET_OFFSET = wp.constant((1.0 - self._TET_SCALE) * wp.vec3(0.25, 0.25, 0.25))
|
|
538
|
+
|
|
539
|
+
@property
|
|
540
|
+
def name(self) -> str:
|
|
541
|
+
return f"Tet_P{self.ORDER}d"
|
|
542
|
+
|
|
543
|
+
def make_node_coords_in_element(self):
|
|
544
|
+
node_coords_in_tet = self._tet_shape.make_node_coords_in_element()
|
|
545
|
+
|
|
546
|
+
TET_SCALE = self._TET_SCALE
|
|
547
|
+
TET_OFFSET = self._TET_OFFSET
|
|
548
|
+
|
|
549
|
+
@cache.dynamic_func(suffix=self.name)
|
|
550
|
+
def node_coords_in_element(
|
|
551
|
+
node_index_in_elt: int,
|
|
552
|
+
):
|
|
553
|
+
tet_coords = node_coords_in_tet(node_index_in_elt)
|
|
554
|
+
return TET_SCALE * tet_coords + TET_OFFSET
|
|
555
|
+
|
|
556
|
+
return node_coords_in_element
|
|
557
|
+
|
|
558
|
+
def make_node_quadrature_weight(self):
|
|
559
|
+
# Intrinsic quadrature -- precomputed integral of node shape functions
|
|
560
|
+
# over element. Order equal to self.ORDER
|
|
561
|
+
|
|
562
|
+
if self.ORDER == 2:
|
|
563
|
+
vertex_weight = 0.07499641
|
|
564
|
+
edge_weight = 0.11666908
|
|
565
|
+
face_interior_weight = 0.0
|
|
566
|
+
elif self.ORDER == 3:
|
|
567
|
+
vertex_weight = 0.03345134
|
|
568
|
+
edge_weight = 0.04521887
|
|
569
|
+
face_interior_weight = 0.08089206
|
|
570
|
+
else:
|
|
571
|
+
vertex_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
572
|
+
edge_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
573
|
+
face_interior_weight = 1.0 / self.NODES_PER_ELEMENT
|
|
574
|
+
|
|
575
|
+
VERTEX_WEIGHT = wp.constant(vertex_weight)
|
|
576
|
+
EDGE_WEIGHT = wp.constant(edge_weight)
|
|
577
|
+
FACE_INTERIOR_WEIGHT = wp.constant(face_interior_weight)
|
|
578
|
+
|
|
579
|
+
@cache.dynamic_func(suffix=self.name)
|
|
580
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
581
|
+
node_type, type_index = self._tet_shape.node_type_and_type_index(node_index_in_element)
|
|
582
|
+
|
|
583
|
+
if node_type == TetrahedronPolynomialShapeFunctions.VERTEX:
|
|
584
|
+
return VERTEX_WEIGHT
|
|
585
|
+
elif node_type == TetrahedronPolynomialShapeFunctions.EDGE:
|
|
586
|
+
return EDGE_WEIGHT
|
|
587
|
+
|
|
588
|
+
return FACE_INTERIOR_WEIGHT
|
|
589
|
+
|
|
590
|
+
return node_quadrature_weight
|
|
591
|
+
|
|
592
|
+
def make_trace_node_quadrature_weight(self):
|
|
593
|
+
# Non-conforming, zero measure on sides
|
|
594
|
+
|
|
595
|
+
@wp.func
|
|
596
|
+
def zero(node_index_in_elt: int):
|
|
597
|
+
return 0.0
|
|
598
|
+
|
|
599
|
+
return zero
|
|
600
|
+
|
|
601
|
+
def make_element_inner_weight(self):
|
|
602
|
+
tet_inner_weight = self._tet_shape.make_element_inner_weight()
|
|
603
|
+
|
|
604
|
+
TET_SCALE = self._TET_SCALE
|
|
605
|
+
TET_OFFSET = self._TET_OFFSET
|
|
606
|
+
|
|
607
|
+
@cache.dynamic_func(suffix=self.name)
|
|
608
|
+
def element_inner_weight(
|
|
609
|
+
coords: Coords,
|
|
610
|
+
node_index_in_elt: int,
|
|
611
|
+
):
|
|
612
|
+
tet_coords = (coords - TET_OFFSET) / TET_SCALE
|
|
613
|
+
|
|
614
|
+
return tet_inner_weight(tet_coords, node_index_in_elt)
|
|
615
|
+
|
|
616
|
+
return element_inner_weight
|
|
617
|
+
|
|
618
|
+
def make_element_inner_weight_gradient(self):
|
|
619
|
+
tet_inner_weight_gradient = self._tet_shape.make_element_inner_weight_gradient()
|
|
620
|
+
|
|
621
|
+
TET_SCALE = self._TET_SCALE
|
|
622
|
+
TET_OFFSET = self._TET_OFFSET
|
|
623
|
+
|
|
624
|
+
@cache.dynamic_func(suffix=self.name)
|
|
625
|
+
def element_inner_weight_gradient(
|
|
626
|
+
coords: Coords,
|
|
627
|
+
node_index_in_elt: int,
|
|
628
|
+
):
|
|
629
|
+
tet_coords = (coords - TET_OFFSET) / TET_SCALE
|
|
630
|
+
grad = tet_inner_weight_gradient(tet_coords, node_index_in_elt)
|
|
631
|
+
return grad / TET_SCALE
|
|
632
|
+
|
|
633
|
+
return element_inner_weight_gradient
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
class TetrahedronNedelecFirstKindShapeFunctions(TetrahedronShapeFunction):
|
|
637
|
+
value = ShapeFunction.Value.CovariantVector
|
|
638
|
+
|
|
639
|
+
def __init__(self, degree: int):
|
|
640
|
+
if degree != 1:
|
|
641
|
+
raise NotImplementedError("Only linear Nédélec implemented right now")
|
|
642
|
+
|
|
643
|
+
self.ORDER = wp.constant(degree)
|
|
644
|
+
|
|
645
|
+
self.NODES_PER_ELEMENT = wp.constant(6)
|
|
646
|
+
self.NODES_PER_SIDE = wp.constant(3)
|
|
647
|
+
|
|
648
|
+
self.VERTEX_NODE_COUNT = wp.constant(0)
|
|
649
|
+
self.EDGE_NODE_COUNT = wp.constant(1)
|
|
650
|
+
self.FACE_NODE_COUNT = wp.constant(0)
|
|
651
|
+
self.INTERIOR_NODE_COUNT = wp.constant(0)
|
|
652
|
+
|
|
653
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
654
|
+
|
|
655
|
+
@property
|
|
656
|
+
def name(self) -> str:
|
|
657
|
+
return f"TetN1_{self.ORDER}"
|
|
658
|
+
|
|
659
|
+
def _get_node_type_and_type_index(self):
|
|
660
|
+
@cache.dynamic_func(suffix=self.name)
|
|
661
|
+
def node_type_and_index(
|
|
662
|
+
node_index_in_elt: int,
|
|
663
|
+
):
|
|
664
|
+
return TetrahedronShapeFunction.EDGE, node_index_in_elt
|
|
665
|
+
|
|
666
|
+
return node_type_and_index
|
|
667
|
+
|
|
668
|
+
def make_node_coords_in_element(self):
|
|
669
|
+
@cache.dynamic_func(suffix=self.name)
|
|
670
|
+
def node_coords_in_element(
|
|
671
|
+
node_index_in_elt: int,
|
|
672
|
+
):
|
|
673
|
+
c1, c2 = TetrahedronShapeFunction.edge_vidx(node_index_in_elt)
|
|
674
|
+
|
|
675
|
+
coords = wp.vec4(0.0)
|
|
676
|
+
coords[c1] = 0.5
|
|
677
|
+
coords[c2] = 0.5
|
|
678
|
+
|
|
679
|
+
return Coords(coords[1], coords[2], coords[3])
|
|
680
|
+
|
|
681
|
+
return node_coords_in_element
|
|
682
|
+
|
|
683
|
+
def make_node_quadrature_weight(self):
|
|
684
|
+
NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
|
|
685
|
+
|
|
686
|
+
@cache.dynamic_func(suffix=self.name)
|
|
687
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
688
|
+
return 1.0 / float(NODES_PER_ELEMENT)
|
|
689
|
+
|
|
690
|
+
return node_quadrature_weight
|
|
691
|
+
|
|
692
|
+
def make_trace_node_quadrature_weight(self):
|
|
693
|
+
NODES_PER_SIDE = self.NODES_PER_SIDE
|
|
694
|
+
|
|
695
|
+
@cache.dynamic_func(suffix=self.name)
|
|
696
|
+
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
697
|
+
return 1.0 / float(NODES_PER_SIDE)
|
|
698
|
+
|
|
699
|
+
return trace_node_quadrature_weight
|
|
700
|
+
|
|
701
|
+
def make_element_inner_weight(self):
|
|
702
|
+
ORDER = self.ORDER
|
|
703
|
+
|
|
704
|
+
def element_inner_weight_linear(
|
|
705
|
+
coords: Coords,
|
|
706
|
+
node_index_in_elt: int,
|
|
707
|
+
):
|
|
708
|
+
e1, e2 = TetrahedronShapeFunction.opposite_edge_vidx(node_index_in_elt)
|
|
709
|
+
|
|
710
|
+
v1 = self._vertex_coords(e1)
|
|
711
|
+
v2 = self._vertex_coords(e2)
|
|
712
|
+
|
|
713
|
+
nor = v2 - v1
|
|
714
|
+
return wp.cross(nor, coords - v1)
|
|
715
|
+
|
|
716
|
+
if ORDER == 1:
|
|
717
|
+
return cache.get_func(element_inner_weight_linear, self.name)
|
|
718
|
+
|
|
719
|
+
return None
|
|
720
|
+
|
|
721
|
+
def make_element_inner_weight_gradient(self):
|
|
722
|
+
ORDER = self.ORDER
|
|
723
|
+
|
|
724
|
+
def element_inner_weight_gradient_linear(
|
|
725
|
+
coords: Coords,
|
|
726
|
+
node_index_in_elt: int,
|
|
727
|
+
):
|
|
728
|
+
e1, e2 = TetrahedronShapeFunction.opposite_edge_vidx(node_index_in_elt)
|
|
729
|
+
|
|
730
|
+
v1 = self._vertex_coords(e1)
|
|
731
|
+
v2 = self._vertex_coords(e2)
|
|
732
|
+
|
|
733
|
+
nor = v2 - v1
|
|
734
|
+
return wp.skew(nor)
|
|
735
|
+
|
|
736
|
+
if ORDER == 1:
|
|
737
|
+
return cache.get_func(element_inner_weight_gradient_linear, self.name)
|
|
738
|
+
|
|
739
|
+
return None
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
class TetrahedronRaviartThomasShapeFunctions(TetrahedronShapeFunction):
|
|
743
|
+
value = ShapeFunction.Value.ContravariantVector
|
|
744
|
+
|
|
745
|
+
def __init__(self, degree: int):
|
|
746
|
+
if degree != 1:
|
|
747
|
+
raise NotImplementedError("Only linear Raviart-Thomas implemented right now")
|
|
748
|
+
|
|
749
|
+
self.ORDER = wp.constant(degree)
|
|
750
|
+
|
|
751
|
+
self.NODES_PER_ELEMENT = wp.constant(4)
|
|
752
|
+
self.NODES_PER_SIDE = wp.constant(1)
|
|
753
|
+
|
|
754
|
+
self.VERTEX_NODE_COUNT = wp.constant(0)
|
|
755
|
+
self.EDGE_NODE_COUNT = wp.constant(0)
|
|
756
|
+
self.FACE_NODE_COUNT = wp.constant(1)
|
|
757
|
+
self.INTERIOR_NODE_COUNT = wp.constant(0)
|
|
758
|
+
|
|
759
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
760
|
+
|
|
761
|
+
@property
|
|
762
|
+
def name(self) -> str:
|
|
763
|
+
return f"TetRT_{self.ORDER}"
|
|
764
|
+
|
|
765
|
+
def _get_node_type_and_type_index(self):
|
|
766
|
+
@cache.dynamic_func(suffix=self.name)
|
|
767
|
+
def node_type_and_index(
|
|
768
|
+
node_index_in_elt: int,
|
|
769
|
+
):
|
|
770
|
+
return TetrahedronShapeFunction.FACE, node_index_in_elt
|
|
771
|
+
|
|
772
|
+
return node_type_and_index
|
|
773
|
+
|
|
774
|
+
def make_node_coords_in_element(self):
|
|
775
|
+
@cache.dynamic_func(suffix=self.name)
|
|
776
|
+
def node_coords_in_element(
|
|
777
|
+
node_index_in_elt: int,
|
|
778
|
+
):
|
|
779
|
+
v = (node_index_in_elt + 3) % 4
|
|
780
|
+
|
|
781
|
+
coords = wp.vec4(1.0 / 3.0)
|
|
782
|
+
coords[v] = 0.0
|
|
783
|
+
|
|
784
|
+
return Coords(coords[1], coords[2], coords[3])
|
|
785
|
+
|
|
786
|
+
return node_coords_in_element
|
|
787
|
+
|
|
788
|
+
def make_node_quadrature_weight(self):
|
|
789
|
+
NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
|
|
790
|
+
|
|
791
|
+
@cache.dynamic_func(suffix=self.name)
|
|
792
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
793
|
+
return 1.0 / float(NODES_PER_ELEMENT)
|
|
794
|
+
|
|
795
|
+
return node_quadrature_weight
|
|
796
|
+
|
|
797
|
+
def make_trace_node_quadrature_weight(self):
|
|
798
|
+
NODES_PER_SIDE = self.NODES_PER_SIDE
|
|
799
|
+
|
|
800
|
+
@cache.dynamic_func(suffix=self.name)
|
|
801
|
+
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
802
|
+
return 1.0 / float(NODES_PER_SIDE)
|
|
803
|
+
|
|
804
|
+
return trace_node_quadrature_weight
|
|
805
|
+
|
|
806
|
+
def make_element_inner_weight(self):
|
|
807
|
+
ORDER = self.ORDER
|
|
808
|
+
|
|
809
|
+
def element_inner_weight_linear(
|
|
810
|
+
coords: Coords,
|
|
811
|
+
node_index_in_elt: int,
|
|
812
|
+
):
|
|
813
|
+
v = (node_index_in_elt + 3) % 4
|
|
814
|
+
|
|
815
|
+
return 2.0 * (coords - self._vertex_coords(v))
|
|
816
|
+
|
|
817
|
+
if ORDER == 1:
|
|
818
|
+
return cache.get_func(element_inner_weight_linear, self.name)
|
|
819
|
+
|
|
820
|
+
return None
|
|
821
|
+
|
|
822
|
+
def make_element_inner_weight_gradient(self):
|
|
823
|
+
ORDER = self.ORDER
|
|
824
|
+
|
|
825
|
+
def element_inner_weight_gradient_linear(
|
|
826
|
+
coords: Coords,
|
|
827
|
+
node_index_in_elt: int,
|
|
828
|
+
):
|
|
829
|
+
return 2.0 * wp.identity(n=3, dtype=float)
|
|
830
|
+
|
|
831
|
+
if ORDER == 1:
|
|
832
|
+
return cache.get_func(element_inner_weight_gradient_linear, self.name)
|
|
833
|
+
|
|
834
|
+
return None
|