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,926 @@
|
|
|
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 math
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
import warp as wp
|
|
21
|
+
from warp.fem import cache
|
|
22
|
+
from warp.fem.polynomial import Polynomial, is_closed, lagrange_scales, quadrature_1d
|
|
23
|
+
from warp.fem.types import Coords
|
|
24
|
+
|
|
25
|
+
from .shape_function import ShapeFunction
|
|
26
|
+
from .triangle_shape_function import TrianglePolynomialShapeFunctions
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SquareShapeFunction(ShapeFunction):
|
|
30
|
+
VERTEX = 0
|
|
31
|
+
EDGE_X = 1
|
|
32
|
+
EDGE_Y = 2
|
|
33
|
+
INTERIOR = 3
|
|
34
|
+
|
|
35
|
+
VERTEX_NODE_COUNT: int
|
|
36
|
+
"""Number of shape function nodes per vertex"""
|
|
37
|
+
|
|
38
|
+
EDGE_NODE_COUNT: int
|
|
39
|
+
"""Number of shape function nodes per triangle edge (excluding vertex nodes)"""
|
|
40
|
+
|
|
41
|
+
INTERIOR_NODE_COUNT: int
|
|
42
|
+
"""Number of shape function nodes per triangle (excluding edge and vertex nodes)"""
|
|
43
|
+
|
|
44
|
+
@wp.func
|
|
45
|
+
def _vertex_coords_f(vidx_in_cell: int):
|
|
46
|
+
x = vidx_in_cell // 2
|
|
47
|
+
y = vidx_in_cell - 2 * x
|
|
48
|
+
return wp.vec2(float(x), float(y))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class SquareBipolynomialShapeFunctions(SquareShapeFunction):
|
|
52
|
+
def __init__(self, degree: int, family: Polynomial):
|
|
53
|
+
self.family = family
|
|
54
|
+
|
|
55
|
+
self.ORDER = wp.constant(degree)
|
|
56
|
+
self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 1))
|
|
57
|
+
self.NODES_PER_SIDE = wp.constant(degree + 1)
|
|
58
|
+
|
|
59
|
+
if is_closed(self.family):
|
|
60
|
+
self.VERTEX_NODE_COUNT = wp.constant(1)
|
|
61
|
+
self.EDGE_NODE_COUNT = wp.constant(max(0, degree - 1))
|
|
62
|
+
self.INTERIOR_NODE_COUNT = wp.constant(max(0, degree - 1) ** 2)
|
|
63
|
+
else:
|
|
64
|
+
self.VERTEX_NODE_COUNT = wp.constant(0)
|
|
65
|
+
self.EDGE_NODE_COUNT = wp.constant(0)
|
|
66
|
+
self.INTERIOR_NODE_COUNT = self.NODES_PER_ELEMENT
|
|
67
|
+
|
|
68
|
+
lobatto_coords, lobatto_weight = quadrature_1d(point_count=degree + 1, family=family)
|
|
69
|
+
lagrange_scale = lagrange_scales(lobatto_coords)
|
|
70
|
+
|
|
71
|
+
NodeVec = wp.types.vector(length=degree + 1, dtype=wp.float32)
|
|
72
|
+
self.LOBATTO_COORDS = wp.constant(NodeVec(lobatto_coords))
|
|
73
|
+
self.LOBATTO_WEIGHT = wp.constant(NodeVec(lobatto_weight))
|
|
74
|
+
self.LAGRANGE_SCALE = wp.constant(NodeVec(lagrange_scale))
|
|
75
|
+
self.ORDER_PLUS_ONE = wp.constant(self.ORDER + 1)
|
|
76
|
+
|
|
77
|
+
self._node_ij = self._make_node_ij()
|
|
78
|
+
self.node_type_and_type_index = self._make_node_type_and_type_index()
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def name(self) -> str:
|
|
82
|
+
return f"Square_Q{self.ORDER}_{self.family}"
|
|
83
|
+
|
|
84
|
+
def _make_node_ij(self):
|
|
85
|
+
ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
|
|
86
|
+
|
|
87
|
+
def node_ij(node_index_in_elt: int):
|
|
88
|
+
node_i = node_index_in_elt // ORDER_PLUS_ONE
|
|
89
|
+
node_j = node_index_in_elt - ORDER_PLUS_ONE * node_i
|
|
90
|
+
return node_i, node_j
|
|
91
|
+
|
|
92
|
+
return cache.get_func(node_ij, self.name)
|
|
93
|
+
|
|
94
|
+
def _make_node_type_and_type_index(self):
|
|
95
|
+
ORDER = self.ORDER
|
|
96
|
+
|
|
97
|
+
@cache.dynamic_func(suffix=self.name)
|
|
98
|
+
def node_type_and_type_index_open(
|
|
99
|
+
node_index_in_elt: int,
|
|
100
|
+
):
|
|
101
|
+
return SquareShapeFunction.INTERIOR, 0, node_index_in_elt
|
|
102
|
+
|
|
103
|
+
@cache.dynamic_func(suffix=self.name)
|
|
104
|
+
def node_type_and_type_index(
|
|
105
|
+
node_index_in_elt: int,
|
|
106
|
+
):
|
|
107
|
+
i, j = self._node_ij(node_index_in_elt)
|
|
108
|
+
|
|
109
|
+
zi = int(i == 0)
|
|
110
|
+
zj = int(j == 0)
|
|
111
|
+
|
|
112
|
+
mi = int(i == ORDER)
|
|
113
|
+
mj = int(j == ORDER)
|
|
114
|
+
|
|
115
|
+
if zi + mi == 1:
|
|
116
|
+
if zj + mj == 1:
|
|
117
|
+
# vertex
|
|
118
|
+
type_instance = mi * 2 + mj
|
|
119
|
+
return SquareShapeFunction.VERTEX, type_instance, 0
|
|
120
|
+
# y edge
|
|
121
|
+
type_index = j - 1
|
|
122
|
+
type_instance = mi
|
|
123
|
+
return SquareShapeFunction.EDGE_Y, type_instance, type_index
|
|
124
|
+
elif zj + mj == 1:
|
|
125
|
+
# x edge
|
|
126
|
+
type_index = i - 1
|
|
127
|
+
type_instance = mj
|
|
128
|
+
return SquareShapeFunction.EDGE_X, type_instance, type_index
|
|
129
|
+
|
|
130
|
+
type_index = (i - 1) * (ORDER - 1) + (j - 1)
|
|
131
|
+
return SquareShapeFunction.INTERIOR, 0, type_index
|
|
132
|
+
|
|
133
|
+
return node_type_and_type_index if is_closed(self.family) else node_type_and_type_index_open
|
|
134
|
+
|
|
135
|
+
def make_node_coords_in_element(self):
|
|
136
|
+
LOBATTO_COORDS = self.LOBATTO_COORDS
|
|
137
|
+
|
|
138
|
+
@cache.dynamic_func(suffix=self.name)
|
|
139
|
+
def node_coords_in_element(
|
|
140
|
+
node_index_in_elt: int,
|
|
141
|
+
):
|
|
142
|
+
node_i, node_j = self._node_ij(node_index_in_elt)
|
|
143
|
+
return Coords(LOBATTO_COORDS[node_i], LOBATTO_COORDS[node_j], 0.0)
|
|
144
|
+
|
|
145
|
+
return node_coords_in_element
|
|
146
|
+
|
|
147
|
+
def make_node_quadrature_weight(self):
|
|
148
|
+
ORDER = self.ORDER
|
|
149
|
+
LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
|
|
150
|
+
|
|
151
|
+
def node_quadrature_weight(
|
|
152
|
+
node_index_in_elt: int,
|
|
153
|
+
):
|
|
154
|
+
node_i, node_j = self._node_ij(node_index_in_elt)
|
|
155
|
+
return LOBATTO_WEIGHT[node_i] * LOBATTO_WEIGHT[node_j]
|
|
156
|
+
|
|
157
|
+
def node_quadrature_weight_linear(
|
|
158
|
+
node_index_in_elt: int,
|
|
159
|
+
):
|
|
160
|
+
return 0.25
|
|
161
|
+
|
|
162
|
+
if ORDER == 1:
|
|
163
|
+
return cache.get_func(node_quadrature_weight_linear, self.name)
|
|
164
|
+
|
|
165
|
+
return cache.get_func(node_quadrature_weight, self.name)
|
|
166
|
+
|
|
167
|
+
def make_trace_node_quadrature_weight(self):
|
|
168
|
+
ORDER = self.ORDER
|
|
169
|
+
LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
|
|
170
|
+
|
|
171
|
+
def trace_node_quadrature_weight(
|
|
172
|
+
node_index_in_elt: int,
|
|
173
|
+
):
|
|
174
|
+
# We're either on a side interior or at a vertex
|
|
175
|
+
# I.e., either both indices are at extrema, or only one is
|
|
176
|
+
# Pick the interior one if possible, if both are at extrema pick any one
|
|
177
|
+
node_i, node_j = self._node_ij(node_index_in_elt)
|
|
178
|
+
if node_i > 0 and node_i < ORDER:
|
|
179
|
+
return LOBATTO_WEIGHT[node_i]
|
|
180
|
+
|
|
181
|
+
return LOBATTO_WEIGHT[node_j]
|
|
182
|
+
|
|
183
|
+
def trace_node_quadrature_weight_linear(
|
|
184
|
+
node_index_in_elt: int,
|
|
185
|
+
):
|
|
186
|
+
return 0.5
|
|
187
|
+
|
|
188
|
+
def trace_node_quadrature_weight_open(
|
|
189
|
+
node_index_in_elt: int,
|
|
190
|
+
):
|
|
191
|
+
return 0.0
|
|
192
|
+
|
|
193
|
+
if not is_closed(self.family):
|
|
194
|
+
return cache.get_func(trace_node_quadrature_weight_open, self.name)
|
|
195
|
+
|
|
196
|
+
if ORDER == 1:
|
|
197
|
+
return cache.get_func(trace_node_quadrature_weight_linear, self.name)
|
|
198
|
+
|
|
199
|
+
return cache.get_func(trace_node_quadrature_weight, self.name)
|
|
200
|
+
|
|
201
|
+
def make_element_inner_weight(self):
|
|
202
|
+
ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
|
|
203
|
+
LOBATTO_COORDS = self.LOBATTO_COORDS
|
|
204
|
+
LAGRANGE_SCALE = self.LAGRANGE_SCALE
|
|
205
|
+
|
|
206
|
+
def element_inner_weight(
|
|
207
|
+
coords: Coords,
|
|
208
|
+
node_index_in_elt: int,
|
|
209
|
+
):
|
|
210
|
+
node_i, node_j = self._node_ij(node_index_in_elt)
|
|
211
|
+
|
|
212
|
+
w = float(1.0)
|
|
213
|
+
for k in range(ORDER_PLUS_ONE):
|
|
214
|
+
if k != node_i:
|
|
215
|
+
w *= coords[0] - LOBATTO_COORDS[k]
|
|
216
|
+
if k != node_j:
|
|
217
|
+
w *= coords[1] - LOBATTO_COORDS[k]
|
|
218
|
+
|
|
219
|
+
w *= LAGRANGE_SCALE[node_i] * LAGRANGE_SCALE[node_j]
|
|
220
|
+
|
|
221
|
+
return w
|
|
222
|
+
|
|
223
|
+
def element_inner_weight_linear(
|
|
224
|
+
coords: Coords,
|
|
225
|
+
node_index_in_elt: int,
|
|
226
|
+
):
|
|
227
|
+
v = SquareBipolynomialShapeFunctions._vertex_coords_f(node_index_in_elt)
|
|
228
|
+
|
|
229
|
+
wx = (1.0 - coords[0]) * (1.0 - v[0]) + v[0] * coords[0]
|
|
230
|
+
wy = (1.0 - coords[1]) * (1.0 - v[1]) + v[1] * coords[1]
|
|
231
|
+
return wx * wy
|
|
232
|
+
|
|
233
|
+
if self.ORDER == 1 and is_closed(self.family):
|
|
234
|
+
return cache.get_func(element_inner_weight_linear, self.name)
|
|
235
|
+
|
|
236
|
+
return cache.get_func(element_inner_weight, self.name)
|
|
237
|
+
|
|
238
|
+
def make_element_inner_weight_gradient(self):
|
|
239
|
+
ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
|
|
240
|
+
LOBATTO_COORDS = self.LOBATTO_COORDS
|
|
241
|
+
LAGRANGE_SCALE = self.LAGRANGE_SCALE
|
|
242
|
+
|
|
243
|
+
def element_inner_weight_gradient(
|
|
244
|
+
coords: Coords,
|
|
245
|
+
node_index_in_elt: int,
|
|
246
|
+
):
|
|
247
|
+
node_i, node_j = self._node_ij(node_index_in_elt)
|
|
248
|
+
|
|
249
|
+
prefix_x = float(1.0)
|
|
250
|
+
prefix_y = float(1.0)
|
|
251
|
+
for k in range(ORDER_PLUS_ONE):
|
|
252
|
+
if k != node_i:
|
|
253
|
+
prefix_y *= coords[0] - LOBATTO_COORDS[k]
|
|
254
|
+
if k != node_j:
|
|
255
|
+
prefix_x *= coords[1] - LOBATTO_COORDS[k]
|
|
256
|
+
|
|
257
|
+
grad_x = float(0.0)
|
|
258
|
+
grad_y = float(0.0)
|
|
259
|
+
|
|
260
|
+
for k in range(ORDER_PLUS_ONE):
|
|
261
|
+
if k != node_i:
|
|
262
|
+
delta_x = coords[0] - LOBATTO_COORDS[k]
|
|
263
|
+
grad_x = grad_x * delta_x + prefix_x
|
|
264
|
+
prefix_x *= delta_x
|
|
265
|
+
if k != node_j:
|
|
266
|
+
delta_y = coords[1] - LOBATTO_COORDS[k]
|
|
267
|
+
grad_y = grad_y * delta_y + prefix_y
|
|
268
|
+
prefix_y *= delta_y
|
|
269
|
+
|
|
270
|
+
grad = LAGRANGE_SCALE[node_i] * LAGRANGE_SCALE[node_j] * wp.vec2(grad_x, grad_y)
|
|
271
|
+
|
|
272
|
+
return grad
|
|
273
|
+
|
|
274
|
+
def element_inner_weight_gradient_linear(
|
|
275
|
+
coords: Coords,
|
|
276
|
+
node_index_in_elt: int,
|
|
277
|
+
):
|
|
278
|
+
v = SquareBipolynomialShapeFunctions._vertex_coords_f(node_index_in_elt)
|
|
279
|
+
|
|
280
|
+
wx = (1.0 - coords[0]) * (1.0 - v[0]) + v[0] * coords[0]
|
|
281
|
+
wy = (1.0 - coords[1]) * (1.0 - v[1]) + v[1] * coords[1]
|
|
282
|
+
|
|
283
|
+
dx = 2.0 * v[0] - 1.0
|
|
284
|
+
dy = 2.0 * v[1] - 1.0
|
|
285
|
+
|
|
286
|
+
return wp.vec2(dx * wy, dy * wx)
|
|
287
|
+
|
|
288
|
+
if self.ORDER == 1 and is_closed(self.family):
|
|
289
|
+
return cache.get_func(element_inner_weight_gradient_linear, self.name)
|
|
290
|
+
|
|
291
|
+
return cache.get_func(element_inner_weight_gradient, self.name)
|
|
292
|
+
|
|
293
|
+
def element_node_triangulation(self):
|
|
294
|
+
from warp.fem.utils import grid_to_tris
|
|
295
|
+
|
|
296
|
+
return grid_to_tris(self.ORDER, self.ORDER)
|
|
297
|
+
|
|
298
|
+
def element_vtk_cells(self):
|
|
299
|
+
n = self.ORDER + 1
|
|
300
|
+
|
|
301
|
+
# vertices
|
|
302
|
+
cells = [[0, (n - 1) * n, n * n - 1, n - 1]]
|
|
303
|
+
|
|
304
|
+
if self.ORDER == 1:
|
|
305
|
+
cell_type = 9 # VTK_QUAD
|
|
306
|
+
else:
|
|
307
|
+
middle = np.arange(1, n - 1)
|
|
308
|
+
|
|
309
|
+
# edges
|
|
310
|
+
cells.append(middle * n)
|
|
311
|
+
cells.append(middle + (n - 1) * n)
|
|
312
|
+
cells.append(middle * n + n - 1)
|
|
313
|
+
cells.append(middle)
|
|
314
|
+
|
|
315
|
+
# faces
|
|
316
|
+
interior = np.broadcast_to(middle, (n - 2, n - 2))
|
|
317
|
+
cells.append((interior * n + interior.transpose()).flatten())
|
|
318
|
+
|
|
319
|
+
cell_type = 70 # VTK_LAGRANGE_QUADRILATERAL
|
|
320
|
+
|
|
321
|
+
return np.concatenate(cells)[np.newaxis, :], np.array([cell_type], dtype=np.int8)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class SquareSerendipityShapeFunctions(SquareShapeFunction):
|
|
325
|
+
"""
|
|
326
|
+
Serendipity element ~ tensor product space without interior nodes
|
|
327
|
+
Side shape functions are usual Lagrange shape functions times a linear function in the normal direction
|
|
328
|
+
Corner shape functions are bilinear shape functions times a function of (x^{d-1} + y^{d-1})
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
def __init__(self, degree: int, family: Polynomial):
|
|
332
|
+
if not is_closed(family):
|
|
333
|
+
raise ValueError("A closed polynomial family is required to define serendipity elements")
|
|
334
|
+
|
|
335
|
+
if degree not in [2, 3]:
|
|
336
|
+
raise NotImplementedError("Serendipity element only implemented for order 2 or 3")
|
|
337
|
+
|
|
338
|
+
self.family = family
|
|
339
|
+
|
|
340
|
+
self.ORDER = wp.constant(degree)
|
|
341
|
+
self.NODES_PER_ELEMENT = wp.constant(4 * degree)
|
|
342
|
+
self.NODES_PER_SIDE = wp.constant(degree + 1)
|
|
343
|
+
|
|
344
|
+
self.VERTEX_NODE_COUNT = wp.constant(1)
|
|
345
|
+
self.EDGE_NODE_COUNT = wp.constant(degree - 1)
|
|
346
|
+
self.INTERIOR_NODE_COUNT = wp.constant(0)
|
|
347
|
+
|
|
348
|
+
lobatto_coords, lobatto_weight = quadrature_1d(point_count=degree + 1, family=family)
|
|
349
|
+
lagrange_scale = lagrange_scales(lobatto_coords)
|
|
350
|
+
|
|
351
|
+
NodeVec = wp.types.vector(length=degree + 1, dtype=wp.float32)
|
|
352
|
+
self.LOBATTO_COORDS = wp.constant(NodeVec(lobatto_coords))
|
|
353
|
+
self.LOBATTO_WEIGHT = wp.constant(NodeVec(lobatto_weight))
|
|
354
|
+
self.LAGRANGE_SCALE = wp.constant(NodeVec(lagrange_scale))
|
|
355
|
+
self.ORDER_PLUS_ONE = wp.constant(self.ORDER + 1)
|
|
356
|
+
|
|
357
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
358
|
+
self._node_lobatto_indices = self._get_node_lobatto_indices()
|
|
359
|
+
|
|
360
|
+
@property
|
|
361
|
+
def name(self) -> str:
|
|
362
|
+
return f"Square_S{self.ORDER}_{self.family}"
|
|
363
|
+
|
|
364
|
+
def _get_node_type_and_type_index(self):
|
|
365
|
+
@cache.dynamic_func(suffix=self.name)
|
|
366
|
+
def node_type_and_index(
|
|
367
|
+
node_index_in_elt: int,
|
|
368
|
+
):
|
|
369
|
+
if node_index_in_elt < 4:
|
|
370
|
+
return SquareSerendipityShapeFunctions.VERTEX, node_index_in_elt, 0
|
|
371
|
+
|
|
372
|
+
edge_index = (node_index_in_elt - 4) // 2
|
|
373
|
+
edge_axis = node_index_in_elt - 4 - 2 * edge_index
|
|
374
|
+
|
|
375
|
+
index_in_side = edge_index // 2
|
|
376
|
+
side_offset = edge_index - 2 * index_in_side
|
|
377
|
+
return SquareSerendipityShapeFunctions.EDGE_X + edge_axis, side_offset, index_in_side
|
|
378
|
+
|
|
379
|
+
return node_type_and_index
|
|
380
|
+
|
|
381
|
+
def _get_node_lobatto_indices(self):
|
|
382
|
+
ORDER = self.ORDER
|
|
383
|
+
|
|
384
|
+
@cache.dynamic_func(suffix=self.name)
|
|
385
|
+
def node_lobatto_indices(node_type: int, type_instance: int, type_index: int):
|
|
386
|
+
if node_type == SquareSerendipityShapeFunctions.VERTEX:
|
|
387
|
+
node_i = type_instance // 2
|
|
388
|
+
node_j = type_instance - 2 * node_i
|
|
389
|
+
return node_i * ORDER, node_j * ORDER
|
|
390
|
+
|
|
391
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_X:
|
|
392
|
+
node_i = 1 + type_index
|
|
393
|
+
node_j = type_instance * ORDER
|
|
394
|
+
else:
|
|
395
|
+
node_j = 1 + type_index
|
|
396
|
+
node_i = type_instance * ORDER
|
|
397
|
+
|
|
398
|
+
return node_i, node_j
|
|
399
|
+
|
|
400
|
+
return node_lobatto_indices
|
|
401
|
+
|
|
402
|
+
def make_node_coords_in_element(self):
|
|
403
|
+
LOBATTO_COORDS = self.LOBATTO_COORDS
|
|
404
|
+
|
|
405
|
+
@cache.dynamic_func(suffix=self.name)
|
|
406
|
+
def node_coords_in_element(
|
|
407
|
+
node_index_in_elt: int,
|
|
408
|
+
):
|
|
409
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
410
|
+
node_i, node_j = self._node_lobatto_indices(node_type, type_instance, type_index)
|
|
411
|
+
return Coords(LOBATTO_COORDS[node_i], LOBATTO_COORDS[node_j], 0.0)
|
|
412
|
+
|
|
413
|
+
return node_coords_in_element
|
|
414
|
+
|
|
415
|
+
def make_node_quadrature_weight(self):
|
|
416
|
+
ORDER = self.ORDER
|
|
417
|
+
|
|
418
|
+
@cache.dynamic_func(suffix=self.name)
|
|
419
|
+
def node_quadrature_weight(
|
|
420
|
+
node_index_in_elt: int,
|
|
421
|
+
):
|
|
422
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
423
|
+
if node_type == SquareSerendipityShapeFunctions.VERTEX:
|
|
424
|
+
return 0.25 / float(ORDER * ORDER)
|
|
425
|
+
|
|
426
|
+
return (0.25 - 0.25 / float(ORDER * ORDER)) / float(ORDER - 1)
|
|
427
|
+
|
|
428
|
+
return node_quadrature_weight
|
|
429
|
+
|
|
430
|
+
def make_trace_node_quadrature_weight(self):
|
|
431
|
+
LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
|
|
432
|
+
|
|
433
|
+
@cache.dynamic_func(suffix=self.name)
|
|
434
|
+
def trace_node_quadrature_weight(
|
|
435
|
+
node_index_in_elt: int,
|
|
436
|
+
):
|
|
437
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
438
|
+
if node_type == SquareSerendipityShapeFunctions.VERTEX:
|
|
439
|
+
return LOBATTO_WEIGHT[0]
|
|
440
|
+
|
|
441
|
+
return LOBATTO_WEIGHT[1 + type_index]
|
|
442
|
+
|
|
443
|
+
return trace_node_quadrature_weight
|
|
444
|
+
|
|
445
|
+
def make_element_inner_weight(self):
|
|
446
|
+
ORDER = self.ORDER
|
|
447
|
+
ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
|
|
448
|
+
|
|
449
|
+
LOBATTO_COORDS = self.LOBATTO_COORDS
|
|
450
|
+
LAGRANGE_SCALE = self.LAGRANGE_SCALE
|
|
451
|
+
|
|
452
|
+
DEGREE_3_CIRCLE_RAD = wp.constant(0.5**2 + (0.5 - LOBATTO_COORDS[1]) ** 2)
|
|
453
|
+
DEGREE_3_CIRCLE_SCALE = 1.0 / (0.5 - DEGREE_3_CIRCLE_RAD)
|
|
454
|
+
|
|
455
|
+
@cache.dynamic_func(suffix=self.name)
|
|
456
|
+
def element_inner_weight(
|
|
457
|
+
coords: Coords,
|
|
458
|
+
node_index_in_elt: int,
|
|
459
|
+
):
|
|
460
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
461
|
+
node_i, node_j = self._node_lobatto_indices(node_type, type_instance, type_index)
|
|
462
|
+
|
|
463
|
+
if node_type == SquareSerendipityShapeFunctions.VERTEX:
|
|
464
|
+
cx = wp.where(node_i == 0, 1.0 - coords[0], coords[0])
|
|
465
|
+
cy = wp.where(node_j == 0, 1.0 - coords[1], coords[1])
|
|
466
|
+
|
|
467
|
+
w = cx * cy
|
|
468
|
+
|
|
469
|
+
if ORDER == 2:
|
|
470
|
+
w *= cx + cy - 2.0 + LOBATTO_COORDS[1]
|
|
471
|
+
return w * LAGRANGE_SCALE[0]
|
|
472
|
+
if ORDER == 3:
|
|
473
|
+
w *= (cx - 0.5) * (cx - 0.5) + (cy - 0.5) * (cy - 0.5) - DEGREE_3_CIRCLE_RAD
|
|
474
|
+
return w * DEGREE_3_CIRCLE_SCALE
|
|
475
|
+
|
|
476
|
+
w = float(1.0)
|
|
477
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_Y:
|
|
478
|
+
w *= wp.where(node_i == 0, 1.0 - coords[0], coords[0])
|
|
479
|
+
else:
|
|
480
|
+
for k in range(ORDER_PLUS_ONE):
|
|
481
|
+
if k != node_i:
|
|
482
|
+
w *= coords[0] - LOBATTO_COORDS[k]
|
|
483
|
+
|
|
484
|
+
w *= LAGRANGE_SCALE[node_i]
|
|
485
|
+
|
|
486
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_X:
|
|
487
|
+
w *= wp.where(node_j == 0, 1.0 - coords[1], coords[1])
|
|
488
|
+
else:
|
|
489
|
+
for k in range(ORDER_PLUS_ONE):
|
|
490
|
+
if k != node_j:
|
|
491
|
+
w *= coords[1] - LOBATTO_COORDS[k]
|
|
492
|
+
w *= LAGRANGE_SCALE[node_j]
|
|
493
|
+
|
|
494
|
+
return w
|
|
495
|
+
|
|
496
|
+
return element_inner_weight
|
|
497
|
+
|
|
498
|
+
def make_element_inner_weight_gradient(self):
|
|
499
|
+
ORDER = self.ORDER
|
|
500
|
+
ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
|
|
501
|
+
LOBATTO_COORDS = self.LOBATTO_COORDS
|
|
502
|
+
LAGRANGE_SCALE = self.LAGRANGE_SCALE
|
|
503
|
+
|
|
504
|
+
DEGREE_3_CIRCLE_RAD = wp.constant(0.5**2 + (0.5 - LOBATTO_COORDS[1]) ** 2)
|
|
505
|
+
DEGREE_3_CIRCLE_SCALE = 1.0 / (0.5 - DEGREE_3_CIRCLE_RAD)
|
|
506
|
+
|
|
507
|
+
@cache.dynamic_func(suffix=self.name)
|
|
508
|
+
def element_inner_weight_gradient(
|
|
509
|
+
coords: Coords,
|
|
510
|
+
node_index_in_elt: int,
|
|
511
|
+
):
|
|
512
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
513
|
+
node_i, node_j = self._node_lobatto_indices(node_type, type_instance, type_index)
|
|
514
|
+
|
|
515
|
+
if node_type == SquareSerendipityShapeFunctions.VERTEX:
|
|
516
|
+
cx = wp.where(node_i == 0, 1.0 - coords[0], coords[0])
|
|
517
|
+
cy = wp.where(node_j == 0, 1.0 - coords[1], coords[1])
|
|
518
|
+
|
|
519
|
+
gx = wp.where(node_i == 0, -1.0, 1.0)
|
|
520
|
+
gy = wp.where(node_j == 0, -1.0, 1.0)
|
|
521
|
+
|
|
522
|
+
if ORDER == 2:
|
|
523
|
+
w = cx + cy - 2.0 + LOBATTO_COORDS[1]
|
|
524
|
+
grad_x = cy * gx * (w + cx)
|
|
525
|
+
grad_y = cx * gy * (w + cy)
|
|
526
|
+
|
|
527
|
+
return wp.vec2(grad_x, grad_y) * LAGRANGE_SCALE[0]
|
|
528
|
+
|
|
529
|
+
if ORDER == 3:
|
|
530
|
+
w = (cx - 0.5) * (cx - 0.5) + (cy - 0.5) * (cy - 0.5) - DEGREE_3_CIRCLE_RAD
|
|
531
|
+
|
|
532
|
+
dw_dcx = 2.0 * cx - 1.0
|
|
533
|
+
dw_dcy = 2.0 * cy - 1.0
|
|
534
|
+
grad_x = cy * gx * (w + cx * dw_dcx)
|
|
535
|
+
grad_y = cx * gy * (w + cy * dw_dcy)
|
|
536
|
+
|
|
537
|
+
return wp.vec2(grad_x, grad_y) * DEGREE_3_CIRCLE_SCALE
|
|
538
|
+
|
|
539
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_X:
|
|
540
|
+
prefix_x = wp.where(node_j == 0, 1.0 - coords[1], coords[1])
|
|
541
|
+
else:
|
|
542
|
+
prefix_x = LAGRANGE_SCALE[node_j]
|
|
543
|
+
for k in range(ORDER_PLUS_ONE):
|
|
544
|
+
if k != node_j:
|
|
545
|
+
prefix_x *= coords[1] - LOBATTO_COORDS[k]
|
|
546
|
+
|
|
547
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_Y:
|
|
548
|
+
prefix_y = wp.where(node_i == 0, 1.0 - coords[0], coords[0])
|
|
549
|
+
else:
|
|
550
|
+
prefix_y = LAGRANGE_SCALE[node_i]
|
|
551
|
+
for k in range(ORDER_PLUS_ONE):
|
|
552
|
+
if k != node_i:
|
|
553
|
+
prefix_y *= coords[0] - LOBATTO_COORDS[k]
|
|
554
|
+
|
|
555
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_X:
|
|
556
|
+
grad_y = wp.where(node_j == 0, -1.0, 1.0) * prefix_y
|
|
557
|
+
else:
|
|
558
|
+
prefix_y *= LAGRANGE_SCALE[node_j]
|
|
559
|
+
grad_y = float(0.0)
|
|
560
|
+
for k in range(ORDER_PLUS_ONE):
|
|
561
|
+
if k != node_j:
|
|
562
|
+
delta_y = coords[1] - LOBATTO_COORDS[k]
|
|
563
|
+
grad_y = grad_y * delta_y + prefix_y
|
|
564
|
+
prefix_y *= delta_y
|
|
565
|
+
|
|
566
|
+
if node_type == SquareSerendipityShapeFunctions.EDGE_Y:
|
|
567
|
+
grad_x = wp.where(node_i == 0, -1.0, 1.0) * prefix_x
|
|
568
|
+
else:
|
|
569
|
+
prefix_x *= LAGRANGE_SCALE[node_i]
|
|
570
|
+
grad_x = float(0.0)
|
|
571
|
+
for k in range(ORDER_PLUS_ONE):
|
|
572
|
+
if k != node_i:
|
|
573
|
+
delta_x = coords[0] - LOBATTO_COORDS[k]
|
|
574
|
+
grad_x = grad_x * delta_x + prefix_x
|
|
575
|
+
prefix_x *= delta_x
|
|
576
|
+
|
|
577
|
+
grad = wp.vec2(grad_x, grad_y)
|
|
578
|
+
return grad
|
|
579
|
+
|
|
580
|
+
return element_inner_weight_gradient
|
|
581
|
+
|
|
582
|
+
def element_node_triangulation(self):
|
|
583
|
+
if self.ORDER == 2:
|
|
584
|
+
element_triangles = [
|
|
585
|
+
[0, 4, 5],
|
|
586
|
+
[5, 4, 6],
|
|
587
|
+
[5, 6, 1],
|
|
588
|
+
[4, 2, 7],
|
|
589
|
+
[4, 7, 6],
|
|
590
|
+
[6, 7, 3],
|
|
591
|
+
]
|
|
592
|
+
else:
|
|
593
|
+
element_triangles = [
|
|
594
|
+
[0, 4, 5],
|
|
595
|
+
[2, 7, 8],
|
|
596
|
+
[3, 10, 11],
|
|
597
|
+
[1, 9, 6],
|
|
598
|
+
[5, 6, 9],
|
|
599
|
+
[5, 4, 6],
|
|
600
|
+
[8, 11, 10],
|
|
601
|
+
[8, 7, 11],
|
|
602
|
+
[4, 8, 10],
|
|
603
|
+
[4, 10, 6],
|
|
604
|
+
]
|
|
605
|
+
|
|
606
|
+
return element_triangles
|
|
607
|
+
|
|
608
|
+
def element_vtk_cells(self):
|
|
609
|
+
tris = np.array(self.element_node_triangulation())
|
|
610
|
+
cell_type = 5 # VTK_TRIANGLE
|
|
611
|
+
|
|
612
|
+
return tris, np.full(tris.shape[0], cell_type, dtype=np.int8)
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
class SquareNonConformingPolynomialShapeFunctions(ShapeFunction):
|
|
616
|
+
# embeds the largest equilateral triangle centered at (0.5, 0.5) into the reference square
|
|
617
|
+
_tri_height = 0.75
|
|
618
|
+
_tri_side = 2.0 / math.sqrt(3.0) * _tri_height
|
|
619
|
+
_tri_to_square = np.array([[_tri_side, _tri_side / 2.0], [0.0, _tri_height]])
|
|
620
|
+
|
|
621
|
+
_TRI_OFFSET = wp.constant(wp.vec2(0.5 - 0.5 * _tri_side, 0.5 - _tri_height / 3.0))
|
|
622
|
+
|
|
623
|
+
def __init__(self, degree: int):
|
|
624
|
+
self._tri_shape = TrianglePolynomialShapeFunctions(degree=degree)
|
|
625
|
+
self.ORDER = self._tri_shape.ORDER
|
|
626
|
+
self.NODES_PER_ELEMENT = self._tri_shape.NODES_PER_ELEMENT
|
|
627
|
+
|
|
628
|
+
self.element_node_triangulation = self._tri_shape.element_node_triangulation
|
|
629
|
+
self.element_vtk_cells = self._tri_shape.element_vtk_cells
|
|
630
|
+
|
|
631
|
+
@property
|
|
632
|
+
def name(self) -> str:
|
|
633
|
+
return f"Square_P{self.ORDER}d"
|
|
634
|
+
|
|
635
|
+
def make_node_coords_in_element(self):
|
|
636
|
+
node_coords_in_tet = self._tri_shape.make_node_coords_in_element()
|
|
637
|
+
|
|
638
|
+
TRI_TO_SQUARE = wp.constant(wp.mat22(self._tri_to_square))
|
|
639
|
+
|
|
640
|
+
@cache.dynamic_func(suffix=self.name)
|
|
641
|
+
def node_coords_in_element(
|
|
642
|
+
node_index_in_elt: int,
|
|
643
|
+
):
|
|
644
|
+
tri_coords = node_coords_in_tet(node_index_in_elt)
|
|
645
|
+
coords = (
|
|
646
|
+
TRI_TO_SQUARE * wp.vec2(tri_coords[1], tri_coords[2])
|
|
647
|
+
) + SquareNonConformingPolynomialShapeFunctions._TRI_OFFSET
|
|
648
|
+
return Coords(coords[0], coords[1], 0.0)
|
|
649
|
+
|
|
650
|
+
return node_coords_in_element
|
|
651
|
+
|
|
652
|
+
def make_node_quadrature_weight(self):
|
|
653
|
+
NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
|
|
654
|
+
|
|
655
|
+
if self.ORDER == 2:
|
|
656
|
+
# Intrinsic quadrature (order 2)
|
|
657
|
+
@cache.dynamic_func(suffix=self.name)
|
|
658
|
+
def node_quadrature_weight_quadratic(
|
|
659
|
+
node_index_in_elt: int,
|
|
660
|
+
):
|
|
661
|
+
node_type, type_index = self._tri_shape.node_type_and_type_index(node_index_in_elt)
|
|
662
|
+
if node_type == TrianglePolynomialShapeFunctions.VERTEX:
|
|
663
|
+
return 0.18518521
|
|
664
|
+
return 0.14814811
|
|
665
|
+
|
|
666
|
+
return node_quadrature_weight_quadratic
|
|
667
|
+
|
|
668
|
+
@cache.dynamic_func(suffix=self.name)
|
|
669
|
+
def node_uniform_quadrature_weight(
|
|
670
|
+
node_index_in_elt: int,
|
|
671
|
+
):
|
|
672
|
+
return 1.0 / float(NODES_PER_ELEMENT)
|
|
673
|
+
|
|
674
|
+
return node_uniform_quadrature_weight
|
|
675
|
+
|
|
676
|
+
def make_trace_node_quadrature_weight(self):
|
|
677
|
+
# Non-conforming, zero measure on sides
|
|
678
|
+
|
|
679
|
+
@wp.func
|
|
680
|
+
def zero(node_index_in_elt: int):
|
|
681
|
+
return 0.0
|
|
682
|
+
|
|
683
|
+
return zero
|
|
684
|
+
|
|
685
|
+
def make_element_inner_weight(self):
|
|
686
|
+
tri_inner_weight = self._tri_shape.make_element_inner_weight()
|
|
687
|
+
|
|
688
|
+
SQUARE_TO_TRI = wp.constant(wp.mat22(np.linalg.inv(self._tri_to_square)))
|
|
689
|
+
|
|
690
|
+
@cache.dynamic_func(suffix=self.name)
|
|
691
|
+
def element_inner_weight(
|
|
692
|
+
coords: Coords,
|
|
693
|
+
node_index_in_elt: int,
|
|
694
|
+
):
|
|
695
|
+
tri_param = SQUARE_TO_TRI * (
|
|
696
|
+
wp.vec2(coords[0], coords[1]) - SquareNonConformingPolynomialShapeFunctions._TRI_OFFSET
|
|
697
|
+
)
|
|
698
|
+
tri_coords = Coords(1.0 - tri_param[0] - tri_param[1], tri_param[0], tri_param[1])
|
|
699
|
+
|
|
700
|
+
return tri_inner_weight(tri_coords, node_index_in_elt)
|
|
701
|
+
|
|
702
|
+
return element_inner_weight
|
|
703
|
+
|
|
704
|
+
def make_element_inner_weight_gradient(self):
|
|
705
|
+
tri_inner_weight_gradient = self._tri_shape.make_element_inner_weight_gradient()
|
|
706
|
+
|
|
707
|
+
SQUARE_TO_TRI = wp.constant(wp.mat22(np.linalg.inv(self._tri_to_square)))
|
|
708
|
+
|
|
709
|
+
@cache.dynamic_func(suffix=self.name)
|
|
710
|
+
def element_inner_weight_gradient(
|
|
711
|
+
coords: Coords,
|
|
712
|
+
node_index_in_elt: int,
|
|
713
|
+
):
|
|
714
|
+
tri_param = SQUARE_TO_TRI * (
|
|
715
|
+
wp.vec2(coords[0], coords[1]) - SquareNonConformingPolynomialShapeFunctions._TRI_OFFSET
|
|
716
|
+
)
|
|
717
|
+
tri_coords = Coords(1.0 - tri_param[0] - tri_param[1], tri_param[0], tri_param[1])
|
|
718
|
+
|
|
719
|
+
grad = tri_inner_weight_gradient(tri_coords, node_index_in_elt)
|
|
720
|
+
return wp.transpose(SQUARE_TO_TRI) * grad
|
|
721
|
+
|
|
722
|
+
return element_inner_weight_gradient
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
class SquareNedelecFirstKindShapeFunctions(SquareShapeFunction):
|
|
726
|
+
value = ShapeFunction.Value.CovariantVector
|
|
727
|
+
|
|
728
|
+
def __init__(self, degree: int):
|
|
729
|
+
if degree != 1:
|
|
730
|
+
raise NotImplementedError("Only linear Nédélec implemented right now")
|
|
731
|
+
|
|
732
|
+
self.ORDER = wp.constant(degree)
|
|
733
|
+
self.NODES_PER_ELEMENT = wp.constant(4)
|
|
734
|
+
self.NODES_PER_SIDE = wp.constant(1)
|
|
735
|
+
|
|
736
|
+
self.VERTEX_NODE_COUNT = wp.constant(0)
|
|
737
|
+
self.EDGE_NODE_COUNT = wp.constant(1)
|
|
738
|
+
self.INTERIOR_NODE_COUNT = wp.constant(0)
|
|
739
|
+
|
|
740
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
741
|
+
|
|
742
|
+
@property
|
|
743
|
+
def name(self) -> str:
|
|
744
|
+
return f"SquareN1_{self.ORDER}"
|
|
745
|
+
|
|
746
|
+
def _get_node_type_and_type_index(self):
|
|
747
|
+
@cache.dynamic_func(suffix=self.name)
|
|
748
|
+
def node_type_and_index(
|
|
749
|
+
node_index_in_elt: int,
|
|
750
|
+
):
|
|
751
|
+
axis = node_index_in_elt // 2
|
|
752
|
+
offset = node_index_in_elt - 2 * axis
|
|
753
|
+
return SquareShapeFunction.EDGE_X + axis, offset, 0
|
|
754
|
+
|
|
755
|
+
return node_type_and_index
|
|
756
|
+
|
|
757
|
+
def make_node_coords_in_element(self):
|
|
758
|
+
@cache.dynamic_func(suffix=self.name)
|
|
759
|
+
def node_coords_in_element(
|
|
760
|
+
node_index_in_elt: int,
|
|
761
|
+
):
|
|
762
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
763
|
+
axis = node_type - SquareShapeFunction.EDGE_X
|
|
764
|
+
|
|
765
|
+
coords = Coords()
|
|
766
|
+
coords[axis] = 0.5
|
|
767
|
+
coords[1 - axis] = float(type_instance)
|
|
768
|
+
|
|
769
|
+
return node_coords_in_element
|
|
770
|
+
|
|
771
|
+
def make_node_quadrature_weight(self):
|
|
772
|
+
NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
|
|
773
|
+
|
|
774
|
+
@cache.dynamic_func(suffix=self.name)
|
|
775
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
776
|
+
return 1.0 / float(NODES_PER_ELEMENT)
|
|
777
|
+
|
|
778
|
+
return node_quadrature_weight
|
|
779
|
+
|
|
780
|
+
def make_trace_node_quadrature_weight(self):
|
|
781
|
+
NODES_PER_SIDE = self.NODES_PER_SIDE
|
|
782
|
+
|
|
783
|
+
@cache.dynamic_func(suffix=self.name)
|
|
784
|
+
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
785
|
+
return 1.0 / float(NODES_PER_SIDE)
|
|
786
|
+
|
|
787
|
+
return trace_node_quadrature_weight
|
|
788
|
+
|
|
789
|
+
def make_element_inner_weight(self):
|
|
790
|
+
@cache.dynamic_func(suffix=self.name)
|
|
791
|
+
def element_inner_weight(
|
|
792
|
+
coords: Coords,
|
|
793
|
+
node_index_in_elt: int,
|
|
794
|
+
):
|
|
795
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
796
|
+
|
|
797
|
+
axis = node_type - SquareShapeFunction.EDGE_X
|
|
798
|
+
a = float(2 * type_instance - 1)
|
|
799
|
+
b = float(1 - type_instance)
|
|
800
|
+
|
|
801
|
+
w = wp.vec2(0.0)
|
|
802
|
+
w[axis] = b + a * coords[1 - axis]
|
|
803
|
+
|
|
804
|
+
return w
|
|
805
|
+
|
|
806
|
+
return element_inner_weight
|
|
807
|
+
|
|
808
|
+
def make_element_inner_weight_gradient(self):
|
|
809
|
+
@cache.dynamic_func(suffix=self.name)
|
|
810
|
+
def element_inner_weight_gradient(
|
|
811
|
+
coords: Coords,
|
|
812
|
+
node_index_in_elt: int,
|
|
813
|
+
):
|
|
814
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
815
|
+
|
|
816
|
+
axis = node_type - SquareShapeFunction.EDGE_X
|
|
817
|
+
a = float(2 * type_instance - 1)
|
|
818
|
+
|
|
819
|
+
grad = wp.mat22(0.0)
|
|
820
|
+
grad[axis, 1 - axis] = a
|
|
821
|
+
|
|
822
|
+
return grad
|
|
823
|
+
|
|
824
|
+
return element_inner_weight_gradient
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
class SquareRaviartThomasShapeFunctions(SquareShapeFunction):
|
|
828
|
+
value = ShapeFunction.Value.ContravariantVector
|
|
829
|
+
|
|
830
|
+
def __init__(self, degree: int):
|
|
831
|
+
if degree != 1:
|
|
832
|
+
raise NotImplementedError("Only linear Nédélec implemented right now")
|
|
833
|
+
|
|
834
|
+
self.ORDER = wp.constant(degree)
|
|
835
|
+
self.NODES_PER_ELEMENT = wp.constant(4)
|
|
836
|
+
self.NODES_PER_SIDE = wp.constant(1)
|
|
837
|
+
|
|
838
|
+
self.VERTEX_NODE_COUNT = wp.constant(0)
|
|
839
|
+
self.EDGE_NODE_COUNT = wp.constant(1)
|
|
840
|
+
self.INTERIOR_NODE_COUNT = wp.constant(0)
|
|
841
|
+
|
|
842
|
+
self.node_type_and_type_index = self._get_node_type_and_type_index()
|
|
843
|
+
|
|
844
|
+
@property
|
|
845
|
+
def name(self) -> str:
|
|
846
|
+
return f"SquareRT_{self.ORDER}"
|
|
847
|
+
|
|
848
|
+
def _get_node_type_and_type_index(self):
|
|
849
|
+
@cache.dynamic_func(suffix=self.name)
|
|
850
|
+
def node_type_and_index(
|
|
851
|
+
node_index_in_elt: int,
|
|
852
|
+
):
|
|
853
|
+
axis = node_index_in_elt // 2
|
|
854
|
+
offset = node_index_in_elt - 2 * axis
|
|
855
|
+
return SquareShapeFunction.EDGE_X + axis, offset, 0
|
|
856
|
+
|
|
857
|
+
return node_type_and_index
|
|
858
|
+
|
|
859
|
+
def make_node_coords_in_element(self):
|
|
860
|
+
@cache.dynamic_func(suffix=self.name)
|
|
861
|
+
def node_coords_in_element(
|
|
862
|
+
node_index_in_elt: int,
|
|
863
|
+
):
|
|
864
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
865
|
+
axis = node_type - SquareShapeFunction.EDGE_X
|
|
866
|
+
|
|
867
|
+
coords = Coords()
|
|
868
|
+
coords[axis] = 0.5
|
|
869
|
+
coords[1 - axis] = float(type_instance)
|
|
870
|
+
|
|
871
|
+
return node_coords_in_element
|
|
872
|
+
|
|
873
|
+
def make_node_quadrature_weight(self):
|
|
874
|
+
NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
|
|
875
|
+
|
|
876
|
+
@cache.dynamic_func(suffix=self.name)
|
|
877
|
+
def node_quadrature_weight(node_index_in_element: int):
|
|
878
|
+
return 1.0 / float(NODES_PER_ELEMENT)
|
|
879
|
+
|
|
880
|
+
return node_quadrature_weight
|
|
881
|
+
|
|
882
|
+
def make_trace_node_quadrature_weight(self):
|
|
883
|
+
NODES_PER_SIDE = self.NODES_PER_SIDE
|
|
884
|
+
|
|
885
|
+
@cache.dynamic_func(suffix=self.name)
|
|
886
|
+
def trace_node_quadrature_weight(node_index_in_element: int):
|
|
887
|
+
return 1.0 / float(NODES_PER_SIDE)
|
|
888
|
+
|
|
889
|
+
return trace_node_quadrature_weight
|
|
890
|
+
|
|
891
|
+
def make_element_inner_weight(self):
|
|
892
|
+
@cache.dynamic_func(suffix=self.name)
|
|
893
|
+
def element_inner_weight(
|
|
894
|
+
coords: Coords,
|
|
895
|
+
node_index_in_elt: int,
|
|
896
|
+
):
|
|
897
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
898
|
+
|
|
899
|
+
axis = node_type - SquareShapeFunction.EDGE_X
|
|
900
|
+
a = float(2 * type_instance - 1)
|
|
901
|
+
b = float(1 - type_instance)
|
|
902
|
+
|
|
903
|
+
w = wp.vec2(0.0)
|
|
904
|
+
w[1 - axis] = b + a * coords[1 - axis]
|
|
905
|
+
|
|
906
|
+
return w
|
|
907
|
+
|
|
908
|
+
return element_inner_weight
|
|
909
|
+
|
|
910
|
+
def make_element_inner_weight_gradient(self):
|
|
911
|
+
@cache.dynamic_func(suffix=self.name)
|
|
912
|
+
def element_inner_weight_gradient(
|
|
913
|
+
coords: Coords,
|
|
914
|
+
node_index_in_elt: int,
|
|
915
|
+
):
|
|
916
|
+
node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
|
|
917
|
+
|
|
918
|
+
axis = node_type - SquareShapeFunction.EDGE_X
|
|
919
|
+
a = float(2 * type_instance - 1)
|
|
920
|
+
|
|
921
|
+
grad = wp.mat22(0.0)
|
|
922
|
+
grad[1 - axis, 1 - axis] = a
|
|
923
|
+
|
|
924
|
+
return grad
|
|
925
|
+
|
|
926
|
+
return element_inner_weight_gradient
|