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,286 @@
|
|
|
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 Adaptive Grid
|
|
18
|
+
#
|
|
19
|
+
# Demonstrates using an adaptive grid to increase the simulation resolition
|
|
20
|
+
# near a collider boundary.
|
|
21
|
+
#
|
|
22
|
+
###########################################################################
|
|
23
|
+
import os.path
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
|
|
27
|
+
import warp as wp
|
|
28
|
+
import warp.examples
|
|
29
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
30
|
+
import warp.fem as fem
|
|
31
|
+
from warp.examples.fem.example_apic_fluid import divergence_form, solve_incompressibility
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@fem.integrand
|
|
35
|
+
def inflow_velocity(
|
|
36
|
+
s: fem.Sample,
|
|
37
|
+
domain: fem.Domain,
|
|
38
|
+
bounds_lo: wp.vec3,
|
|
39
|
+
bounds_hi: wp.vec3,
|
|
40
|
+
):
|
|
41
|
+
x = fem.position(domain, s)
|
|
42
|
+
|
|
43
|
+
if x[1] <= bounds_lo[1] or x[2] <= bounds_lo[2] or x[1] >= bounds_hi[1] or x[2] >= bounds_hi[2]:
|
|
44
|
+
return wp.vec3(0.0)
|
|
45
|
+
|
|
46
|
+
if x[0] <= bounds_lo[0] or x[0] >= bounds_hi[0]:
|
|
47
|
+
return wp.vec3(1.0, 0.0, 0.0)
|
|
48
|
+
|
|
49
|
+
return wp.vec3(0.0)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@fem.integrand
|
|
53
|
+
def noslip_projector_form(
|
|
54
|
+
s: fem.Sample,
|
|
55
|
+
u: fem.Field,
|
|
56
|
+
v: fem.Field,
|
|
57
|
+
):
|
|
58
|
+
return wp.dot(u(s), v(s))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@fem.integrand
|
|
62
|
+
def mass_form(
|
|
63
|
+
s: fem.Sample,
|
|
64
|
+
u: fem.Field,
|
|
65
|
+
v: fem.Field,
|
|
66
|
+
):
|
|
67
|
+
return fem.linalg.generalized_inner(u(s), v(s))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@fem.integrand
|
|
71
|
+
def side_divergence_form(s: fem.Sample, domain: fem.Domain, u: fem.Field, psi: fem.Field):
|
|
72
|
+
# normal velocity jump (non-zero at resolution boundaries)
|
|
73
|
+
return -wp.dot(fem.jump(u, s), fem.normal(domain, s)) * psi(s)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@wp.func
|
|
77
|
+
def refinement_field(xyz: wp.vec3, volume: wp.uint64):
|
|
78
|
+
# use distance to collider as refinement function
|
|
79
|
+
uvw = wp.volume_world_to_index(volume, xyz)
|
|
80
|
+
sdf = wp.volume_sample_f(volume, uvw, wp.Volume.LINEAR)
|
|
81
|
+
|
|
82
|
+
if sdf < 0.0:
|
|
83
|
+
return sdf
|
|
84
|
+
|
|
85
|
+
# combine with heuristical distance to keep coarsening past nvdb narrowband
|
|
86
|
+
return 0.5 * wp.max(wp.length(xyz) - 20.0, sdf)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@fem.integrand
|
|
90
|
+
def pressure_anomaly_field(s: fem.Sample, domain: fem.Domain, pressure: fem.Field):
|
|
91
|
+
# for visualization, deduce affine part such that grad P = u_x
|
|
92
|
+
x = domain(s)
|
|
93
|
+
return pressure(s) + x[0]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class Example:
|
|
97
|
+
def __init__(
|
|
98
|
+
self, quiet=False, degree=2, div_conforming=False, base_resolution=8, level_count=4, headless: bool = False
|
|
99
|
+
):
|
|
100
|
+
self._quiet = quiet
|
|
101
|
+
self._degree = degree
|
|
102
|
+
self._div_conforming = div_conforming
|
|
103
|
+
|
|
104
|
+
# Start from a coarse, dense grid
|
|
105
|
+
res = wp.vec3i(2 * base_resolution, base_resolution // 2, base_resolution)
|
|
106
|
+
bounds_lo = wp.vec3(-50.0, 0.0, -17.5)
|
|
107
|
+
bounds_hi = wp.vec3(50.0, 12.5, 17.5)
|
|
108
|
+
sim_vol = fem_example_utils.gen_volume(res=res, bounds_lo=bounds_lo, bounds_hi=bounds_hi)
|
|
109
|
+
|
|
110
|
+
# load collision volume
|
|
111
|
+
collider_path = os.path.join(warp.examples.get_asset_directory(), "rocks.nvdb")
|
|
112
|
+
with open(collider_path, "rb") as file:
|
|
113
|
+
# create Volume object
|
|
114
|
+
collider = wp.Volume.load_from_nvdb(file)
|
|
115
|
+
|
|
116
|
+
# Make adaptive grid from coarse base and refinement field
|
|
117
|
+
refinement = fem.ImplicitField(
|
|
118
|
+
domain=fem.Cells(fem.Nanogrid(sim_vol)), func=refinement_field, values={"volume": collider.id}
|
|
119
|
+
)
|
|
120
|
+
self._geo = fem.adaptivity.adaptive_nanogrid_from_field(
|
|
121
|
+
sim_vol, level_count, refinement_field=refinement, grading="face"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Function spaces for velocity, pressure (RTk / Pk-1 or Pk / Pk-1)
|
|
125
|
+
u_space = fem.make_polynomial_space(
|
|
126
|
+
geo=self._geo,
|
|
127
|
+
element_basis=fem.ElementBasis.RAVIART_THOMAS if div_conforming else None,
|
|
128
|
+
degree=self._degree,
|
|
129
|
+
dtype=wp.vec3,
|
|
130
|
+
)
|
|
131
|
+
p_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree - 1, dtype=float)
|
|
132
|
+
|
|
133
|
+
self.pressure_field = p_space.make_field()
|
|
134
|
+
self.pressure_anomaly_field = p_space.make_field()
|
|
135
|
+
self.velocity_field = u_space.make_field()
|
|
136
|
+
|
|
137
|
+
# Initialize velocity field with BC
|
|
138
|
+
bounds_scale = 0.9999 # account for difference between bounds and actual grid extents
|
|
139
|
+
bounds_center = 0.5 * (bounds_hi + bounds_lo)
|
|
140
|
+
bounds_extent = 0.5 * (bounds_hi - bounds_lo)
|
|
141
|
+
fem.interpolate(
|
|
142
|
+
inflow_velocity,
|
|
143
|
+
dest=fem.make_restriction(self.velocity_field, domain=fem.BoundarySides(self._geo)),
|
|
144
|
+
values={
|
|
145
|
+
"bounds_lo": bounds_center - bounds_scale * bounds_extent,
|
|
146
|
+
"bounds_hi": bounds_center + bounds_scale * bounds_extent,
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
self.plot = fem_example_utils.Plot()
|
|
151
|
+
|
|
152
|
+
def render(self):
|
|
153
|
+
# self.renderer.add_field("solution", self.pressure_field)
|
|
154
|
+
self.plot.add_field("pressure_anomaly", self.pressure_anomaly_field)
|
|
155
|
+
|
|
156
|
+
if self._div_conforming:
|
|
157
|
+
# If using H(div)-conforming elements, interpolate to continuous space
|
|
158
|
+
velocity_field_lagrange = fem.make_polynomial_space(
|
|
159
|
+
self.velocity_field.geometry, dtype=wp.vec3, degree=self._degree
|
|
160
|
+
).make_field()
|
|
161
|
+
fem.interpolate(self.velocity_field, dest=velocity_field_lagrange)
|
|
162
|
+
else:
|
|
163
|
+
velocity_field_lagrange = self.velocity_field
|
|
164
|
+
|
|
165
|
+
self.plot.add_field("velocity", velocity_field_lagrange)
|
|
166
|
+
|
|
167
|
+
def step(self):
|
|
168
|
+
u_space = self.velocity_field.space
|
|
169
|
+
p_space = self.pressure_field.space
|
|
170
|
+
|
|
171
|
+
# Boundary condition projector and matrices
|
|
172
|
+
boundary = fem.BoundarySides(self._geo)
|
|
173
|
+
bd_test = fem.make_test(u_space, domain=boundary)
|
|
174
|
+
bd_trial = fem.make_trial(u_space, domain=boundary)
|
|
175
|
+
dirichlet_projector = fem.integrate(
|
|
176
|
+
noslip_projector_form, fields={"u": bd_test, "v": bd_trial}, nodal=True, output_dtype=float
|
|
177
|
+
)
|
|
178
|
+
fem.normalize_dirichlet_projector(dirichlet_projector)
|
|
179
|
+
|
|
180
|
+
# (Diagonal) mass matrix
|
|
181
|
+
if self._div_conforming:
|
|
182
|
+
rho_test = fem.make_test(u_space)
|
|
183
|
+
rho_trial = fem.make_trial(u_space)
|
|
184
|
+
else:
|
|
185
|
+
rho_space = fem.make_polynomial_space(geo=u_space.geometry, degree=self._degree)
|
|
186
|
+
rho_test = fem.make_test(rho_space)
|
|
187
|
+
rho_trial = fem.make_trial(rho_space)
|
|
188
|
+
|
|
189
|
+
inv_mass_matrix = fem.integrate(
|
|
190
|
+
mass_form, fields={"u": rho_trial, "v": rho_test}, nodal=True, output_dtype=float
|
|
191
|
+
)
|
|
192
|
+
fem_example_utils.invert_diagonal_bsr_matrix(inv_mass_matrix)
|
|
193
|
+
|
|
194
|
+
# Assemble divergence operator matrix
|
|
195
|
+
p_test = fem.make_test(p_space)
|
|
196
|
+
u_trial = fem.make_trial(u_space)
|
|
197
|
+
divergence_matrix = fem.integrate(
|
|
198
|
+
divergence_form,
|
|
199
|
+
fields={"u": u_trial, "psi": p_test},
|
|
200
|
+
output_dtype=float,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# need to account for discontinuities at resolution boundaries (t-junctions)
|
|
204
|
+
p_side_test = fem.make_test(p_space, domain=fem.Sides(self._geo))
|
|
205
|
+
u_side_trial = fem.make_trial(u_space, domain=fem.Sides(self._geo))
|
|
206
|
+
divergence_matrix += fem.integrate(
|
|
207
|
+
side_divergence_form,
|
|
208
|
+
fields={"u": u_side_trial, "psi": p_side_test},
|
|
209
|
+
output_dtype=float,
|
|
210
|
+
assembly="generic", # not required, for test coverage purposes
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Solve incompressibility
|
|
214
|
+
solve_incompressibility(
|
|
215
|
+
divergence_matrix,
|
|
216
|
+
dirichlet_projector,
|
|
217
|
+
inv_mass_matrix.values,
|
|
218
|
+
self.pressure_field.dof_values,
|
|
219
|
+
self.velocity_field.dof_values,
|
|
220
|
+
quiet=self._quiet,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
fem.interpolate(
|
|
224
|
+
pressure_anomaly_field,
|
|
225
|
+
dest=self.pressure_anomaly_field,
|
|
226
|
+
fields={"pressure": self.pressure_field},
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if __name__ == "__main__":
|
|
231
|
+
import argparse
|
|
232
|
+
|
|
233
|
+
wp.set_module_options({"enable_backward": False})
|
|
234
|
+
|
|
235
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
236
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
237
|
+
parser.add_argument("--resolution", type=int, default=8, help="Grid resolution.")
|
|
238
|
+
parser.add_argument("--degree", type=int, default=1, help="Polynomial degree of shape functions.")
|
|
239
|
+
parser.add_argument(
|
|
240
|
+
"--div_conforming", action="store_true", default=False, help="Use H(div)-conforming function space"
|
|
241
|
+
)
|
|
242
|
+
parser.add_argument("--level_count", type=int, default=4, help="Number of refinement levels.")
|
|
243
|
+
parser.add_argument(
|
|
244
|
+
"--headless",
|
|
245
|
+
action="store_true",
|
|
246
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
247
|
+
)
|
|
248
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
249
|
+
|
|
250
|
+
args = parser.parse_known_args()[0]
|
|
251
|
+
|
|
252
|
+
with wp.ScopedDevice(args.device):
|
|
253
|
+
example = Example(
|
|
254
|
+
quiet=args.quiet,
|
|
255
|
+
degree=args.degree,
|
|
256
|
+
div_conforming=args.div_conforming,
|
|
257
|
+
base_resolution=args.resolution,
|
|
258
|
+
level_count=args.level_count,
|
|
259
|
+
headless=args.headless,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
example.step()
|
|
263
|
+
example.render()
|
|
264
|
+
|
|
265
|
+
if not args.headless:
|
|
266
|
+
ref_geom = None
|
|
267
|
+
try:
|
|
268
|
+
from pxr import Usd, UsdGeom
|
|
269
|
+
|
|
270
|
+
stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "rocks.usd"))
|
|
271
|
+
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/rocks"))
|
|
272
|
+
points = np.array((mesh.GetPointsAttr().Get()))
|
|
273
|
+
counts = np.array((mesh.GetFaceVertexCountsAttr().Get()))
|
|
274
|
+
indices = np.array(mesh.GetFaceVertexIndicesAttr().Get())
|
|
275
|
+
ref_geom = (points, counts, indices)
|
|
276
|
+
except Exception:
|
|
277
|
+
pass
|
|
278
|
+
|
|
279
|
+
example.plot.plot(
|
|
280
|
+
{
|
|
281
|
+
"rows": 2,
|
|
282
|
+
"ref_geom": ref_geom,
|
|
283
|
+
"velocity": {"streamlines": {"density": 25, "glyph_scale": 0.01}},
|
|
284
|
+
"pressure_anomaly": {},
|
|
285
|
+
}
|
|
286
|
+
)
|
|
@@ -0,0 +1,423 @@
|
|
|
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 APIC Fluid Simulation
|
|
18
|
+
#
|
|
19
|
+
# Shows how to implement a minimalist APIC fluid simulation using a NanoVDB
|
|
20
|
+
# grid and the PicQuadrature class.
|
|
21
|
+
###########################################################################
|
|
22
|
+
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
|
|
27
|
+
import warp as wp
|
|
28
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
29
|
+
import warp.fem as fem
|
|
30
|
+
import warp.sim.render
|
|
31
|
+
from warp.fem import Domain, Field, Sample, at_node, div, grad, integrand
|
|
32
|
+
from warp.sim import Model, State
|
|
33
|
+
from warp.sparse import BsrMatrix, bsr_mm, bsr_mv, bsr_transposed
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@wp.func
|
|
37
|
+
def collision_sdf(x: wp.vec3):
|
|
38
|
+
# Arbitrary sdf representing collision geometry
|
|
39
|
+
# Here an inverted half-ball of radius 10
|
|
40
|
+
x[1] = wp.min(x[1], 0.0)
|
|
41
|
+
return 10.0 - wp.length(x), -wp.normalize(x)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@integrand
|
|
45
|
+
def integrate_fraction(s: Sample, phi: Field):
|
|
46
|
+
return phi(s)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@integrand
|
|
50
|
+
def integrate_velocity(
|
|
51
|
+
s: Sample,
|
|
52
|
+
domain: Domain,
|
|
53
|
+
u: Field,
|
|
54
|
+
velocities: wp.array(dtype=wp.vec3),
|
|
55
|
+
velocity_gradients: wp.array(dtype=wp.mat33),
|
|
56
|
+
dt: float,
|
|
57
|
+
gravity: wp.vec3,
|
|
58
|
+
):
|
|
59
|
+
"""Transfer particle velocities to grid"""
|
|
60
|
+
node_offset = domain(at_node(u, s)) - domain(s)
|
|
61
|
+
vel_apic = velocities[s.qp_index] + velocity_gradients[s.qp_index] * node_offset
|
|
62
|
+
|
|
63
|
+
vel_adv = vel_apic + dt * gravity
|
|
64
|
+
|
|
65
|
+
# if inside collider, remove normal velocity
|
|
66
|
+
sdf, sdf_gradient = collision_sdf(domain(s))
|
|
67
|
+
if sdf <= 0:
|
|
68
|
+
v_n = wp.dot(vel_adv, sdf_gradient)
|
|
69
|
+
vel_adv -= wp.max(v_n, 0.0) * sdf_gradient
|
|
70
|
+
|
|
71
|
+
return wp.dot(u(s), vel_adv)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@integrand
|
|
75
|
+
def update_particles(
|
|
76
|
+
s: Sample,
|
|
77
|
+
domain: Domain,
|
|
78
|
+
grid_vel: Field,
|
|
79
|
+
dt: float,
|
|
80
|
+
pos: wp.array(dtype=wp.vec3),
|
|
81
|
+
pos_prev: wp.array(dtype=wp.vec3),
|
|
82
|
+
vel: wp.array(dtype=wp.vec3),
|
|
83
|
+
vel_grad: wp.array(dtype=wp.mat33),
|
|
84
|
+
):
|
|
85
|
+
"""Read particle velocity from grid and advect positions"""
|
|
86
|
+
p_vel = grid_vel(s)
|
|
87
|
+
vel_grad[s.qp_index] = grad(grid_vel, s)
|
|
88
|
+
|
|
89
|
+
pos_adv = pos_prev[s.qp_index] + dt * p_vel
|
|
90
|
+
|
|
91
|
+
pos[s.qp_index] = pos_adv
|
|
92
|
+
vel[s.qp_index] = p_vel
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@integrand
|
|
96
|
+
def velocity_boundary_projector_form(s: Sample, domain: Domain, u: Field, v: Field):
|
|
97
|
+
"""Projector for velocity-Dirichlet boundary conditions"""
|
|
98
|
+
|
|
99
|
+
x = domain(s)
|
|
100
|
+
sdf, sdf_normal = collision_sdf(x)
|
|
101
|
+
|
|
102
|
+
if sdf > 0.0:
|
|
103
|
+
# Neuman
|
|
104
|
+
return 0.0
|
|
105
|
+
|
|
106
|
+
# Free-slip on boundary
|
|
107
|
+
return wp.dot(u(s), sdf_normal) * wp.dot(v(s), sdf_normal)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@integrand
|
|
111
|
+
def divergence_form(s: Sample, domain: Domain, u: Field, psi: Field):
|
|
112
|
+
# Divergence bilinear form
|
|
113
|
+
return div(u, s) * psi(s)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@wp.kernel
|
|
117
|
+
def invert_volume_kernel(values: wp.array(dtype=float)):
|
|
118
|
+
i = wp.tid()
|
|
119
|
+
m = values[i]
|
|
120
|
+
values[i] = wp.where(m == 0.0, 0.0, 1.0 / m)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@wp.kernel
|
|
124
|
+
def scalar_vector_multiply(
|
|
125
|
+
alpha: wp.array(dtype=float),
|
|
126
|
+
x: wp.array(dtype=wp.vec3),
|
|
127
|
+
y: wp.array(dtype=wp.vec3),
|
|
128
|
+
):
|
|
129
|
+
i = wp.tid()
|
|
130
|
+
y[i] = alpha[i] * x[i]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@wp.kernel
|
|
134
|
+
def scale_transposed_divergence_mat(
|
|
135
|
+
tr_divergence_mat_offsets: wp.array(dtype=int),
|
|
136
|
+
tr_divergence_mat_values: wp.array(dtype=Any),
|
|
137
|
+
inv_fraction_int: wp.array(dtype=float),
|
|
138
|
+
):
|
|
139
|
+
# In-place scaling of gradient operator rows with inverse mass
|
|
140
|
+
|
|
141
|
+
u_i = wp.tid()
|
|
142
|
+
block_beg = tr_divergence_mat_offsets[u_i]
|
|
143
|
+
block_end = tr_divergence_mat_offsets[u_i + 1]
|
|
144
|
+
|
|
145
|
+
for b in range(block_beg, block_end):
|
|
146
|
+
tr_divergence_mat_values[b] = tr_divergence_mat_values[b] * inv_fraction_int[u_i]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def solve_incompressibility(
|
|
150
|
+
divergence_mat: BsrMatrix, dirichlet_projector: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False
|
|
151
|
+
):
|
|
152
|
+
"""Solve for divergence-free velocity delta:
|
|
153
|
+
|
|
154
|
+
delta_velocity = inv_volume * transpose(divergence_mat) * pressure
|
|
155
|
+
divergence_mat * (velocity + delta_velocity) = 0
|
|
156
|
+
dirichlet_projector * delta_velocity = 0
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
# Constraint-free divergence -- computed *before* projection of divergence_mat
|
|
160
|
+
rhs = wp.empty_like(pressure)
|
|
161
|
+
bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0)
|
|
162
|
+
|
|
163
|
+
# Project matrix to enforce boundary conditions
|
|
164
|
+
# divergence_matrix -= divergence_matrix * vel_projector
|
|
165
|
+
bsr_mm(alpha=-1.0, x=divergence_mat, y=dirichlet_projector, z=divergence_mat, beta=1.0)
|
|
166
|
+
|
|
167
|
+
# Build transposed gradient matrix, scale with inverse fraction
|
|
168
|
+
transposed_divergence_mat = bsr_transposed(divergence_mat)
|
|
169
|
+
wp.launch(
|
|
170
|
+
kernel=scale_transposed_divergence_mat,
|
|
171
|
+
dim=inv_volume.shape[0],
|
|
172
|
+
inputs=[
|
|
173
|
+
transposed_divergence_mat.offsets,
|
|
174
|
+
transposed_divergence_mat.values,
|
|
175
|
+
inv_volume,
|
|
176
|
+
],
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# For simplicity, assemble Schur complement and solve with CG
|
|
180
|
+
schur = bsr_mm(divergence_mat, transposed_divergence_mat)
|
|
181
|
+
|
|
182
|
+
fem_example_utils.bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6, method="cr", max_iters=1000)
|
|
183
|
+
|
|
184
|
+
# Apply pressure to velocity
|
|
185
|
+
bsr_mv(A=transposed_divergence_mat, x=pressure, y=velocity, alpha=1.0, beta=1.0)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class Example:
|
|
189
|
+
def __init__(self, quiet=False, stage_path="example_apic_fluid.usd", voxel_size=1.0):
|
|
190
|
+
fps = 60
|
|
191
|
+
self.frame_dt = 1.0 / fps
|
|
192
|
+
self.current_frame = 0
|
|
193
|
+
|
|
194
|
+
self.sim_substeps = 1
|
|
195
|
+
self.sim_dt = self.frame_dt / self.sim_substeps
|
|
196
|
+
self.voxel_size = voxel_size
|
|
197
|
+
|
|
198
|
+
self._quiet = quiet
|
|
199
|
+
|
|
200
|
+
# particle emission
|
|
201
|
+
particle_grid_lo = wp.vec3(-5)
|
|
202
|
+
particle_grid_hi = wp.vec3(5)
|
|
203
|
+
|
|
204
|
+
grid_cell_size = voxel_size
|
|
205
|
+
grid_cell_volume = np.prod(grid_cell_size)
|
|
206
|
+
|
|
207
|
+
PARTICLES_PER_CELL_DIM = 2
|
|
208
|
+
self.radius = float(np.max(grid_cell_size) / (2 * PARTICLES_PER_CELL_DIM))
|
|
209
|
+
|
|
210
|
+
particle_grid_res = (
|
|
211
|
+
np.array((particle_grid_hi - particle_grid_lo) / voxel_size, dtype=int) * PARTICLES_PER_CELL_DIM
|
|
212
|
+
)
|
|
213
|
+
particle_grid_offset = wp.vec3(self.radius, self.radius, self.radius)
|
|
214
|
+
|
|
215
|
+
# Initialize warp.sim model, spawn particles
|
|
216
|
+
builder = wp.sim.ModelBuilder()
|
|
217
|
+
builder.add_particle_grid(
|
|
218
|
+
dim_x=particle_grid_res[0],
|
|
219
|
+
dim_y=particle_grid_res[1],
|
|
220
|
+
dim_z=particle_grid_res[2],
|
|
221
|
+
cell_x=self.radius * 2.0,
|
|
222
|
+
cell_y=self.radius * 2.0,
|
|
223
|
+
cell_z=self.radius * 2.0,
|
|
224
|
+
pos=particle_grid_lo + particle_grid_offset,
|
|
225
|
+
rot=wp.quat_identity(),
|
|
226
|
+
vel=wp.vec3(0.0, 0.0, 0.0),
|
|
227
|
+
mass=grid_cell_volume / PARTICLES_PER_CELL_DIM**3,
|
|
228
|
+
jitter=self.radius * 1.0,
|
|
229
|
+
)
|
|
230
|
+
self.model: Model = builder.finalize()
|
|
231
|
+
self.model.ground = False
|
|
232
|
+
|
|
233
|
+
# Storage for temporary variables
|
|
234
|
+
self.temporary_store = fem.TemporaryStore()
|
|
235
|
+
|
|
236
|
+
if not self._quiet:
|
|
237
|
+
print("Particle count:", self.model.particle_count)
|
|
238
|
+
|
|
239
|
+
self.state_0: State = self.model.state()
|
|
240
|
+
self.state_0.particle_qd_grad = wp.zeros(shape=(self.model.particle_count), dtype=wp.mat33)
|
|
241
|
+
|
|
242
|
+
self.state_1: State = self.model.state()
|
|
243
|
+
self.state_1.particle_qd_grad = wp.zeros(shape=(self.model.particle_count), dtype=wp.mat33)
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
if stage_path:
|
|
247
|
+
self.renderer = warp.sim.render.SimRenderer(self.model, stage_path, scaling=20.0)
|
|
248
|
+
else:
|
|
249
|
+
self.renderer = None
|
|
250
|
+
except Exception as err:
|
|
251
|
+
print(f"Could not initialize SimRenderer for stage '{stage_path}': {err}.")
|
|
252
|
+
|
|
253
|
+
def step(self):
|
|
254
|
+
fem.set_default_temporary_store(self.temporary_store)
|
|
255
|
+
|
|
256
|
+
self.current_frame = self.current_frame + 1
|
|
257
|
+
|
|
258
|
+
with wp.ScopedTimer(f"simulate frame {self.current_frame}", active=True):
|
|
259
|
+
for _s in range(self.sim_substeps):
|
|
260
|
+
# Allocate the voxels and create the warp.fem geometry
|
|
261
|
+
volume = wp.Volume.allocate_by_voxels(
|
|
262
|
+
voxel_points=self.state_0.particle_q,
|
|
263
|
+
voxel_size=self.voxel_size,
|
|
264
|
+
)
|
|
265
|
+
grid = fem.Nanogrid(volume)
|
|
266
|
+
|
|
267
|
+
# Define function spaces: linear (Q1) for velocity and volume fraction,
|
|
268
|
+
# piecewise-constant for pressure
|
|
269
|
+
linear_basis_space = fem.make_polynomial_basis_space(grid, degree=1)
|
|
270
|
+
velocity_space = fem.make_collocated_function_space(linear_basis_space, dtype=wp.vec3)
|
|
271
|
+
fraction_space = fem.make_collocated_function_space(linear_basis_space, dtype=float)
|
|
272
|
+
strain_space = fem.make_polynomial_space(
|
|
273
|
+
grid,
|
|
274
|
+
dtype=float,
|
|
275
|
+
degree=0,
|
|
276
|
+
discontinuous=True,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
pressure_field = strain_space.make_field()
|
|
280
|
+
velocity_field = velocity_space.make_field()
|
|
281
|
+
|
|
282
|
+
# Define test and trial functions and integrating linear and bilinear forms
|
|
283
|
+
domain = fem.Cells(grid)
|
|
284
|
+
velocity_test = fem.make_test(velocity_space, domain=domain)
|
|
285
|
+
velocity_trial = fem.make_trial(velocity_space, domain=domain)
|
|
286
|
+
fraction_test = fem.make_test(fraction_space, domain=domain)
|
|
287
|
+
strain_test = fem.make_test(strain_space, domain=domain)
|
|
288
|
+
|
|
289
|
+
# Build projector for Dirichlet boundary conditions
|
|
290
|
+
vel_projector = fem.integrate(
|
|
291
|
+
velocity_boundary_projector_form,
|
|
292
|
+
fields={"u": velocity_trial, "v": velocity_test},
|
|
293
|
+
nodal=True,
|
|
294
|
+
output_dtype=float,
|
|
295
|
+
)
|
|
296
|
+
fem.normalize_dirichlet_projector(vel_projector)
|
|
297
|
+
|
|
298
|
+
# Bin particles to grid cells
|
|
299
|
+
pic = fem.PicQuadrature(
|
|
300
|
+
domain=domain, positions=self.state_0.particle_q, measures=self.model.particle_mass
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# Compute inverse particle volume for each grid node
|
|
304
|
+
inv_volume = fem.integrate(
|
|
305
|
+
integrate_fraction,
|
|
306
|
+
quadrature=pic,
|
|
307
|
+
fields={"phi": fraction_test},
|
|
308
|
+
output_dtype=float,
|
|
309
|
+
)
|
|
310
|
+
wp.launch(kernel=invert_volume_kernel, dim=inv_volume.shape, inputs=[inv_volume])
|
|
311
|
+
|
|
312
|
+
# Velocity right-hand side
|
|
313
|
+
velocity_int = fem.integrate(
|
|
314
|
+
integrate_velocity,
|
|
315
|
+
quadrature=pic,
|
|
316
|
+
fields={"u": velocity_test},
|
|
317
|
+
values={
|
|
318
|
+
"velocities": self.state_0.particle_qd,
|
|
319
|
+
"velocity_gradients": self.state_0.particle_qd_grad,
|
|
320
|
+
"dt": self.sim_dt,
|
|
321
|
+
"gravity": self.model.gravity,
|
|
322
|
+
},
|
|
323
|
+
output_dtype=wp.vec3,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Compute constraint-free velocity
|
|
327
|
+
wp.launch(
|
|
328
|
+
kernel=scalar_vector_multiply,
|
|
329
|
+
dim=inv_volume.shape[0],
|
|
330
|
+
inputs=[inv_volume, velocity_int, velocity_field.dof_values],
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Apply velocity boundary conditions:
|
|
334
|
+
# velocity -= vel_projector * velocity
|
|
335
|
+
bsr_mv(
|
|
336
|
+
A=vel_projector,
|
|
337
|
+
x=velocity_field.dof_values,
|
|
338
|
+
y=velocity_field.dof_values,
|
|
339
|
+
alpha=-1.0,
|
|
340
|
+
beta=1.0,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# Assemble divergence operator matrix
|
|
344
|
+
divergence_matrix = fem.integrate(
|
|
345
|
+
divergence_form,
|
|
346
|
+
quadrature=pic,
|
|
347
|
+
fields={"u": velocity_trial, "psi": strain_test},
|
|
348
|
+
output_dtype=float,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Solve unilateral incompressibility
|
|
352
|
+
solve_incompressibility(
|
|
353
|
+
divergence_matrix,
|
|
354
|
+
vel_projector,
|
|
355
|
+
inv_volume,
|
|
356
|
+
pressure_field.dof_values,
|
|
357
|
+
velocity_field.dof_values,
|
|
358
|
+
quiet=self._quiet,
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# (A)PIC advection
|
|
362
|
+
fem.interpolate(
|
|
363
|
+
update_particles,
|
|
364
|
+
quadrature=pic,
|
|
365
|
+
values={
|
|
366
|
+
"pos": self.state_1.particle_q,
|
|
367
|
+
"pos_prev": self.state_0.particle_q,
|
|
368
|
+
"vel": self.state_1.particle_qd,
|
|
369
|
+
"vel_grad": self.state_1.particle_qd_grad,
|
|
370
|
+
"dt": self.sim_dt,
|
|
371
|
+
},
|
|
372
|
+
fields={"grid_vel": velocity_field},
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# swap states
|
|
376
|
+
(self.state_0, self.state_1) = (self.state_1, self.state_0)
|
|
377
|
+
|
|
378
|
+
fem.set_default_temporary_store(None)
|
|
379
|
+
|
|
380
|
+
def render(self, is_live=False):
|
|
381
|
+
if self.renderer is None:
|
|
382
|
+
return
|
|
383
|
+
|
|
384
|
+
with wp.ScopedTimer("render", active=True):
|
|
385
|
+
time = self.current_frame * self.frame_dt
|
|
386
|
+
|
|
387
|
+
self.renderer.begin_frame(time)
|
|
388
|
+
self.renderer.render(self.state_0)
|
|
389
|
+
self.renderer.end_frame()
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
if __name__ == "__main__":
|
|
393
|
+
import argparse
|
|
394
|
+
|
|
395
|
+
wp.set_module_options({"enable_backward": False})
|
|
396
|
+
|
|
397
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
398
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
399
|
+
parser.add_argument(
|
|
400
|
+
"--stage_path",
|
|
401
|
+
type=lambda x: None if x == "None" else str(x),
|
|
402
|
+
default="example_apic_fluid.usd",
|
|
403
|
+
help="Path to the output USD file.",
|
|
404
|
+
)
|
|
405
|
+
parser.add_argument("--num_frames", type=int, default=250, help="Total number of frames.")
|
|
406
|
+
parser.add_argument("--quiet", action="store_true")
|
|
407
|
+
parser.add_argument(
|
|
408
|
+
"--voxel_size",
|
|
409
|
+
type=float,
|
|
410
|
+
default=0.25,
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
args = parser.parse_known_args()[0]
|
|
414
|
+
|
|
415
|
+
with wp.ScopedDevice(args.device):
|
|
416
|
+
example = Example(quiet=args.quiet, stage_path=args.stage_path, voxel_size=args.voxel_size)
|
|
417
|
+
|
|
418
|
+
for _ in range(args.num_frames):
|
|
419
|
+
example.step()
|
|
420
|
+
example.render()
|
|
421
|
+
|
|
422
|
+
if example.renderer:
|
|
423
|
+
example.renderer.save()
|