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
warp/fem/field/field.py
ADDED
|
@@ -0,0 +1,619 @@
|
|
|
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, Dict, Optional, Set
|
|
17
|
+
|
|
18
|
+
import warp as wp
|
|
19
|
+
from warp.fem import cache
|
|
20
|
+
from warp.fem.domain import GeometryDomain, Sides
|
|
21
|
+
from warp.fem.geometry import DeformedGeometry, Geometry
|
|
22
|
+
from warp.fem.operator import Operator, integrand
|
|
23
|
+
from warp.fem.space import FunctionSpace, SpacePartition
|
|
24
|
+
from warp.fem.types import NULL_ELEMENT_INDEX, ElementKind, Sample
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FieldLike:
|
|
28
|
+
"""Base class for integrable fields"""
|
|
29
|
+
|
|
30
|
+
EvalArg: wp.codegen.Struct
|
|
31
|
+
"""Structure containing field-level arguments passed to device functions for field evaluation"""
|
|
32
|
+
|
|
33
|
+
ElementEvalArg: wp.codegen.Struct
|
|
34
|
+
"""Structure combining geometry-level and field-level arguments passed to device functions for field evaluation"""
|
|
35
|
+
|
|
36
|
+
def eval_arg_value(self, device) -> "EvalArg": # noqa: F821
|
|
37
|
+
"""Value of the field-level arguments to be passed to device functions"""
|
|
38
|
+
raise NotImplementedError
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def degree(self) -> int:
|
|
42
|
+
"""Polynomial degree of the field, used to estimate necessary quadrature order"""
|
|
43
|
+
raise NotImplementedError
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def name(self) -> str:
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def __str__(self) -> str:
|
|
51
|
+
return self.name
|
|
52
|
+
|
|
53
|
+
def eval_arg_value(self, device):
|
|
54
|
+
"""Value of arguments to be passed to device functions"""
|
|
55
|
+
raise NotImplementedError
|
|
56
|
+
|
|
57
|
+
def gradient_valid(self) -> bool:
|
|
58
|
+
"""Whether the gradient operator is implemented for this field."""
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def divergence_valid(self) -> bool:
|
|
62
|
+
"""Whether the divergence operator is implemented for this field."""
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def eval_inner(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
67
|
+
"""Device function evaluating the inner field value at a sample point"""
|
|
68
|
+
raise NotImplementedError
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def eval_grad_inner(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
72
|
+
"""Device function evaluating the inner field gradient at a sample point"""
|
|
73
|
+
raise NotImplementedError
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def eval_div_inner(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
77
|
+
"""Device function evaluating the inner field divergence at a sample point"""
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def eval_outer(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
82
|
+
"""Device function evaluating the outer field value at a sample point"""
|
|
83
|
+
raise NotImplementedError
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def eval_grad_outer(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
87
|
+
"""Device function evaluating the outer field gradient at a sample point"""
|
|
88
|
+
raise NotImplementedError
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def eval_div_outer(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
92
|
+
"""Device function evaluating the outer field divergence at a sample point"""
|
|
93
|
+
raise NotImplementedError
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def eval_degree(args: "ElementEvalArg"): # noqa: F821
|
|
97
|
+
"""Polynomial degree of the field is applicable, or hint for determination of interpolation order"""
|
|
98
|
+
raise NotImplementedError
|
|
99
|
+
|
|
100
|
+
def notify_operator_usage(self, ops: Set[Operator]):
|
|
101
|
+
"""Makes the Domain aware that the operators `ops` will be applied"""
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class GeometryField(FieldLike):
|
|
106
|
+
"""Base class for fields defined over a geometry"""
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def geometry(self) -> Geometry:
|
|
110
|
+
"""Geometry over which the field is expressed"""
|
|
111
|
+
raise NotImplementedError
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def element_kind(self) -> ElementKind:
|
|
115
|
+
"""Kind of element over which the field is expressed"""
|
|
116
|
+
raise NotImplementedError
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def eval_reference_grad_inner(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
120
|
+
"""Device function evaluating the inner field gradient with respect to reference element coordinates at a sample point"""
|
|
121
|
+
raise NotImplementedError
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def eval_reference_grad_outer(args: "ElementEvalArg", s: Sample): # noqa: F821
|
|
125
|
+
"""Device function evaluating the outer field gradient with respect to reference element coordinates at a sample point"""
|
|
126
|
+
raise NotImplementedError
|
|
127
|
+
|
|
128
|
+
def trace(self) -> FieldLike:
|
|
129
|
+
"""Trace of this field over lower-dimensional elements"""
|
|
130
|
+
raise NotImplementedError
|
|
131
|
+
|
|
132
|
+
def make_deformed_geometry(self, relative=True) -> Geometry:
|
|
133
|
+
"""Returns a deformed version of the underlying geometry, with positions displaced according to this field's values.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
relative: If ``True``, the field is interpreted as a relative displacement over the original geometry.
|
|
137
|
+
If ``False``, the field values are interpreted as absolute positions.
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
return DeformedGeometry(self, relative=relative)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class SpaceField(GeometryField):
|
|
144
|
+
"""Base class for fields defined over a function space"""
|
|
145
|
+
|
|
146
|
+
def __init__(self, space: FunctionSpace, space_partition: SpacePartition):
|
|
147
|
+
self._space = space
|
|
148
|
+
self._space_partition = space_partition
|
|
149
|
+
|
|
150
|
+
self.gradient_valid = self.space.gradient_valid
|
|
151
|
+
self.divergence_valid = self.space.divergence_valid
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def geometry(self) -> Geometry:
|
|
155
|
+
return self._space.geometry
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def element_kind(self) -> ElementKind:
|
|
159
|
+
return self._space.element_kind
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def space(self) -> FunctionSpace:
|
|
163
|
+
return self._space
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def space_partition(self) -> SpacePartition:
|
|
167
|
+
return self._space_partition
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def degree(self) -> int:
|
|
171
|
+
return self.space.degree
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def dtype(self) -> type:
|
|
175
|
+
return self.space.dtype
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def dof_dtype(self) -> type:
|
|
179
|
+
return self.space.dof_dtype
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def gradient_dtype(self):
|
|
183
|
+
"""Return type of the gradient operator. Assumes self.gradient_valid()"""
|
|
184
|
+
if wp.types.type_is_vector(self.dtype):
|
|
185
|
+
return cache.cached_mat_type(
|
|
186
|
+
shape=(wp.types.type_length(self.dtype), self.geometry.dimension),
|
|
187
|
+
dtype=wp.types.type_scalar_type(self.dtype),
|
|
188
|
+
)
|
|
189
|
+
return cache.cached_vec_type(length=self.geometry.dimension, dtype=wp.types.type_scalar_type(self.dtype))
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def divergence_dtype(self):
|
|
193
|
+
"""Return type of the divergence operator. Assumes self.gradient_valid()"""
|
|
194
|
+
if wp.types.type_is_vector(self.dtype):
|
|
195
|
+
return wp.types.type_scalar_type(self.dtype)
|
|
196
|
+
return cache.cached_vec_type(length=self.dtype._shape_[1], dtype=wp.types.type_scalar_type(self.dtype))
|
|
197
|
+
|
|
198
|
+
def _make_eval_degree(self):
|
|
199
|
+
ORDER = self.space.ORDER
|
|
200
|
+
|
|
201
|
+
@cache.dynamic_func(suffix=self.name)
|
|
202
|
+
def degree(args: self.ElementEvalArg):
|
|
203
|
+
return ORDER
|
|
204
|
+
|
|
205
|
+
return degree
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class DiscreteField(SpaceField):
|
|
209
|
+
"""Explicitly-valued field defined over a partition of a discrete function space"""
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def dof_values(self) -> wp.array:
|
|
213
|
+
"""Array of degrees of freedom values"""
|
|
214
|
+
raise NotImplementedError
|
|
215
|
+
|
|
216
|
+
@dof_values.setter
|
|
217
|
+
def dof_values(self, values: wp.array):
|
|
218
|
+
"""Sets degrees of freedom values from an array"""
|
|
219
|
+
raise NotImplementedError
|
|
220
|
+
|
|
221
|
+
@staticmethod
|
|
222
|
+
def set_node_value(args: "FieldLike.EvalArg", node_index: int, value: Any):
|
|
223
|
+
"""Device function setting the value at given node"""
|
|
224
|
+
raise NotImplementedError
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def name(self) -> str:
|
|
228
|
+
return f"{self.__class__.__qualname__}_{self.space.name}_{self.space_partition.name}"
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class ImplicitField(GeometryField):
|
|
232
|
+
"""Field defined from an arbitrary function over a domain.
|
|
233
|
+
Does not support autodiff yet, so if gradient/divergence evaluation is required corresponding functions must be provided.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
domain: Domain over which the field is defined
|
|
237
|
+
func: Warp function evaluating the field at a given position. Must accept at least one argument, with the first argument being the evaluation position (``wp.vec2`` or ``wp.vec3``).
|
|
238
|
+
values: Optional dictionary of additional argument values to be passed to the evaluation function.
|
|
239
|
+
grad_func: Optional gradient evaluation function; must take same arguments as `func`
|
|
240
|
+
div_func: Optional divergence evaluation function; must take same arguments as `func`
|
|
241
|
+
degree: Optional hint for automatic determination of quadrature orders when integrating this field
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def __init__(
|
|
245
|
+
self,
|
|
246
|
+
domain: GeometryDomain,
|
|
247
|
+
func: wp.Function,
|
|
248
|
+
values: Optional[Dict[str, Any]] = None,
|
|
249
|
+
grad_func: Optional[wp.Function] = None,
|
|
250
|
+
div_func: Optional[wp.Function] = None,
|
|
251
|
+
degree=0,
|
|
252
|
+
):
|
|
253
|
+
self.domain = domain
|
|
254
|
+
self._degree = degree
|
|
255
|
+
|
|
256
|
+
if not isinstance(func, wp.Function):
|
|
257
|
+
raise ValueError("Implicit field function must be a warp Function (decorated with `wp.func`)")
|
|
258
|
+
|
|
259
|
+
self._func = func
|
|
260
|
+
self._grad_func = grad_func
|
|
261
|
+
self._div_func = div_func
|
|
262
|
+
|
|
263
|
+
argspec = integrand(func.func).argspec
|
|
264
|
+
arg_types = argspec.annotations
|
|
265
|
+
|
|
266
|
+
pos_arg_type = arg_types.pop(argspec.args[0]) if arg_types else None
|
|
267
|
+
if not pos_arg_type or not wp.types.types_equal(
|
|
268
|
+
pos_arg_type, wp.vec(length=domain.geometry.dimension, dtype=float), match_generic=True
|
|
269
|
+
):
|
|
270
|
+
raise ValueError(
|
|
271
|
+
f"Implicit field function '{func.func.__name__}' must accept a position as its first argument"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
self.EvalArg = cache.get_argument_struct(arg_types)
|
|
275
|
+
self.values = values
|
|
276
|
+
|
|
277
|
+
self.ElementEvalArg = self._make_element_eval_arg()
|
|
278
|
+
self.eval_degree = self._make_eval_degree()
|
|
279
|
+
|
|
280
|
+
self.eval_inner = self._make_eval_func(func)
|
|
281
|
+
self.eval_grad_inner = self._make_eval_func(grad_func)
|
|
282
|
+
self.eval_div_inner = self._make_eval_func(div_func)
|
|
283
|
+
self.eval_reference_grad_inner = self._make_eval_reference_grad()
|
|
284
|
+
|
|
285
|
+
self.eval_outer = self.eval_inner
|
|
286
|
+
self.eval_grad_outer = self.eval_grad_inner
|
|
287
|
+
self.eval_div_outer = self.eval_div_inner
|
|
288
|
+
self.eval_reference_grad_outer = self.eval_reference_grad_inner
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def values(self):
|
|
292
|
+
return self._func_arg
|
|
293
|
+
|
|
294
|
+
@values.setter
|
|
295
|
+
def values(self, v):
|
|
296
|
+
self._func_arg = cache.populate_argument_struct(self.EvalArg, v, self._func.func.__name__)
|
|
297
|
+
|
|
298
|
+
@property
|
|
299
|
+
def geometry(self) -> Geometry:
|
|
300
|
+
return self.domain.geometry
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
def element_kind(self) -> ElementKind:
|
|
304
|
+
return self.domain.element_kind
|
|
305
|
+
|
|
306
|
+
def eval_arg_value(self, device):
|
|
307
|
+
return self._func_arg
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def degree(self) -> int:
|
|
311
|
+
return self._degree
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def name(self) -> str:
|
|
315
|
+
return f"Implicit_{self.domain.name}_{self.degree}_{self.EvalArg.key}"
|
|
316
|
+
|
|
317
|
+
def _make_eval_func(self, func):
|
|
318
|
+
if func is None:
|
|
319
|
+
return None
|
|
320
|
+
|
|
321
|
+
@cache.dynamic_func(
|
|
322
|
+
suffix=f"{self.name}_{func.key}",
|
|
323
|
+
code_transformers=[cache.ExpandStarredArgumentStruct({"args.eval_arg": self.EvalArg})],
|
|
324
|
+
)
|
|
325
|
+
def eval_inner(args: self.ElementEvalArg, s: Sample):
|
|
326
|
+
pos = self.domain.element_position(args.elt_arg, s)
|
|
327
|
+
return func(pos, *args.eval_arg)
|
|
328
|
+
|
|
329
|
+
return eval_inner
|
|
330
|
+
|
|
331
|
+
def _make_eval_reference_grad(self):
|
|
332
|
+
if self.eval_grad_inner is None:
|
|
333
|
+
return None
|
|
334
|
+
|
|
335
|
+
@cache.dynamic_func(suffix=f"{self.eval_grad_inner.key}")
|
|
336
|
+
def eval_reference_grad_inner(args: self.ElementEvalArg, s: Sample):
|
|
337
|
+
return self.eval_grad_inner(args, s) * self.domain.element_deformation_gradient(args.elt_arg, s)
|
|
338
|
+
|
|
339
|
+
return eval_reference_grad_inner
|
|
340
|
+
|
|
341
|
+
def _make_element_eval_arg(self):
|
|
342
|
+
@cache.dynamic_struct(suffix=self.name)
|
|
343
|
+
class ElementEvalArg:
|
|
344
|
+
elt_arg: self.domain.ElementArg
|
|
345
|
+
eval_arg: self.EvalArg
|
|
346
|
+
|
|
347
|
+
return ElementEvalArg
|
|
348
|
+
|
|
349
|
+
def _make_eval_degree(self):
|
|
350
|
+
ORDER = wp.constant(self._degree)
|
|
351
|
+
|
|
352
|
+
@cache.dynamic_func(suffix=self.name)
|
|
353
|
+
def degree(args: self.ElementEvalArg):
|
|
354
|
+
return ORDER
|
|
355
|
+
|
|
356
|
+
return degree
|
|
357
|
+
|
|
358
|
+
def trace(self):
|
|
359
|
+
if self.element_kind == ElementKind.SIDE:
|
|
360
|
+
raise RuntimeError("Trace only available for field defined on cell elements")
|
|
361
|
+
|
|
362
|
+
return ImplicitField(
|
|
363
|
+
domain=Sides(self.domain.geometry_partition),
|
|
364
|
+
func=self._func,
|
|
365
|
+
values={name: getattr(self.values, name) for name in self.EvalArg.vars},
|
|
366
|
+
grad_func=self._grad_func,
|
|
367
|
+
div_func=self._div_func,
|
|
368
|
+
degree=self._degree,
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
class UniformField(GeometryField):
|
|
373
|
+
"""Field defined as a constant value over a domain.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
domain: Domain over which the field is defined
|
|
377
|
+
value: Uniform value over the domain
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
def __init__(self, domain: GeometryDomain, value: Any):
|
|
381
|
+
self.domain = domain
|
|
382
|
+
|
|
383
|
+
if not wp.types.is_value(value):
|
|
384
|
+
raise ValueError("value must be a Warp scalar, vector or matrix")
|
|
385
|
+
|
|
386
|
+
self.dtype = wp.types.type_to_warp(type(value))
|
|
387
|
+
self._value = self.dtype(value)
|
|
388
|
+
|
|
389
|
+
scalar_type = wp.types.type_scalar_type(self.dtype)
|
|
390
|
+
if wp.types.type_is_vector(self.dtype):
|
|
391
|
+
grad_type = wp.mat(shape=(wp.types.type_length(self.dtype), self.geometry.dimension), dtype=scalar_type)
|
|
392
|
+
div_type = scalar_type
|
|
393
|
+
elif wp.types.type_is_matrix(self.dtype):
|
|
394
|
+
grad_type = None
|
|
395
|
+
div_type = wp.vec(length=(wp.types.type_length(self.dtype) // self.geometry.dimension), dtype=scalar_type)
|
|
396
|
+
else:
|
|
397
|
+
div_type = None
|
|
398
|
+
grad_type = wp.vec(length=self.geometry.dimension, dtype=scalar_type)
|
|
399
|
+
|
|
400
|
+
self.EvalArg = self._make_eval_arg()
|
|
401
|
+
self.ElementEvalArg = self._make_element_eval_arg()
|
|
402
|
+
self.eval_degree = self._make_eval_degree()
|
|
403
|
+
|
|
404
|
+
self.eval_inner = self._make_eval_inner()
|
|
405
|
+
self.eval_grad_inner = self._make_eval_zero(grad_type)
|
|
406
|
+
self.eval_div_inner = self._make_eval_zero(div_type)
|
|
407
|
+
self.eval_reference_grad_inner = self.eval_grad_inner
|
|
408
|
+
|
|
409
|
+
self.eval_outer = self.eval_inner
|
|
410
|
+
self.eval_grad_outer = self.eval_grad_inner
|
|
411
|
+
self.eval_div_outer = self.eval_div_inner
|
|
412
|
+
self.eval_reference_grad_outer = self.eval_reference_grad_inner
|
|
413
|
+
|
|
414
|
+
@property
|
|
415
|
+
def value(self):
|
|
416
|
+
return self._value
|
|
417
|
+
|
|
418
|
+
@value.setter
|
|
419
|
+
def value(self, v):
|
|
420
|
+
value_type = wp.types.type_to_warp(type(v))
|
|
421
|
+
assert wp.types.types_equal(value_type, self.dtype)
|
|
422
|
+
self._value = self.dtype(v)
|
|
423
|
+
|
|
424
|
+
@property
|
|
425
|
+
def geometry(self) -> Geometry:
|
|
426
|
+
return self.domain.geometry
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def element_kind(self) -> ElementKind:
|
|
430
|
+
return self.domain.element_kind
|
|
431
|
+
|
|
432
|
+
def eval_arg_value(self, device):
|
|
433
|
+
arg = self.EvalArg()
|
|
434
|
+
arg.value = self.value
|
|
435
|
+
return arg
|
|
436
|
+
|
|
437
|
+
@property
|
|
438
|
+
def degree(self) -> int:
|
|
439
|
+
return 0
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def name(self) -> str:
|
|
443
|
+
return f"Uniform{self.domain.name}_{wp.types.get_type_code(self.dtype)}"
|
|
444
|
+
|
|
445
|
+
def _make_eval_inner(self):
|
|
446
|
+
@cache.dynamic_func(suffix=self.name)
|
|
447
|
+
def eval_inner(args: self.ElementEvalArg, s: Sample):
|
|
448
|
+
return args.eval_arg.value
|
|
449
|
+
|
|
450
|
+
return eval_inner
|
|
451
|
+
|
|
452
|
+
def _make_eval_zero(self, dtype):
|
|
453
|
+
if dtype is None:
|
|
454
|
+
return None
|
|
455
|
+
|
|
456
|
+
scalar_type = wp.types.type_scalar_type(dtype)
|
|
457
|
+
|
|
458
|
+
@cache.dynamic_func(suffix=f"{self.name}_{wp.types.get_type_code(dtype)}")
|
|
459
|
+
def eval_zero(args: self.ElementEvalArg, s: Sample):
|
|
460
|
+
return dtype(scalar_type(0.0))
|
|
461
|
+
|
|
462
|
+
return eval_zero
|
|
463
|
+
|
|
464
|
+
def _make_eval_arg(self):
|
|
465
|
+
@cache.dynamic_struct(suffix=self.name)
|
|
466
|
+
class EvalArg:
|
|
467
|
+
value: self.dtype
|
|
468
|
+
|
|
469
|
+
return EvalArg
|
|
470
|
+
|
|
471
|
+
def _make_element_eval_arg(self):
|
|
472
|
+
@cache.dynamic_struct(suffix=self.name)
|
|
473
|
+
class ElementEvalArg:
|
|
474
|
+
elt_arg: self.domain.ElementArg
|
|
475
|
+
eval_arg: self.EvalArg
|
|
476
|
+
|
|
477
|
+
return ElementEvalArg
|
|
478
|
+
|
|
479
|
+
def _make_eval_degree(self):
|
|
480
|
+
@cache.dynamic_func(suffix=self.name)
|
|
481
|
+
def degree(args: self.ElementEvalArg):
|
|
482
|
+
return 0
|
|
483
|
+
|
|
484
|
+
return degree
|
|
485
|
+
|
|
486
|
+
def trace(self):
|
|
487
|
+
if self.element_kind == ElementKind.SIDE:
|
|
488
|
+
raise RuntimeError("Trace only available for field defined on cell elements")
|
|
489
|
+
|
|
490
|
+
return UniformField(domain=Sides(self.domain.geometry_partition), value=self.value)
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
class NonconformingField(GeometryField):
|
|
494
|
+
"""Field defined as the map of a DiscreteField over a non-conforming geometry.
|
|
495
|
+
|
|
496
|
+
Args:
|
|
497
|
+
domain: The new domain over which the nonconforming field will be evaluated
|
|
498
|
+
field: Nonconforming discrete field
|
|
499
|
+
background: Uniform value or domain-conforming field determining the value outside of the geometry of definition of `field`
|
|
500
|
+
"""
|
|
501
|
+
|
|
502
|
+
_LOOKUP_EPS = wp.constant(1.0e-6)
|
|
503
|
+
|
|
504
|
+
def __init__(self, domain: GeometryDomain, field: DiscreteField, background: Any = 0.0):
|
|
505
|
+
self.domain = domain
|
|
506
|
+
|
|
507
|
+
self.field = field
|
|
508
|
+
self.dtype = field.dtype
|
|
509
|
+
|
|
510
|
+
if not isinstance(background, GeometryField):
|
|
511
|
+
background = UniformField(domain, self.dtype(background))
|
|
512
|
+
elif background.geometry != domain.geometry or background.element_kind != domain.element_kind:
|
|
513
|
+
raise ValueError("Background field must be conforming to the domain")
|
|
514
|
+
self.background = background
|
|
515
|
+
|
|
516
|
+
self.EvalArg = self._make_eval_arg()
|
|
517
|
+
self.ElementEvalArg = self._make_element_eval_arg()
|
|
518
|
+
self.eval_degree = self._make_eval_degree()
|
|
519
|
+
|
|
520
|
+
self.eval_inner = self._make_nonconforming_eval("eval_inner")
|
|
521
|
+
self.eval_grad_inner = self._make_nonconforming_eval("eval_grad_inner")
|
|
522
|
+
self.eval_div_inner = self._make_nonconforming_eval("eval_div_inner")
|
|
523
|
+
self.eval_reference_grad_inner = self._make_eval_reference_grad()
|
|
524
|
+
|
|
525
|
+
# Nonconforming evaluation is position based, does not handle discontinuous fields
|
|
526
|
+
self.eval_outer = self.eval_inner
|
|
527
|
+
self.eval_grad_outer = self.eval_grad_inner
|
|
528
|
+
self.eval_div_outer = self.eval_div_inner
|
|
529
|
+
self.eval_reference_grad_outer = self.eval_reference_grad_inner
|
|
530
|
+
|
|
531
|
+
@property
|
|
532
|
+
def geometry(self) -> Geometry:
|
|
533
|
+
return self.domain.geometry
|
|
534
|
+
|
|
535
|
+
@property
|
|
536
|
+
def element_kind(self) -> ElementKind:
|
|
537
|
+
return self.domain.element_kind
|
|
538
|
+
|
|
539
|
+
@cache.cached_arg_value
|
|
540
|
+
def eval_arg_value(self, device):
|
|
541
|
+
arg = self.EvalArg()
|
|
542
|
+
arg.field_cell_eval_arg = self.field.ElementEvalArg()
|
|
543
|
+
arg.field_cell_eval_arg.elt_arg = self.field.geometry.cell_arg_value(device)
|
|
544
|
+
arg.field_cell_eval_arg.eval_arg = self.field.eval_arg_value(device)
|
|
545
|
+
arg.background_arg = self.background.eval_arg_value(device)
|
|
546
|
+
return arg
|
|
547
|
+
|
|
548
|
+
@property
|
|
549
|
+
def degree(self) -> int:
|
|
550
|
+
return self.field.degree
|
|
551
|
+
|
|
552
|
+
@property
|
|
553
|
+
def name(self) -> str:
|
|
554
|
+
return f"{self.domain.name}_{self.field.name}_{self.background.name}"
|
|
555
|
+
|
|
556
|
+
def _make_nonconforming_eval(self, eval_func_name):
|
|
557
|
+
field_eval = getattr(self.field, eval_func_name)
|
|
558
|
+
bg_eval = getattr(self.background, eval_func_name)
|
|
559
|
+
|
|
560
|
+
if field_eval is None or bg_eval is None:
|
|
561
|
+
return None
|
|
562
|
+
|
|
563
|
+
@cache.dynamic_func(suffix=f"{eval_func_name}_{self.name}")
|
|
564
|
+
def eval_nc(args: self.ElementEvalArg, s: Sample):
|
|
565
|
+
pos = self.domain.element_position(args.elt_arg, s)
|
|
566
|
+
cell_arg = args.eval_arg.field_cell_eval_arg.elt_arg
|
|
567
|
+
nonconforming_s = self.field.geometry.cell_lookup(cell_arg, pos)
|
|
568
|
+
if (
|
|
569
|
+
nonconforming_s.element_index == NULL_ELEMENT_INDEX
|
|
570
|
+
or wp.length_sq(pos - self.field.geometry.cell_position(cell_arg, nonconforming_s))
|
|
571
|
+
> NonconformingField._LOOKUP_EPS
|
|
572
|
+
):
|
|
573
|
+
return bg_eval(self.background.ElementEvalArg(args.elt_arg, args.eval_arg.background_arg), s)
|
|
574
|
+
return field_eval(
|
|
575
|
+
self.field.ElementEvalArg(cell_arg, args.eval_arg.field_cell_eval_arg.eval_arg), nonconforming_s
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
return eval_nc
|
|
579
|
+
|
|
580
|
+
def _make_eval_reference_grad(self):
|
|
581
|
+
if self.eval_grad_inner is None:
|
|
582
|
+
return None
|
|
583
|
+
|
|
584
|
+
@cache.dynamic_func(suffix=f"{self.eval_grad_inner.key}")
|
|
585
|
+
def eval_reference_grad_inner(args: self.ElementEvalArg, s: Sample):
|
|
586
|
+
return self.eval_grad_inner(args, s) * self.domain.element_deformation_gradient(args.elt_arg, s)
|
|
587
|
+
|
|
588
|
+
return eval_reference_grad_inner
|
|
589
|
+
|
|
590
|
+
def _make_eval_arg(self):
|
|
591
|
+
@cache.dynamic_struct(suffix=self.name)
|
|
592
|
+
class EvalArg:
|
|
593
|
+
field_cell_eval_arg: self.field.ElementEvalArg
|
|
594
|
+
background_arg: self.background.EvalArg
|
|
595
|
+
|
|
596
|
+
return EvalArg
|
|
597
|
+
|
|
598
|
+
def _make_element_eval_arg(self):
|
|
599
|
+
@cache.dynamic_struct(suffix=self.name)
|
|
600
|
+
class ElementEvalArg:
|
|
601
|
+
elt_arg: self.domain.ElementArg
|
|
602
|
+
eval_arg: self.EvalArg
|
|
603
|
+
|
|
604
|
+
return ElementEvalArg
|
|
605
|
+
|
|
606
|
+
def _make_eval_degree(self):
|
|
607
|
+
@cache.dynamic_func(suffix=self.name)
|
|
608
|
+
def degree(args: self.ElementEvalArg):
|
|
609
|
+
return self.field.eval_degree(args.eval_arg.field_cell_eval_arg)
|
|
610
|
+
|
|
611
|
+
return degree
|
|
612
|
+
|
|
613
|
+
def trace(self):
|
|
614
|
+
if self.element_kind == ElementKind.SIDE:
|
|
615
|
+
raise RuntimeError("Trace only available for field defined on cell elements")
|
|
616
|
+
|
|
617
|
+
return NonconformingField(
|
|
618
|
+
domain=Sides(self.domain.geometry_partition), field=self.field, background=self.background.trace()
|
|
619
|
+
)
|