warp-lang 1.7.0__py3-none-manylinux_2_34_aarch64.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
warp/fem/linalg.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024 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
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import warp as wp
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@wp.func
|
|
22
|
+
def generalized_outer(x: Any, y: Any):
|
|
23
|
+
"""Generalized outer product allowing for the first argument to be a scalar"""
|
|
24
|
+
return wp.outer(x, y)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@wp.func
|
|
28
|
+
def generalized_outer(x: wp.float32, y: wp.vec2):
|
|
29
|
+
return x * y
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@wp.func
|
|
33
|
+
def generalized_outer(x: wp.float32, y: wp.vec3):
|
|
34
|
+
return x * y
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@wp.func
|
|
38
|
+
def generalized_inner(x: Any, y: Any):
|
|
39
|
+
"""Generalized inner product allowing for the first argument to be a tensor"""
|
|
40
|
+
return wp.dot(x, y)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@wp.func
|
|
44
|
+
def generalized_inner(x: float, y: float):
|
|
45
|
+
return x * y
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@wp.func
|
|
49
|
+
def generalized_inner(x: wp.mat22, y: wp.vec2):
|
|
50
|
+
return x[0] * y[0] + x[1] * y[1]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@wp.func
|
|
54
|
+
def generalized_inner(x: wp.mat33, y: wp.vec3):
|
|
55
|
+
return x[0] * y[0] + x[1] * y[1] + x[2] * y[2]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@wp.func
|
|
59
|
+
def basis_element(template_type: Any, coord: int):
|
|
60
|
+
"""Returns a instance of `template_type` with a single coordinate set to 1 in the canonical basis"""
|
|
61
|
+
|
|
62
|
+
t = type(template_type)(0.0)
|
|
63
|
+
t[coord] = 1.0
|
|
64
|
+
return t
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@wp.func
|
|
68
|
+
def basis_element(template_type: wp.float32, coord: int):
|
|
69
|
+
return 1.0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@wp.func
|
|
73
|
+
def basis_element(template_type: wp.mat22, coord: int):
|
|
74
|
+
t = wp.mat22(0.0)
|
|
75
|
+
row = coord // 2
|
|
76
|
+
col = coord - 2 * row
|
|
77
|
+
t[row, col] = 1.0
|
|
78
|
+
return t
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@wp.func
|
|
82
|
+
def basis_element(template_type: wp.mat33, coord: int):
|
|
83
|
+
t = wp.mat33(0.0)
|
|
84
|
+
row = coord // 3
|
|
85
|
+
col = coord - 3 * row
|
|
86
|
+
t[row, col] = 1.0
|
|
87
|
+
return t
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@wp.func
|
|
91
|
+
def basis_coefficient(val: wp.float32, i: int):
|
|
92
|
+
return val
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@wp.func
|
|
96
|
+
def basis_coefficient(val: Any, i: int):
|
|
97
|
+
return val[i]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@wp.func
|
|
101
|
+
def basis_coefficient(val: wp.vec2, i: int, j: int):
|
|
102
|
+
# treat as row vector
|
|
103
|
+
return val[j]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@wp.func
|
|
107
|
+
def basis_coefficient(val: wp.vec3, i: int, j: int):
|
|
108
|
+
# treat as row vector
|
|
109
|
+
return val[j]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@wp.func
|
|
113
|
+
def basis_coefficient(val: Any, i: int, j: int):
|
|
114
|
+
return val[i, j]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@wp.func
|
|
118
|
+
def basis_coefficient(template_type: wp.mat33, coord: int):
|
|
119
|
+
t = wp.mat33(0.0)
|
|
120
|
+
row = coord // 3
|
|
121
|
+
col = coord - 3 * row
|
|
122
|
+
t[row, col] = 1.0
|
|
123
|
+
return t
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@wp.func
|
|
127
|
+
def symmetric_part(x: Any):
|
|
128
|
+
"""Symmetric part of a square tensor"""
|
|
129
|
+
return 0.5 * (x + wp.transpose(x))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@wp.func
|
|
133
|
+
def spherical_part(x: wp.mat22):
|
|
134
|
+
"""Spherical part of a square tensor"""
|
|
135
|
+
return 0.5 * wp.trace(x) * wp.identity(n=2, dtype=float)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@wp.func
|
|
139
|
+
def spherical_part(x: wp.mat33):
|
|
140
|
+
"""Spherical part of a square tensor"""
|
|
141
|
+
return (wp.trace(x) / 3.0) * wp.identity(n=3, dtype=float)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@wp.func
|
|
145
|
+
def skew_part(x: wp.mat22):
|
|
146
|
+
"""Skew part of a 2x2 tensor as corresponding rotation angle"""
|
|
147
|
+
return 0.5 * (x[1, 0] - x[0, 1])
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@wp.func
|
|
151
|
+
def skew_part(x: wp.mat33):
|
|
152
|
+
"""Skew part of a 3x3 tensor as the corresponding rotation vector"""
|
|
153
|
+
a = 0.5 * (x[2, 1] - x[1, 2])
|
|
154
|
+
b = 0.5 * (x[0, 2] - x[2, 0])
|
|
155
|
+
c = 0.5 * (x[1, 0] - x[0, 1])
|
|
156
|
+
return wp.vec3(a, b, c)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@wp.func
|
|
160
|
+
def householder_qr_decomposition(A: Any):
|
|
161
|
+
"""
|
|
162
|
+
QR decomposition of a square matrix using Householder reflections
|
|
163
|
+
|
|
164
|
+
Returns Q and R such that Q R = A, Q orthonormal (such that QQ^T = Id), R upper triangular
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
x = type(A[0])()
|
|
168
|
+
Q = wp.identity(n=type(x).length, dtype=A.dtype)
|
|
169
|
+
|
|
170
|
+
zero = x.dtype(0.0)
|
|
171
|
+
two = x.dtype(2.0)
|
|
172
|
+
|
|
173
|
+
for i in range(type(x).length):
|
|
174
|
+
for k in range(type(x).length):
|
|
175
|
+
x[k] = wp.where(k < i, zero, A[k, i])
|
|
176
|
+
|
|
177
|
+
alpha = wp.length(x) * wp.sign(x[i])
|
|
178
|
+
x[i] += alpha
|
|
179
|
+
two_over_x_sq = wp.where(alpha == zero, zero, two / wp.length_sq(x))
|
|
180
|
+
|
|
181
|
+
A -= wp.outer(two_over_x_sq * x, x * A)
|
|
182
|
+
Q -= wp.outer(Q * x, two_over_x_sq * x)
|
|
183
|
+
|
|
184
|
+
return Q, A
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@wp.func
|
|
188
|
+
def householder_make_hessenberg(A: Any):
|
|
189
|
+
"""Transforms a square matrix to Hessenberg form (single lower diagonal) using Householder reflections
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Q and H such that Q H Q^T = A, Q orthonormal, H under Hessenberg form
|
|
193
|
+
If A is symmetric, H will be tridiagonal
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
x = type(A[0])()
|
|
197
|
+
Q = wp.identity(n=type(x).length, dtype=A.dtype)
|
|
198
|
+
|
|
199
|
+
zero = x.dtype(0.0)
|
|
200
|
+
two = x.dtype(2.0)
|
|
201
|
+
|
|
202
|
+
for i in range(1, type(x).length):
|
|
203
|
+
for k in range(type(x).length):
|
|
204
|
+
x[k] = wp.where(k < i, zero, A[k, i - 1])
|
|
205
|
+
|
|
206
|
+
alpha = wp.length(x) * wp.sign(x[i])
|
|
207
|
+
x[i] += alpha
|
|
208
|
+
two_over_x_sq = wp.where(alpha == zero, zero, two / wp.length_sq(x))
|
|
209
|
+
|
|
210
|
+
# apply on both sides
|
|
211
|
+
A -= wp.outer(two_over_x_sq * x, x * A)
|
|
212
|
+
A -= wp.outer(A * x, two_over_x_sq * x)
|
|
213
|
+
Q -= wp.outer(Q * x, two_over_x_sq * x)
|
|
214
|
+
|
|
215
|
+
return Q, A
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@wp.func
|
|
219
|
+
def solve_triangular(R: Any, b: Any):
|
|
220
|
+
"""Solves for R x = b where R is an upper triangular matrix
|
|
221
|
+
|
|
222
|
+
Returns x
|
|
223
|
+
"""
|
|
224
|
+
zero = b.dtype(0)
|
|
225
|
+
x = type(b)(b.dtype(0))
|
|
226
|
+
for i in range(b.length, 0, -1):
|
|
227
|
+
j = i - 1
|
|
228
|
+
r = b[j] - wp.dot(R[j], x)
|
|
229
|
+
x[j] = wp.where(R[j, j] == zero, zero, r / R[j, j])
|
|
230
|
+
|
|
231
|
+
return x
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@wp.func
|
|
235
|
+
def inverse_qr(A: Any):
|
|
236
|
+
# Computes a square matrix inverse using QR factorization
|
|
237
|
+
|
|
238
|
+
Q, R = householder_qr_decomposition(A)
|
|
239
|
+
|
|
240
|
+
A_inv = type(A)()
|
|
241
|
+
for i in range(type(A[0]).length):
|
|
242
|
+
A_inv[i] = solve_triangular(R, Q[i]) # ith column of Q^T
|
|
243
|
+
|
|
244
|
+
return wp.transpose(A_inv)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@wp.func
|
|
248
|
+
def _wilkinson_shift(a: Any, b: Any, c: Any, tol: Any):
|
|
249
|
+
# Wilkinson shift: estimate eigenvalue of 2x2 symmetric matrix [a, c, c, b]
|
|
250
|
+
d = (a - b) * type(tol)(0.5)
|
|
251
|
+
return b + d - wp.sign(d) * wp.sqrt(d * d + c * c)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@wp.func
|
|
255
|
+
def _givens_rotation(a: Any, b: Any):
|
|
256
|
+
# Givens rotation [[c -s], [s c]] such that sa+cb =0
|
|
257
|
+
zero = type(a)(0.0)
|
|
258
|
+
one = type(a)(1.0)
|
|
259
|
+
|
|
260
|
+
b2 = b * b
|
|
261
|
+
if b2 == zero:
|
|
262
|
+
# id rotation
|
|
263
|
+
return one, zero
|
|
264
|
+
|
|
265
|
+
scale = one / wp.sqrt(a * a + b2)
|
|
266
|
+
return a * scale, -b * scale
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@wp.func
|
|
270
|
+
def tridiagonal_symmetric_eigenvalues_qr(D: Any, L: Any, Q: Any, tol: Any):
|
|
271
|
+
"""
|
|
272
|
+
Computes the eigenvalues and eigen vectors of a symmetric tridiagonal matrix using the
|
|
273
|
+
Symmetric tridiagonal QR algorithm with implicit Wilkinson shift
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
D: Main diagonal of the matrix
|
|
277
|
+
L: Lower diagonal of the matrix, indexed such that L[i] = A[i+1, i]
|
|
278
|
+
Q: Initialization for the eigenvectors, useful if a pre-transformation has been applied, otherwise may be identity
|
|
279
|
+
tol: Tolerance for the diagonalization residual (Linf norm of off-diagonal over diagonal terms)
|
|
280
|
+
|
|
281
|
+
Returns a tuple (D: vector of eigenvalues, P: matrix with one eigenvector per row) such that A = P^T D P
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
Ref: Arbenz P, Numerical Methods for Solving Large Scale Eigenvalue Problems, Chapter 4 (QR algorithm, Mar 13, 2018)
|
|
285
|
+
"""
|
|
286
|
+
|
|
287
|
+
two = D.dtype(2.0)
|
|
288
|
+
|
|
289
|
+
# so that we can use the type length in expressions
|
|
290
|
+
# this will prevent unrolling by warp, but should be ok for native code
|
|
291
|
+
m = int(0)
|
|
292
|
+
for _ in range(type(D).length):
|
|
293
|
+
m += 1
|
|
294
|
+
|
|
295
|
+
start = int(0)
|
|
296
|
+
y = D.dtype(0.0) # moving buldge
|
|
297
|
+
x = D.dtype(0.0) # coeff atop buldge
|
|
298
|
+
|
|
299
|
+
for _ in range(32 * m): # failsafe, usually converges faster than that
|
|
300
|
+
# Iterate over all independent (deflated) blocks
|
|
301
|
+
end = int(-1)
|
|
302
|
+
|
|
303
|
+
for k in range(m - 1):
|
|
304
|
+
if k >= end:
|
|
305
|
+
# Check if new block is starting
|
|
306
|
+
if k == end or wp.abs(L[k]) <= tol * (wp.abs(D[k]) + wp.abs(D[k + 1])):
|
|
307
|
+
continue
|
|
308
|
+
|
|
309
|
+
# Find end of block
|
|
310
|
+
start = k
|
|
311
|
+
end = start + 1
|
|
312
|
+
while end + 1 < m:
|
|
313
|
+
if wp.abs(L[end]) <= tol * (wp.abs(D[end + 1]) + wp.abs(D[end])):
|
|
314
|
+
break
|
|
315
|
+
end += 1
|
|
316
|
+
|
|
317
|
+
# Wilkinson shift (an eigenvalue of the last 2x2 block)
|
|
318
|
+
shift = _wilkinson_shift(D[end - 1], D[end], L[end - 1], tol)
|
|
319
|
+
|
|
320
|
+
# start with eliminating lower diag of first column of shifted matrix
|
|
321
|
+
# (i.e. first step of explicit QR factorization)
|
|
322
|
+
# Then all further steps eliminate the buldge (second diag) of the non-shifted matrix
|
|
323
|
+
x = D[start] - shift
|
|
324
|
+
y = L[start]
|
|
325
|
+
|
|
326
|
+
c, s = _givens_rotation(x, y)
|
|
327
|
+
|
|
328
|
+
# Apply Givens rotation on both sides of tridiagonal matrix
|
|
329
|
+
|
|
330
|
+
# middle block
|
|
331
|
+
d = D[k] - D[k + 1]
|
|
332
|
+
z = (two * c * L[k] + d * s) * s
|
|
333
|
+
D[k] -= z
|
|
334
|
+
D[k + 1] += z
|
|
335
|
+
L[k] = d * c * s + (c * c - s * s) * L[k]
|
|
336
|
+
|
|
337
|
+
if k > start:
|
|
338
|
+
L[k - 1] = c * x - s * y
|
|
339
|
+
|
|
340
|
+
x = L[k]
|
|
341
|
+
y = -s * L[k + 1] # new buldge
|
|
342
|
+
L[k + 1] *= c
|
|
343
|
+
|
|
344
|
+
# apply givens rotation on left of Q
|
|
345
|
+
# note: Q is transposed compared to usual impls, as Warp makes it easier to index rows
|
|
346
|
+
Qk0 = Q[k]
|
|
347
|
+
Qk1 = Q[k + 1]
|
|
348
|
+
Q[k] = c * Qk0 - s * Qk1
|
|
349
|
+
Q[k + 1] = c * Qk1 + s * Qk0
|
|
350
|
+
|
|
351
|
+
if end <= 0:
|
|
352
|
+
# We did nothing, so diagonalization must have been achieved
|
|
353
|
+
break
|
|
354
|
+
|
|
355
|
+
return D, Q
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@wp.func
|
|
359
|
+
def symmetric_eigenvalues_qr(A: Any, tol: Any):
|
|
360
|
+
"""
|
|
361
|
+
Computes the eigenvalues and eigen vectors of a square symmetric matrix A using the QR algorithm
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
A: square symmetric matrix
|
|
365
|
+
tol: Tolerance for the diagonalization residual (Linf norm of off-diagonal over diagonal terms)
|
|
366
|
+
|
|
367
|
+
Returns a tuple (D: vector of eigenvalues, P: matrix with one eigenvector per row) such that A = P^T D P
|
|
368
|
+
"""
|
|
369
|
+
|
|
370
|
+
# Put A under Hessenberg form (tridiagonal)
|
|
371
|
+
Q, H = householder_make_hessenberg(A)
|
|
372
|
+
|
|
373
|
+
# tridiagonal storage for H
|
|
374
|
+
D = wp.get_diag(H)
|
|
375
|
+
L = type(D)(A.dtype(0.0))
|
|
376
|
+
for i in range(1, type(D).length):
|
|
377
|
+
L[i - 1] = H[i, i - 1]
|
|
378
|
+
|
|
379
|
+
Qt = wp.transpose(Q)
|
|
380
|
+
ev, P = tridiagonal_symmetric_eigenvalues_qr(D, L, Qt, tol)
|
|
381
|
+
return ev, P
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def array_axpy(x: wp.array, y: wp.array, alpha: float = 1.0, beta: float = 1.0):
|
|
385
|
+
"""Performs y = alpha*x + beta*y"""
|
|
386
|
+
|
|
387
|
+
dtype = wp.types.type_scalar_type(y.dtype)
|
|
388
|
+
|
|
389
|
+
alpha = dtype(alpha)
|
|
390
|
+
beta = dtype(beta)
|
|
391
|
+
|
|
392
|
+
if x.shape != y.shape or x.device != y.device:
|
|
393
|
+
raise ValueError("x and y arrays must have the same shape and device")
|
|
394
|
+
|
|
395
|
+
# array_axpy requires a custom adjoint; unfortunately we cannot use `wp.func_grad`
|
|
396
|
+
# as generic functions are not supported yet. Instead we use a non-differentiable kernel
|
|
397
|
+
# and record a custom adjoint function on the tape.
|
|
398
|
+
|
|
399
|
+
# temporarily disable tape to avoid printing warning that kernel is not differentiable
|
|
400
|
+
(tape, wp.context.runtime.tape) = (wp.context.runtime.tape, None)
|
|
401
|
+
wp.launch(kernel=_array_axpy_kernel, dim=x.shape, device=x.device, inputs=[x, y, alpha, beta])
|
|
402
|
+
wp.context.runtime.tape = tape
|
|
403
|
+
|
|
404
|
+
if tape is not None and (x.requires_grad or y.requires_grad):
|
|
405
|
+
|
|
406
|
+
def backward_axpy():
|
|
407
|
+
# adj_x += adj_y * alpha
|
|
408
|
+
# adj_y = adj_y * beta
|
|
409
|
+
array_axpy(x=y.grad, y=x.grad, alpha=alpha, beta=1.0)
|
|
410
|
+
if beta != 1.0:
|
|
411
|
+
array_axpy(x=y.grad, y=y.grad, alpha=0.0, beta=beta)
|
|
412
|
+
|
|
413
|
+
tape.record_func(backward_axpy, arrays=[x, y])
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
@wp.kernel(enable_backward=False)
|
|
417
|
+
def _array_axpy_kernel(x: wp.array(dtype=Any), y: wp.array(dtype=Any), alpha: Any, beta: Any):
|
|
418
|
+
i = wp.tid()
|
|
419
|
+
y[i] = beta * y[i] + alpha * y.dtype(x[i])
|
warp/fem/operator.py
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
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
|
+
from typing import Any, Callable, Dict, Optional, Set
|
|
17
|
+
|
|
18
|
+
import warp as wp
|
|
19
|
+
from warp.fem.linalg import skew_part, symmetric_part
|
|
20
|
+
from warp.fem.types import Coords, Domain, ElementIndex, Field, NodeIndex, Sample, make_free_sample
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Integrand:
|
|
24
|
+
"""An integrand is a device function containing arbitrary expressions over Field and Domain variables.
|
|
25
|
+
It will get transformed to a proper warp.Function by resolving concrete Field types at call time.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, func: Callable, kernel_options: Optional[Dict[str, Any]] = None):
|
|
29
|
+
self.func = func
|
|
30
|
+
self.name = wp.codegen.make_full_qualified_name(self.func)
|
|
31
|
+
self.module = wp.get_module(self.func.__module__)
|
|
32
|
+
self.argspec = wp.codegen.get_full_arg_spec(self.func)
|
|
33
|
+
self.kernel_options = {} if kernel_options is None else kernel_options
|
|
34
|
+
|
|
35
|
+
# Operators for each field argument. This will be populated at first integrate call
|
|
36
|
+
self.operators: Dict[str, Set[Operator]] = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Operator:
|
|
40
|
+
"""
|
|
41
|
+
Operators provide syntactic sugar over Field and Domain evaluation functions and arguments
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, func: Callable, resolver: Callable, field_result: Callable = None):
|
|
45
|
+
self.func = func
|
|
46
|
+
self.name = func.__name__
|
|
47
|
+
self.resolver = resolver
|
|
48
|
+
self.field_result = field_result
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def integrand(func: Callable = None, kernel_options: Optional[Dict[str, Any]] = None):
|
|
52
|
+
"""Decorator for functions to be integrated (or interpolated) using warp.fem
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
func: Decorated function
|
|
56
|
+
kernel_options: Supplemental code-generation options to be passed to the generated kernel.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
if func is not None:
|
|
60
|
+
itg = Integrand(func)
|
|
61
|
+
itg.__doc__ = func.__doc__
|
|
62
|
+
return itg
|
|
63
|
+
|
|
64
|
+
def wrap_integrand(func: Callable):
|
|
65
|
+
itg = Integrand(func, kernel_options)
|
|
66
|
+
itg.__doc__ = func.__doc__
|
|
67
|
+
return itg
|
|
68
|
+
|
|
69
|
+
return wrap_integrand
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def operator(**kwargs):
|
|
73
|
+
"""Decorator for functions operating on Field-like or Domain-like data inside warp.fem integrands"""
|
|
74
|
+
|
|
75
|
+
def wrap_operator(func: Callable):
|
|
76
|
+
op = Operator(func, **kwargs)
|
|
77
|
+
op.__doc__ = func.__doc__
|
|
78
|
+
return op
|
|
79
|
+
|
|
80
|
+
return wrap_operator
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Domain operators
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@operator(resolver=lambda dmn: dmn.element_position)
|
|
87
|
+
def position(domain: Domain, s: Sample):
|
|
88
|
+
"""Evaluates the world position of the sample point `s`"""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@operator(resolver=lambda dmn: dmn.element_normal)
|
|
93
|
+
def normal(domain: Domain, s: Sample):
|
|
94
|
+
"""Evaluates the element normal at the sample point `s`. Non zero if the element is a side or the geometry is embedded in a higher-dimensional space (e.g. :class:`Trimesh3D`)"""
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@operator(resolver=lambda dmn: dmn.element_deformation_gradient)
|
|
99
|
+
def deformation_gradient(domain: Domain, s: Sample):
|
|
100
|
+
"""Evaluates the gradient of the domain position with respect to the element reference space at the sample point `s`"""
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@operator(resolver=lambda dmn: dmn.element_lookup)
|
|
105
|
+
def lookup(domain: Domain, x: Any) -> Sample:
|
|
106
|
+
"""Looks-up the sample point corresponding to a world position `x`, projecting to the closest point on the domain.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
x: world position of the point to look-up in the geometry
|
|
110
|
+
guess: (optional) :class:`Sample` initial guess, may help perform the query
|
|
111
|
+
|
|
112
|
+
Note:
|
|
113
|
+
Currently this operator is unsupported for :class:`Hexmesh`, :class:`Quadmesh2D`, :class:`Quadmesh3D` and deformed geometries.
|
|
114
|
+
"""
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@operator(resolver=lambda dmn: dmn.element_measure)
|
|
119
|
+
def measure(domain: Domain, s: Sample) -> float:
|
|
120
|
+
"""Returns the measure (volume, area, or length) determinant of an element at a sample point `s`"""
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@operator(resolver=lambda dmn: dmn.element_measure_ratio)
|
|
125
|
+
def measure_ratio(domain: Domain, s: Sample) -> float:
|
|
126
|
+
"""Returns the maximum ratio between the measure of this element and that of higher-dimensional neighbors."""
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# Operators for evaluating cell-level quantities on domains defined on sides
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@operator(
|
|
134
|
+
resolver=lambda dmn: dmn.domain_cell_arg, field_result=lambda dmn: (dmn.cell_domain(), Domain, dmn.geometry.CellArg)
|
|
135
|
+
)
|
|
136
|
+
def cells(domain: Domain) -> Domain:
|
|
137
|
+
"""Converts a domain defined on geometry sides to a domain defined of cells."""
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@operator(resolver=lambda dmn: dmn.element_inner_cell_index)
|
|
142
|
+
def _inner_cell_index(domain: Domain, side_index: ElementIndex, side_coords: Coords) -> Sample:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@operator(resolver=lambda dmn: dmn.element_outer_cell_index)
|
|
147
|
+
def _outer_cell_index(domain: Domain, side_index: ElementIndex, side_coords: Coords) -> Sample:
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@operator(resolver=lambda dmn: dmn.element_inner_cell_coords)
|
|
152
|
+
def _inner_cell_coords(domain: Domain, side_index: ElementIndex, side_coords: Coords) -> Sample:
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@operator(resolver=lambda dmn: dmn.element_outer_cell_coords)
|
|
157
|
+
def _outer_cell_coords(domain: Domain, side_index: ElementIndex, side_coords: Coords) -> Sample:
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@operator(resolver=lambda dmn: dmn.cell_to_element_coords)
|
|
162
|
+
def _cell_to_element_coords(
|
|
163
|
+
domain: Domain, side_index: ElementIndex, cell_index: ElementIndex, cell_coords: Coords
|
|
164
|
+
) -> Sample:
|
|
165
|
+
pass
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@integrand
|
|
169
|
+
def to_inner_cell(domain: Domain, s: Sample):
|
|
170
|
+
"""Converts a :class:`Sample` defined on a side to a sample defined on the side's inner cell"""
|
|
171
|
+
return make_free_sample(
|
|
172
|
+
_inner_cell_index(domain, s.element_index), _inner_cell_coords(domain, s.element_index, s.element_coords)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@integrand
|
|
177
|
+
def to_outer_cell(domain: Domain, s: Sample):
|
|
178
|
+
"""Converts a :class:`Sample` defined on a side to a sample defined on the side's outer cell"""
|
|
179
|
+
return make_free_sample(
|
|
180
|
+
_outer_cell_index(domain, s.element_index), _outer_cell_coords(domain, s.element_index, s.element_coords)
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@integrand
|
|
185
|
+
def to_cell_side(domain: Domain, cell_s: Sample, side_index: ElementIndex):
|
|
186
|
+
"""Converts a :class:`Sample` defined on a cell to a sample defined on one of its side.
|
|
187
|
+
If the result does not lie on the side `side_index`, the resulting coordinates will be set to ``OUTSIDE``."""
|
|
188
|
+
return make_free_sample(
|
|
189
|
+
side_index, _cell_to_element_coords(domain, side_index, cell_s.element_index, cell_s.element_coords)
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# Field operators
|
|
194
|
+
# On a side, inner and outer are such that normal goes from inner to outer
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@operator(resolver=lambda f: f.eval_inner)
|
|
198
|
+
def inner(f: Field, s: Sample):
|
|
199
|
+
"""Evaluates the field at a sample point `s`. On oriented sides, uses the inner element"""
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@operator(resolver=lambda f: f.eval_grad_inner)
|
|
204
|
+
def grad(f: Field, s: Sample):
|
|
205
|
+
"""Evaluates the field gradient at a sample point `s`. On oriented sides, uses the inner element"""
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@operator(resolver=lambda f: f.eval_div_inner)
|
|
210
|
+
def div(f: Field, s: Sample):
|
|
211
|
+
"""Evaluates the field divergence at a sample point `s`. On oriented sides, uses the inner element"""
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@operator(resolver=lambda f: f.eval_outer)
|
|
216
|
+
def outer(f: Field, s: Sample):
|
|
217
|
+
"""Evaluates the field at a sample point `s`. On oriented sides, uses the outer element. On interior points and on domain boundaries, this is equivalent to :func:`inner`."""
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
@operator(resolver=lambda f: f.eval_grad_outer)
|
|
222
|
+
def grad_outer(f: Field, s: Sample):
|
|
223
|
+
"""Evaluates the field gradient at a sample point `s`. On oriented sides, uses the outer element. On interior points and on domain boundaries, this is equivalent to :func:`grad`."""
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@operator(resolver=lambda f: f.eval_grad_outer)
|
|
228
|
+
def div_outer(f: Field, s: Sample):
|
|
229
|
+
"""Evaluates the field divergence at a sample point `s`. On oriented sides, uses the outer element. On interior points and on domain boundaries, this is equivalent to :func:`div`."""
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@operator(resolver=lambda f: f.eval_degree)
|
|
234
|
+
def degree(f: Field):
|
|
235
|
+
"""Polynomial degree of a field"""
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@operator(resolver=lambda f: f.at_node)
|
|
240
|
+
def at_node(f: Field, s: Sample):
|
|
241
|
+
"""For a Test or Trial field `f`, returns a copy of the Sample `s` moved to the coordinates of the node being evaluated"""
|
|
242
|
+
pass
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@operator(resolver=lambda f: f.node_partition_index)
|
|
246
|
+
def node_partition_index(f: Field, node_index: NodeIndex):
|
|
247
|
+
"""For a NodalField `f`, returns the index of a given node in the fields's space partition,
|
|
248
|
+
or ``NULL_NODE_INDEX`` if it does not exists"""
|
|
249
|
+
pass
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# Common derived operators, for convenience
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@integrand
|
|
256
|
+
def D(f: Field, s: Sample):
|
|
257
|
+
"""Symmetric part of the (inner) gradient of the field at `s`"""
|
|
258
|
+
return symmetric_part(grad(f, s))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@integrand
|
|
262
|
+
def curl(f: Field, s: Sample):
|
|
263
|
+
"""Skew part of the (inner) gradient of the field at `s`, as a vector such that ``wp.cross(curl(u), v) = skew(grad(u)) v``"""
|
|
264
|
+
return skew_part(grad(f, s))
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@integrand
|
|
268
|
+
def jump(f: Field, s: Sample):
|
|
269
|
+
"""Jump between inner and outer element values on an interior side. Zero for interior points or domain boundaries"""
|
|
270
|
+
return inner(f, s) - outer(f, s)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@integrand
|
|
274
|
+
def average(f: Field, s: Sample):
|
|
275
|
+
"""Average between inner and outer element values"""
|
|
276
|
+
return 0.5 * (inner(f, s) + outer(f, s))
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@integrand
|
|
280
|
+
def grad_jump(f: Field, s: Sample):
|
|
281
|
+
"""Jump between inner and outer element gradients on an interior side. Zero for interior points or domain boundaries"""
|
|
282
|
+
return grad(f, s) - grad_outer(f, s)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@integrand
|
|
286
|
+
def grad_average(f: Field, s: Sample):
|
|
287
|
+
"""Average between inner and outer element gradients"""
|
|
288
|
+
return 0.5 * (grad(f, s) + grad_outer(f, s))
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# Set default call operators for argument types, so that field(s) = inner(field, s) and domain(s) = position(domain, s)
|
|
292
|
+
Field.call_operator = inner
|
|
293
|
+
Domain.call_operator = position
|