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,220 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2022 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
|
+
###########################################################################
|
|
17
|
+
# Example Diffusion MGPU
|
|
18
|
+
#
|
|
19
|
+
# This example illustrates using domain decomposition to
|
|
20
|
+
# solve a diffusion PDE over multiple devices
|
|
21
|
+
###########################################################################
|
|
22
|
+
|
|
23
|
+
from typing import Tuple
|
|
24
|
+
|
|
25
|
+
import warp as wp
|
|
26
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
27
|
+
import warp.fem as fem
|
|
28
|
+
from warp.examples.fem.example_diffusion import diffusion_form, linear_form
|
|
29
|
+
from warp.sparse import bsr_axpy, bsr_mv
|
|
30
|
+
from warp.utils import array_cast
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@fem.integrand
|
|
34
|
+
def mass_form(
|
|
35
|
+
s: fem.Sample,
|
|
36
|
+
u: fem.Field,
|
|
37
|
+
v: fem.Field,
|
|
38
|
+
):
|
|
39
|
+
return u(s) * v(s)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@wp.kernel
|
|
43
|
+
def scal_kernel(a: wp.array(dtype=wp.float64), res: wp.array(dtype=wp.float64), alpha: wp.float64):
|
|
44
|
+
res[wp.tid()] = a[wp.tid()] * alpha
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@wp.kernel
|
|
48
|
+
def sum_kernel(a: wp.indexedarray(dtype=wp.float64), b: wp.array(dtype=wp.float64)):
|
|
49
|
+
a[wp.tid()] = a[wp.tid()] + b[wp.tid()]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def sum_vecs(vecs, indices, sum: wp.array, tmp: wp.array):
|
|
53
|
+
for v, idx in zip(vecs, indices):
|
|
54
|
+
wp.copy(dest=tmp, src=v)
|
|
55
|
+
idx_sum = wp.indexedarray(sum, idx)
|
|
56
|
+
wp.launch(kernel=sum_kernel, dim=idx.shape, device=sum.device, inputs=[idx_sum, tmp])
|
|
57
|
+
|
|
58
|
+
return sum
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class DistributedSystem:
|
|
62
|
+
device = None
|
|
63
|
+
scalar_type: type
|
|
64
|
+
tmp_buf: wp.array
|
|
65
|
+
|
|
66
|
+
nrow: int
|
|
67
|
+
shape = Tuple[int, int]
|
|
68
|
+
rank_data = None
|
|
69
|
+
|
|
70
|
+
def mv_routine(self, x: wp.array, y: wp.array, z: wp.array, alpha=1.0, beta=0.0):
|
|
71
|
+
"""Distributed matrix-vector multiplication routine, for example purposes"""
|
|
72
|
+
|
|
73
|
+
tmp = self.tmp_buf
|
|
74
|
+
|
|
75
|
+
wp.launch(kernel=scal_kernel, dim=y.shape, device=y.device, inputs=[y, z, wp.float64(beta)])
|
|
76
|
+
|
|
77
|
+
stream = wp.get_stream()
|
|
78
|
+
|
|
79
|
+
for mat_i, x_i, y_i, idx in zip(*self.rank_data):
|
|
80
|
+
# WAR copy with indexed array requiring matching shape
|
|
81
|
+
tmp_i = wp.array(ptr=tmp.ptr, device=tmp.device, capacity=tmp.capacity, dtype=tmp.dtype, shape=idx.shape)
|
|
82
|
+
|
|
83
|
+
# Compress rhs on rank 0
|
|
84
|
+
x_idx = wp.indexedarray(x, idx)
|
|
85
|
+
wp.copy(dest=tmp_i, src=x_idx, count=idx.size, stream=stream)
|
|
86
|
+
|
|
87
|
+
# Send to rank i
|
|
88
|
+
wp.copy(dest=x_i, src=tmp_i, count=idx.size, stream=stream)
|
|
89
|
+
|
|
90
|
+
with wp.ScopedDevice(x_i.device):
|
|
91
|
+
wp.wait_stream(stream)
|
|
92
|
+
bsr_mv(A=mat_i, x=x_i, y=y_i, alpha=alpha, beta=0.0)
|
|
93
|
+
|
|
94
|
+
wp.wait_stream(wp.get_stream(x_i.device))
|
|
95
|
+
|
|
96
|
+
# Back to rank 0 for sum
|
|
97
|
+
wp.copy(dest=tmp_i, src=y_i, count=idx.size, stream=stream)
|
|
98
|
+
z_idx = wp.indexedarray(z, idx)
|
|
99
|
+
wp.launch(kernel=sum_kernel, dim=idx.shape, device=z_idx.device, inputs=[z_idx, tmp_i], stream=stream)
|
|
100
|
+
|
|
101
|
+
wp.wait_stream(stream)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class Example:
|
|
105
|
+
def __init__(self, quiet=False, device=None):
|
|
106
|
+
self._bd_weight = 100.0
|
|
107
|
+
self._quiet = quiet
|
|
108
|
+
|
|
109
|
+
self._geo = fem.Grid2D(res=wp.vec2i(25))
|
|
110
|
+
|
|
111
|
+
self._main_device = wp.get_device(device)
|
|
112
|
+
|
|
113
|
+
with wp.ScopedDevice(self._main_device):
|
|
114
|
+
self._scalar_space = fem.make_polynomial_space(self._geo, degree=3)
|
|
115
|
+
self._scalar_field = self._scalar_space.make_field()
|
|
116
|
+
|
|
117
|
+
self.renderer = fem_example_utils.Plot()
|
|
118
|
+
|
|
119
|
+
def step(self):
|
|
120
|
+
devices = wp.get_cuda_devices()
|
|
121
|
+
main_device = self._main_device
|
|
122
|
+
|
|
123
|
+
rhs_vecs = []
|
|
124
|
+
res_vecs = []
|
|
125
|
+
matrices = []
|
|
126
|
+
indices = []
|
|
127
|
+
|
|
128
|
+
# Build local system for each device
|
|
129
|
+
for k, device in enumerate(devices):
|
|
130
|
+
with wp.ScopedDevice(device):
|
|
131
|
+
# Construct the partition corresponding to the k'th device
|
|
132
|
+
geo_partition = fem.LinearGeometryPartition(self._geo, k, len(devices))
|
|
133
|
+
matrix, rhs, partition_node_indices = self._assemble_local_system(geo_partition)
|
|
134
|
+
|
|
135
|
+
rhs_vecs.append(rhs)
|
|
136
|
+
res_vecs.append(wp.empty_like(rhs))
|
|
137
|
+
matrices.append(matrix)
|
|
138
|
+
indices.append(partition_node_indices.to(main_device))
|
|
139
|
+
|
|
140
|
+
# Global rhs as sum of all local rhs
|
|
141
|
+
glob_rhs = wp.zeros(n=self._scalar_space.node_count(), dtype=wp.float64, device=main_device)
|
|
142
|
+
|
|
143
|
+
# This temporary buffer will be used for peer-to-peer copying during graph capture,
|
|
144
|
+
# so we allocate it using the default CUDA allocator. This ensures that the copying
|
|
145
|
+
# will succeed without enabling mempool access between devices, which is not supported
|
|
146
|
+
# on all systems.
|
|
147
|
+
with wp.ScopedMempool(main_device, False):
|
|
148
|
+
tmp = wp.empty_like(glob_rhs)
|
|
149
|
+
|
|
150
|
+
sum_vecs(rhs_vecs, indices, glob_rhs, tmp)
|
|
151
|
+
|
|
152
|
+
# Distributed CG
|
|
153
|
+
global_res = wp.zeros_like(glob_rhs)
|
|
154
|
+
A = DistributedSystem()
|
|
155
|
+
A.device = main_device
|
|
156
|
+
A.dtype = glob_rhs.dtype
|
|
157
|
+
A.nrow = self._scalar_space.node_count()
|
|
158
|
+
A.shape = (A.nrow, A.nrow)
|
|
159
|
+
A.tmp_buf = tmp
|
|
160
|
+
A.rank_data = (matrices, rhs_vecs, res_vecs, indices)
|
|
161
|
+
|
|
162
|
+
with wp.ScopedDevice(main_device):
|
|
163
|
+
fem_example_utils.bsr_cg(
|
|
164
|
+
A, x=global_res, b=glob_rhs, use_diag_precond=False, quiet=self._quiet, mv_routine=A.mv_routine
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
array_cast(in_array=global_res, out_array=self._scalar_field.dof_values)
|
|
168
|
+
|
|
169
|
+
def render(self):
|
|
170
|
+
self.renderer.add_field("solution", self._scalar_field)
|
|
171
|
+
|
|
172
|
+
def _assemble_local_system(self, geo_partition: fem.GeometryPartition):
|
|
173
|
+
scalar_space = self._scalar_space
|
|
174
|
+
space_partition = fem.make_space_partition(scalar_space, geo_partition)
|
|
175
|
+
|
|
176
|
+
domain = fem.Cells(geometry=geo_partition)
|
|
177
|
+
|
|
178
|
+
# Right-hand-side
|
|
179
|
+
test = fem.make_test(space=scalar_space, space_partition=space_partition, domain=domain)
|
|
180
|
+
rhs = fem.integrate(linear_form, fields={"v": test})
|
|
181
|
+
|
|
182
|
+
# Weakly-imposed boundary conditions on all sides
|
|
183
|
+
boundary = fem.BoundarySides(geometry=geo_partition)
|
|
184
|
+
bd_test = fem.make_test(space=scalar_space, space_partition=space_partition, domain=boundary)
|
|
185
|
+
bd_trial = fem.make_trial(space=scalar_space, space_partition=space_partition, domain=boundary)
|
|
186
|
+
bd_matrix = fem.integrate(mass_form, fields={"u": bd_trial, "v": bd_test})
|
|
187
|
+
|
|
188
|
+
# Diffusion form
|
|
189
|
+
trial = fem.make_trial(space=scalar_space, space_partition=space_partition, domain=domain)
|
|
190
|
+
matrix = fem.integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": 1.0})
|
|
191
|
+
|
|
192
|
+
bsr_axpy(y=matrix, x=bd_matrix, alpha=self._bd_weight)
|
|
193
|
+
|
|
194
|
+
return matrix, rhs, space_partition.space_node_indices()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
import argparse
|
|
199
|
+
|
|
200
|
+
wp.set_module_options({"enable_backward": False})
|
|
201
|
+
|
|
202
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
203
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
204
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
205
|
+
parser.add_argument(
|
|
206
|
+
"--headless",
|
|
207
|
+
action="store_true",
|
|
208
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
args = parser.parse_known_args()[0]
|
|
212
|
+
|
|
213
|
+
with wp.ScopedTimer(__file__):
|
|
214
|
+
example = Example(quiet=args.quiet, device=args.device)
|
|
215
|
+
|
|
216
|
+
example.step()
|
|
217
|
+
example.render()
|
|
218
|
+
|
|
219
|
+
if not args.headless:
|
|
220
|
+
example.renderer.plot()
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2022 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
|
+
###########################################################################
|
|
17
|
+
# Example Distortion Energy
|
|
18
|
+
#
|
|
19
|
+
# This example illustrates using a Newton loop to minimize distortion of a
|
|
20
|
+
# 3D surface (u,v) parameterization under a Symmetric Dirichlet energy,
|
|
21
|
+
#
|
|
22
|
+
# E(F) = 1/2 |F|^2 + |F^{-1}|^2
|
|
23
|
+
#
|
|
24
|
+
# with F := dx/du
|
|
25
|
+
###########################################################################
|
|
26
|
+
|
|
27
|
+
import numpy as np
|
|
28
|
+
|
|
29
|
+
import warp as wp
|
|
30
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
31
|
+
import warp.fem as fem
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@fem.integrand
|
|
35
|
+
def distortion_gradient_form(s: fem.Sample, u_cur: fem.Field, v: fem.Field):
|
|
36
|
+
# Symmetric Dirichlet energy gradient (linear form)
|
|
37
|
+
# E = 1/2 (F:F + F^-T:F^-T)
|
|
38
|
+
|
|
39
|
+
F = fem.grad(u_cur, s)
|
|
40
|
+
|
|
41
|
+
F_inv_sq = wp.inverse(F * wp.transpose(F))
|
|
42
|
+
F_inv = F_inv_sq * F
|
|
43
|
+
|
|
44
|
+
dE_dF = F - F_inv_sq * F_inv
|
|
45
|
+
|
|
46
|
+
return wp.ddot(fem.grad(v, s), dE_dF)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@fem.integrand
|
|
50
|
+
def distortion_hessian_form(s: fem.Sample, u_cur: fem.Field, u: fem.Field, v: fem.Field):
|
|
51
|
+
# Symmetric Dirichlet energy approximate hessian (bilinear form)
|
|
52
|
+
|
|
53
|
+
# F:F term
|
|
54
|
+
H = wp.ddot(fem.grad(v, s), fem.grad(u, s))
|
|
55
|
+
|
|
56
|
+
# F^-T:F^-T term
|
|
57
|
+
F = fem.grad(u_cur, s)
|
|
58
|
+
F_inv_sq = wp.inverse(F * wp.transpose(F))
|
|
59
|
+
|
|
60
|
+
# Gauss--Newton (ignore F^-2 derivative)
|
|
61
|
+
H += wp.ddot(F_inv_sq * fem.grad(v, s), F_inv_sq * F_inv_sq * fem.grad(u, s))
|
|
62
|
+
|
|
63
|
+
return H
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@fem.integrand
|
|
67
|
+
def initial_guess(
|
|
68
|
+
s: fem.Sample,
|
|
69
|
+
domain: fem.Domain,
|
|
70
|
+
):
|
|
71
|
+
# initialization for UV parameter
|
|
72
|
+
x = domain(s)
|
|
73
|
+
return wp.vec2(x[0], x[1])
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@fem.integrand
|
|
77
|
+
def boundary_projector_form(
|
|
78
|
+
s: fem.Sample,
|
|
79
|
+
domain: fem.Domain,
|
|
80
|
+
u: fem.Field,
|
|
81
|
+
v: fem.Field,
|
|
82
|
+
):
|
|
83
|
+
# Fix a single point
|
|
84
|
+
# (underconstrained, solution up to a rotation in UV space)
|
|
85
|
+
w = wp.where(s.qp_index == 0, 1.0, 0.0)
|
|
86
|
+
return w * wp.dot(u(s), v(s))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@fem.integrand
|
|
90
|
+
def checkerboard(s: fem.Sample, domain: fem.Domain, u: fem.Field):
|
|
91
|
+
# checkerboard pattern for parameter visualization
|
|
92
|
+
u_s = u(s)
|
|
93
|
+
return wp.sign(wp.cos(16.0 * u_s[0]) * wp.sin(16.0 * u_s[1]))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class Example:
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
quiet=False,
|
|
100
|
+
degree=2,
|
|
101
|
+
resolution=25,
|
|
102
|
+
mesh="grid",
|
|
103
|
+
nonconforming_stresses=False,
|
|
104
|
+
):
|
|
105
|
+
self._quiet = quiet
|
|
106
|
+
|
|
107
|
+
def deform_along_z(positions, z_scale=1.0):
|
|
108
|
+
pos = positions.numpy()
|
|
109
|
+
pos_z = z_scale * np.cos(3.0 * pos[:, 0]) * np.sin(4.0 * pos[:, 1])
|
|
110
|
+
pos = np.hstack((pos, np.expand_dims(pos_z, axis=1)))
|
|
111
|
+
return wp.array(pos, dtype=wp.vec3)
|
|
112
|
+
|
|
113
|
+
# Grid or mesh geometry
|
|
114
|
+
if mesh == "tri":
|
|
115
|
+
positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(resolution))
|
|
116
|
+
self._uv_geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=wp.zeros_like(positions))
|
|
117
|
+
|
|
118
|
+
positions = deform_along_z(positions)
|
|
119
|
+
self._geo = fem.Trimesh3D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
120
|
+
elif mesh == "quad":
|
|
121
|
+
positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
|
|
122
|
+
self._uv_geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=wp.zeros_like(positions))
|
|
123
|
+
|
|
124
|
+
positions = deform_along_z(positions)
|
|
125
|
+
self._geo = fem.Quadmesh3D(quad_vertex_indices=quad_vidx, positions=positions)
|
|
126
|
+
else:
|
|
127
|
+
positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
|
|
128
|
+
self._uv_geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=wp.zeros_like(positions))
|
|
129
|
+
|
|
130
|
+
undef_positions = deform_along_z(positions, z_scale=0.0)
|
|
131
|
+
flat_geo = fem.Quadmesh3D(quad_vertex_indices=quad_vidx, positions=undef_positions)
|
|
132
|
+
|
|
133
|
+
deformation_field = fem.make_discrete_field(fem.make_polynomial_space(flat_geo, dtype=wp.vec3))
|
|
134
|
+
deformation_field.dof_values = deform_along_z(positions)
|
|
135
|
+
|
|
136
|
+
self._geo = deformation_field.make_deformed_geometry(relative=False)
|
|
137
|
+
|
|
138
|
+
# parameter space
|
|
139
|
+
self._u_space = fem.make_polynomial_space(self._geo, degree=degree, dtype=wp.vec2)
|
|
140
|
+
self._u_field = self._u_space.make_field()
|
|
141
|
+
self._du_field = self._u_space.make_field()
|
|
142
|
+
fem.interpolate(initial_guess, dest=self._u_field)
|
|
143
|
+
|
|
144
|
+
# scalar parameter visualization function
|
|
145
|
+
viz_space = fem.make_polynomial_space(self._geo, degree=3, dtype=float)
|
|
146
|
+
self.viz_field = viz_space.make_field()
|
|
147
|
+
# For visualization of uv in 2D space
|
|
148
|
+
uv_space = fem.make_polynomial_space(self._uv_geo, degree=degree, dtype=wp.vec2)
|
|
149
|
+
self._uv_field = uv_space.make_field()
|
|
150
|
+
|
|
151
|
+
self.renderer = fem_example_utils.Plot()
|
|
152
|
+
|
|
153
|
+
def step(self):
|
|
154
|
+
boundary = fem.BoundarySides(self._geo)
|
|
155
|
+
domain = fem.Cells(geometry=self._geo)
|
|
156
|
+
|
|
157
|
+
# Parameter boundary conditions
|
|
158
|
+
u_bd_test = fem.make_test(space=self._u_space, domain=boundary)
|
|
159
|
+
u_bd_trial = fem.make_trial(space=self._u_space, domain=boundary)
|
|
160
|
+
u_bd_matrix = fem.integrate(
|
|
161
|
+
boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True, output_dtype=float
|
|
162
|
+
)
|
|
163
|
+
fem.normalize_dirichlet_projector(u_bd_matrix)
|
|
164
|
+
|
|
165
|
+
u_test = fem.make_test(space=self._u_space, domain=domain)
|
|
166
|
+
u_trial = fem.make_trial(space=self._u_space, domain=domain)
|
|
167
|
+
|
|
168
|
+
# Newton iterations (without line-search for simplicity)
|
|
169
|
+
for _newton_iteration in range(10):
|
|
170
|
+
u_matrix = fem.integrate(
|
|
171
|
+
distortion_hessian_form, fields={"u_cur": self._u_field, "u": u_trial, "v": u_test}, output_dtype=float
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
u_rhs = fem.integrate(
|
|
175
|
+
distortion_gradient_form, fields={"u_cur": self._u_field, "v": u_test}, output_dtype=wp.vec2
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
fem.project_linear_system(u_matrix, u_rhs, u_bd_matrix, normalize_projector=False)
|
|
179
|
+
|
|
180
|
+
# Solve for uv increment
|
|
181
|
+
du = self._du_field.dof_values
|
|
182
|
+
du.zero_()
|
|
183
|
+
fem_example_utils.bsr_cg(u_matrix, b=u_rhs, x=du, quiet=self._quiet)
|
|
184
|
+
|
|
185
|
+
# Accumulate to UV field
|
|
186
|
+
fem.utils.array_axpy(x=du, y=self._u_field.dof_values, alpha=-1.0, beta=1.0)
|
|
187
|
+
|
|
188
|
+
def render(self):
|
|
189
|
+
# Visualization
|
|
190
|
+
fem.interpolate(checkerboard, fields={"u": self._u_field}, dest=self.viz_field)
|
|
191
|
+
|
|
192
|
+
self._uv_field.dof_values = wp.clone(self._u_field.dof_values)
|
|
193
|
+
|
|
194
|
+
self.renderer.add_field("pattern", self.viz_field)
|
|
195
|
+
self.renderer.add_field("uv", self._uv_field)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
import argparse
|
|
200
|
+
|
|
201
|
+
wp.set_module_options({"enable_backward": False})
|
|
202
|
+
|
|
203
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
204
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
205
|
+
parser.add_argument("--resolution", type=int, default=25, help="Grid resolution.")
|
|
206
|
+
parser.add_argument("--degree", type=int, default=1, help="Polynomial degree of shape functions.")
|
|
207
|
+
parser.add_argument("--mesh", choices=("tri", "quad", "deformed"), default="tri", help="Mesh type")
|
|
208
|
+
parser.add_argument(
|
|
209
|
+
"--headless",
|
|
210
|
+
action="store_true",
|
|
211
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
212
|
+
)
|
|
213
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
214
|
+
|
|
215
|
+
args = parser.parse_known_args()[0]
|
|
216
|
+
|
|
217
|
+
with wp.ScopedDevice(args.device):
|
|
218
|
+
example = Example(
|
|
219
|
+
quiet=args.quiet,
|
|
220
|
+
degree=args.degree,
|
|
221
|
+
resolution=args.resolution,
|
|
222
|
+
mesh=args.mesh,
|
|
223
|
+
)
|
|
224
|
+
example.step()
|
|
225
|
+
example.render()
|
|
226
|
+
|
|
227
|
+
if not args.headless:
|
|
228
|
+
example.renderer.plot(options={"uv": {"displacement": {}}})
|
|
@@ -0,0 +1,240 @@
|
|
|
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
|
+
###########################################################################
|
|
17
|
+
# Example Magnetostatics
|
|
18
|
+
#
|
|
19
|
+
# This example demonstrates solving a 3d magnetostatics problem
|
|
20
|
+
# (a copper coil with radial current around a cylindrical iron core)
|
|
21
|
+
# using a curl-curl formulation and H(curl)-conforming function space
|
|
22
|
+
#
|
|
23
|
+
# 1/mu Curl B + j = 0
|
|
24
|
+
# Div. B = 0
|
|
25
|
+
#
|
|
26
|
+
# solved over field A such that B = Curl A,
|
|
27
|
+
# and Direchlet homogeneous essential boundary conditions
|
|
28
|
+
#
|
|
29
|
+
# This example also illustrates using an ImplictField to warp a grid mesh
|
|
30
|
+
# to a cylindrical domain
|
|
31
|
+
###########################################################################
|
|
32
|
+
|
|
33
|
+
import numpy as np
|
|
34
|
+
|
|
35
|
+
import warp as wp
|
|
36
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
37
|
+
import warp.fem as fem
|
|
38
|
+
|
|
39
|
+
# Physics constants
|
|
40
|
+
MU_0 = wp.constant(np.pi * 4.0e-7) # Vacuum magnetic permeability
|
|
41
|
+
MU_c = wp.constant(1.25e-6) # Copper magnetic permeability
|
|
42
|
+
MU_i = wp.constant(6.0e-3) # Iron magnetic permeability
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@wp.func
|
|
46
|
+
def cube_to_cylinder(x: wp.vec3):
|
|
47
|
+
# mapping from unit square to unit disk
|
|
48
|
+
pos_xz = wp.vec3(x[0], 0.0, x[2])
|
|
49
|
+
return wp.max(wp.abs(pos_xz)) * wp.normalize(pos_xz) + wp.vec3(0.0, x[1], 0.0)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@wp.func
|
|
53
|
+
def cube_to_cylinder_grad(x: wp.vec3):
|
|
54
|
+
# gradient of mapping from unit square to unit disk
|
|
55
|
+
pos_xz = wp.vec3(x[0], 0.0, x[2])
|
|
56
|
+
if pos_xz == wp.vec3(0.0):
|
|
57
|
+
grad = wp.mat33(0.0)
|
|
58
|
+
else:
|
|
59
|
+
dir_xz = wp.normalize(pos_xz)
|
|
60
|
+
dir_grad = (wp.identity(n=3, dtype=float) - wp.outer(dir_xz, dir_xz)) / wp.length(pos_xz)
|
|
61
|
+
|
|
62
|
+
abs_xz = wp.abs(pos_xz)
|
|
63
|
+
xinf_grad = wp.where(
|
|
64
|
+
abs_xz[0] > abs_xz[2], wp.vec(wp.sign(pos_xz[0]), 0.0, 0.0), wp.vec3(0.0, 0.0, wp.sign(pos_xz[2]))
|
|
65
|
+
)
|
|
66
|
+
grad = dir_grad * wp.max(abs_xz) + wp.outer(dir_xz, xinf_grad)
|
|
67
|
+
|
|
68
|
+
grad[1, 1] = 1.0
|
|
69
|
+
return grad
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@wp.func
|
|
73
|
+
def permeability_field(
|
|
74
|
+
pos: wp.vec3,
|
|
75
|
+
core_radius: float,
|
|
76
|
+
core_height: float,
|
|
77
|
+
coil_internal_radius: float,
|
|
78
|
+
coil_external_radius: float,
|
|
79
|
+
coil_height: float,
|
|
80
|
+
):
|
|
81
|
+
x = wp.abs(pos[0])
|
|
82
|
+
y = wp.abs(pos[1])
|
|
83
|
+
z = wp.abs(pos[2])
|
|
84
|
+
|
|
85
|
+
r = wp.sqrt(x * x + z * z)
|
|
86
|
+
|
|
87
|
+
if r <= core_radius:
|
|
88
|
+
return wp.where(y < core_height, MU_i, MU_0)
|
|
89
|
+
|
|
90
|
+
if r >= coil_internal_radius and r <= coil_external_radius:
|
|
91
|
+
return wp.where(y < coil_height, MU_c, MU_0)
|
|
92
|
+
|
|
93
|
+
return MU_0
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@wp.func
|
|
97
|
+
def current_field(
|
|
98
|
+
pos: wp.vec3,
|
|
99
|
+
current: float,
|
|
100
|
+
coil_internal_radius: float,
|
|
101
|
+
coil_external_radius: float,
|
|
102
|
+
coil_height: float,
|
|
103
|
+
):
|
|
104
|
+
x = pos[0]
|
|
105
|
+
y = wp.abs(pos[1])
|
|
106
|
+
z = pos[2]
|
|
107
|
+
|
|
108
|
+
r = wp.sqrt(x * x + z * z)
|
|
109
|
+
|
|
110
|
+
return wp.where(
|
|
111
|
+
y < coil_height and r >= coil_internal_radius and r <= coil_external_radius,
|
|
112
|
+
wp.vec3(z, 0.0, -x) * current / r,
|
|
113
|
+
wp.vec3(0.0),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@fem.integrand
|
|
118
|
+
def curl_curl_form(s: fem.Sample, domain: fem.Domain, u: fem.Field, v: fem.Field, mu: fem.Field):
|
|
119
|
+
return wp.dot(fem.curl(u, s), fem.curl(v, s)) / mu(s)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@fem.integrand
|
|
123
|
+
def mass_form(s: fem.Sample, domain: fem.Domain, v: fem.Field, u: fem.Field):
|
|
124
|
+
return wp.dot(u(s), v(s))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@fem.integrand
|
|
128
|
+
def curl_expr(s: fem.Sample, u: fem.Field):
|
|
129
|
+
return fem.curl(u, s)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class Example:
|
|
133
|
+
def __init__(self, quiet=False, mesh: str = "grid", resolution=32, domain_radius=2.0, current=1.0e6):
|
|
134
|
+
# We mesh the unit disk by first meshing the unit square, then building a deformed geometry
|
|
135
|
+
# from an implicit mapping field
|
|
136
|
+
|
|
137
|
+
if mesh == "hex":
|
|
138
|
+
positions, hex_vidx = fem_example_utils.gen_hexmesh(
|
|
139
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
140
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
141
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
142
|
+
)
|
|
143
|
+
cube_geo = fem.Hexmesh(hex_vertex_indices=hex_vidx, positions=positions)
|
|
144
|
+
elif mesh == "tet":
|
|
145
|
+
positions, tet_vidx = fem_example_utils.gen_tetmesh(
|
|
146
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
147
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
148
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
149
|
+
)
|
|
150
|
+
cube_geo = fem.Tetmesh(tet_vertex_indices=tet_vidx, positions=positions)
|
|
151
|
+
elif mesh == "nano":
|
|
152
|
+
vol = fem_example_utils.gen_volume(
|
|
153
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
154
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
155
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
156
|
+
)
|
|
157
|
+
cube_geo = fem.Nanogrid(grid=vol)
|
|
158
|
+
else:
|
|
159
|
+
cube_geo = fem.Grid3D(
|
|
160
|
+
bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
|
|
161
|
+
bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
|
|
162
|
+
res=wp.vec3i(resolution, resolution, resolution),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def_field = fem.ImplicitField(
|
|
166
|
+
domain=fem.Cells(cube_geo), func=cube_to_cylinder, grad_func=cube_to_cylinder_grad
|
|
167
|
+
)
|
|
168
|
+
sim_geo = def_field.make_deformed_geometry(relative=False)
|
|
169
|
+
|
|
170
|
+
coil_config = {"coil_height": 0.25, "coil_internal_radius": 0.3, "coil_external_radius": 0.4}
|
|
171
|
+
core_config = {"core_height": 1.0, "core_radius": 0.2}
|
|
172
|
+
|
|
173
|
+
domain = fem.Cells(sim_geo)
|
|
174
|
+
self._permeability_field = fem.ImplicitField(
|
|
175
|
+
domain, func=permeability_field, values=dict(**coil_config, **core_config)
|
|
176
|
+
)
|
|
177
|
+
self._current_field = fem.ImplicitField(domain, func=current_field, values=dict(current=current, **coil_config))
|
|
178
|
+
|
|
179
|
+
A_space = fem.make_polynomial_space(
|
|
180
|
+
sim_geo, degree=1, element_basis=fem.ElementBasis.NEDELEC_FIRST_KIND, dtype=wp.vec3
|
|
181
|
+
)
|
|
182
|
+
self.A_field = A_space.make_field()
|
|
183
|
+
|
|
184
|
+
B_space = fem.make_polynomial_space(sim_geo, degree=1, element_basis=fem.ElementBasis.LAGRANGE, dtype=wp.vec3)
|
|
185
|
+
self.B_field = B_space.make_field()
|
|
186
|
+
|
|
187
|
+
self.renderer = fem_example_utils.Plot()
|
|
188
|
+
|
|
189
|
+
def step(self):
|
|
190
|
+
A_space = self.A_field.space
|
|
191
|
+
sim_geo = A_space.geometry
|
|
192
|
+
|
|
193
|
+
u = fem.make_trial(space=A_space)
|
|
194
|
+
v = fem.make_test(space=A_space)
|
|
195
|
+
lhs = fem.integrate(curl_curl_form, fields={"u": u, "v": v, "mu": self._permeability_field}, output_dtype=float)
|
|
196
|
+
rhs = fem.integrate(mass_form, fields={"v": v, "u": self._current_field}, output_dtype=float)
|
|
197
|
+
|
|
198
|
+
# Dirichlet BC
|
|
199
|
+
boundary = fem.BoundarySides(sim_geo)
|
|
200
|
+
u_bd = fem.make_trial(space=A_space, domain=boundary)
|
|
201
|
+
v_bd = fem.make_test(space=A_space, domain=boundary)
|
|
202
|
+
dirichlet_bd_proj = fem.integrate(mass_form, fields={"u": u_bd, "v": v_bd}, nodal=True, output_dtype=float)
|
|
203
|
+
fem.project_linear_system(lhs, rhs, dirichlet_bd_proj)
|
|
204
|
+
|
|
205
|
+
# solve using Conjugate Residual (numerically rhs may not be in image of lhs)
|
|
206
|
+
fem_example_utils.bsr_cg(lhs, b=rhs, x=self.A_field.dof_values, method="cr", max_iters=250, quiet=False)
|
|
207
|
+
|
|
208
|
+
# compute B as curl(A)
|
|
209
|
+
fem.interpolate(curl_expr, dest=self.B_field, fields={"u": self.A_field})
|
|
210
|
+
|
|
211
|
+
def render(self):
|
|
212
|
+
self.renderer.add_field("B", self.B_field)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__":
|
|
216
|
+
import argparse
|
|
217
|
+
|
|
218
|
+
wp.set_module_options({"enable_backward": False})
|
|
219
|
+
|
|
220
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
221
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
222
|
+
parser.add_argument("--resolution", type=int, default=32, help="Grid resolution.")
|
|
223
|
+
parser.add_argument("--mesh", type=str, default="grid", choices=["tet", "hex", "grid", "nano"], help="Mesh type.")
|
|
224
|
+
parser.add_argument("--radius", type=float, default=2.0, help="Radius of simulation domain.")
|
|
225
|
+
parser.add_argument(
|
|
226
|
+
"--headless",
|
|
227
|
+
action="store_true",
|
|
228
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
229
|
+
)
|
|
230
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
231
|
+
|
|
232
|
+
args = parser.parse_known_args()[0]
|
|
233
|
+
|
|
234
|
+
with wp.ScopedDevice(args.device):
|
|
235
|
+
example = Example(quiet=args.quiet, mesh=args.mesh, resolution=args.resolution, domain_radius=args.radius)
|
|
236
|
+
example.step()
|
|
237
|
+
example.render()
|
|
238
|
+
|
|
239
|
+
if not args.headless:
|
|
240
|
+
example.renderer.plot({"B": {"streamlines": {"density": 1.0}}})
|