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,262 @@
|
|
|
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 Stokes Transfer
|
|
18
|
+
#
|
|
19
|
+
# This example computes a 2D weakly-compressible Stokes flow around
|
|
20
|
+
# a moving object, including:
|
|
21
|
+
# - defining active cells from a mask, and restricting the computation domain to those
|
|
22
|
+
# - utilizing the PicQuadrature to integrate over unstructured particles
|
|
23
|
+
###########################################################################
|
|
24
|
+
|
|
25
|
+
import math
|
|
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
|
+
from warp.fem.utils import array_axpy
|
|
33
|
+
from warp.utils import array_cast
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@fem.integrand
|
|
37
|
+
def vel_from_particles_form(s: fem.Sample, particle_vel: wp.array(dtype=wp.vec2), v: fem.Field):
|
|
38
|
+
vel = particle_vel[s.qp_index]
|
|
39
|
+
return wp.dot(vel, v(s))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@fem.integrand
|
|
43
|
+
def viscosity_form(s: fem.Sample, u: fem.Field, v: fem.Field, nu: float):
|
|
44
|
+
return nu * wp.ddot(fem.D(u, s), fem.D(v, s))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@fem.integrand
|
|
48
|
+
def mass_form(
|
|
49
|
+
s: fem.Sample,
|
|
50
|
+
u: fem.Field,
|
|
51
|
+
v: fem.Field,
|
|
52
|
+
):
|
|
53
|
+
return wp.dot(u(s), v(s))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@fem.integrand
|
|
57
|
+
def scalar_mass_form(
|
|
58
|
+
s: fem.Sample,
|
|
59
|
+
p: fem.Field,
|
|
60
|
+
q: fem.Field,
|
|
61
|
+
):
|
|
62
|
+
return p(s) * q(s)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@fem.integrand
|
|
66
|
+
def div_form(
|
|
67
|
+
s: fem.Sample,
|
|
68
|
+
u: fem.Field,
|
|
69
|
+
q: fem.Field,
|
|
70
|
+
):
|
|
71
|
+
return q(s) * fem.div(u, s)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@fem.integrand
|
|
75
|
+
def cell_activity(s: fem.Sample, domain: fem.Domain, c1: wp.vec2, c2: wp.vec2, radius: float):
|
|
76
|
+
pos = domain(s)
|
|
77
|
+
if wp.length(pos - c1) < radius:
|
|
78
|
+
return 0.0
|
|
79
|
+
if wp.length(pos - c2) < radius:
|
|
80
|
+
return 0.0
|
|
81
|
+
return 1.0
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@wp.kernel
|
|
85
|
+
def inverse_array_kernel(m: wp.array(dtype=wp.float64)):
|
|
86
|
+
m[wp.tid()] = wp.float64(1.0) / m[wp.tid()]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Example:
|
|
90
|
+
def __init__(self, quiet=False, resolution=50):
|
|
91
|
+
self._quiet = quiet
|
|
92
|
+
|
|
93
|
+
self.res = resolution
|
|
94
|
+
self.cell_size = 1.0 / self.res
|
|
95
|
+
|
|
96
|
+
self.vel = 1.0
|
|
97
|
+
self.viscosity = 100.0
|
|
98
|
+
self.compliance = 0.01
|
|
99
|
+
self.bd_strength = 100000.0
|
|
100
|
+
|
|
101
|
+
geo = fem.Grid2D(res=wp.vec2i(self.res))
|
|
102
|
+
|
|
103
|
+
# Displacement boundary conditions are defined by two circles going in opposite directions
|
|
104
|
+
# Sample particles along those
|
|
105
|
+
circle_radius = 0.15
|
|
106
|
+
c1_center = wp.vec2(0.25, 0.5)
|
|
107
|
+
c2_center = wp.vec2(0.75, 0.5)
|
|
108
|
+
particles, particle_areas, particle_velocities = self._gen_particles(circle_radius, c1_center, c2_center)
|
|
109
|
+
|
|
110
|
+
# Disable cells that are interior to the circles
|
|
111
|
+
cell_space = fem.make_polynomial_space(geo, degree=0)
|
|
112
|
+
activity = cell_space.make_field()
|
|
113
|
+
fem.interpolate(
|
|
114
|
+
cell_activity,
|
|
115
|
+
dest=activity,
|
|
116
|
+
values={"c1": c1_center, "c2": c2_center, "radius": circle_radius - self.cell_size},
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Explicitly define the active geometry partition from those cells
|
|
120
|
+
self._active_partition = fem.ExplicitGeometryPartition(geo, wp.array(activity.dof_values.numpy(), dtype=int))
|
|
121
|
+
if not self._quiet:
|
|
122
|
+
print("Active cells:", self._active_partition.cell_count())
|
|
123
|
+
|
|
124
|
+
# Function spaces -- Q1 for vel, Q0 for pressure
|
|
125
|
+
u_space = fem.make_polynomial_space(geo, degree=1, dtype=wp.vec2)
|
|
126
|
+
p_space = fem.make_polynomial_space(geo, degree=0)
|
|
127
|
+
|
|
128
|
+
self._active_space_partition = fem.make_space_partition(
|
|
129
|
+
space=u_space, geometry_partition=self._active_partition
|
|
130
|
+
)
|
|
131
|
+
self._active_p_space_partition = fem.make_space_partition(
|
|
132
|
+
space=p_space, geometry_partition=self._active_partition
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
self._u_field = u_space.make_field()
|
|
136
|
+
self._p_field = p_space.make_field()
|
|
137
|
+
|
|
138
|
+
# Particle-based quadrature rule over active cells
|
|
139
|
+
domain = fem.Cells(geometry=self._active_partition)
|
|
140
|
+
self._pic_quadrature = fem.PicQuadrature(domain, particles, particle_areas)
|
|
141
|
+
self._particle_velocities = particle_velocities
|
|
142
|
+
|
|
143
|
+
self.renderer = fem_example_utils.Plot()
|
|
144
|
+
|
|
145
|
+
def step(self):
|
|
146
|
+
u_space = self._u_field.space
|
|
147
|
+
p_space = self._p_field.space
|
|
148
|
+
|
|
149
|
+
# Weakly-enforced boundary condition on particles
|
|
150
|
+
u_test = fem.make_test(space=u_space, space_partition=self._active_space_partition)
|
|
151
|
+
u_trial = fem.make_trial(space=u_space, space_partition=self._active_space_partition)
|
|
152
|
+
|
|
153
|
+
u_rhs = fem.integrate(
|
|
154
|
+
vel_from_particles_form,
|
|
155
|
+
quadrature=self._pic_quadrature,
|
|
156
|
+
fields={"v": u_test},
|
|
157
|
+
values={"particle_vel": self._particle_velocities},
|
|
158
|
+
output_dtype=wp.vec2d,
|
|
159
|
+
)
|
|
160
|
+
u_bd_matrix = fem.integrate(mass_form, quadrature=self._pic_quadrature, fields={"u": u_trial, "v": u_test})
|
|
161
|
+
|
|
162
|
+
# Viscosity
|
|
163
|
+
u_visc_matrix = fem.integrate(
|
|
164
|
+
viscosity_form,
|
|
165
|
+
fields={"u": u_trial, "v": u_test},
|
|
166
|
+
values={"nu": self.viscosity},
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Pressure-velocity coupling
|
|
170
|
+
p_test = fem.make_test(space=p_space, space_partition=self._active_p_space_partition)
|
|
171
|
+
p_trial = fem.make_trial(space=p_space, space_partition=self._active_p_space_partition)
|
|
172
|
+
|
|
173
|
+
div_matrix = fem.integrate(div_form, fields={"u": u_trial, "q": p_test})
|
|
174
|
+
inv_p_mass_matrix = fem.integrate(scalar_mass_form, fields={"p": p_trial, "q": p_test})
|
|
175
|
+
wp.launch(
|
|
176
|
+
kernel=inverse_array_kernel,
|
|
177
|
+
dim=inv_p_mass_matrix.values.shape,
|
|
178
|
+
device=inv_p_mass_matrix.values.device,
|
|
179
|
+
inputs=[inv_p_mass_matrix.values],
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Assemble linear system
|
|
183
|
+
u_matrix = u_visc_matrix
|
|
184
|
+
u_matrix += u_bd_matrix * self.bd_strength
|
|
185
|
+
|
|
186
|
+
gradient_matrix = div_matrix.transpose() @ inv_p_mass_matrix
|
|
187
|
+
u_matrix += gradient_matrix @ div_matrix / self.compliance
|
|
188
|
+
|
|
189
|
+
# scale u_rhs
|
|
190
|
+
array_axpy(u_rhs, u_rhs, alpha=0.0, beta=self.bd_strength)
|
|
191
|
+
|
|
192
|
+
# Solve for displacement
|
|
193
|
+
u_res = wp.zeros_like(u_rhs)
|
|
194
|
+
fem_example_utils.bsr_cg(u_matrix, x=u_res, b=u_rhs, quiet=self._quiet)
|
|
195
|
+
|
|
196
|
+
# Compute pressure from displacement
|
|
197
|
+
div_u = div_matrix @ u_res
|
|
198
|
+
p_res = -inv_p_mass_matrix @ div_u
|
|
199
|
+
|
|
200
|
+
# Copy to fields
|
|
201
|
+
u_nodes = wp.indexedarray(self._u_field.dof_values, indices=self._active_space_partition.space_node_indices())
|
|
202
|
+
p_nodes = wp.indexedarray(self._p_field.dof_values, indices=self._active_p_space_partition.space_node_indices())
|
|
203
|
+
|
|
204
|
+
array_cast(in_array=u_res, out_array=u_nodes)
|
|
205
|
+
array_cast(in_array=p_res, out_array=p_nodes)
|
|
206
|
+
|
|
207
|
+
def render(self):
|
|
208
|
+
self.renderer.add_field("pressure", self._p_field)
|
|
209
|
+
self.renderer.add_field("velocity", self._u_field)
|
|
210
|
+
|
|
211
|
+
def _gen_particles(self, circle_radius, c1_center, c2_center):
|
|
212
|
+
"""Generate some particles along two circles defining velocity boundary conditions"""
|
|
213
|
+
|
|
214
|
+
# Generate particles defining the transfer displacement
|
|
215
|
+
particles_per_circle = int(2.0 * math.pi * circle_radius * self.res)
|
|
216
|
+
|
|
217
|
+
angles = np.linspace(0, 2.0 * math.pi, particles_per_circle, endpoint=False)
|
|
218
|
+
|
|
219
|
+
n_particles = 2 * particles_per_circle
|
|
220
|
+
particles = np.empty((n_particles, 2), dtype=float)
|
|
221
|
+
|
|
222
|
+
particles[:particles_per_circle, 0] = c1_center[0] + circle_radius * np.cos(angles)
|
|
223
|
+
particles[:particles_per_circle, 1] = c1_center[1] + circle_radius * np.sin(angles)
|
|
224
|
+
particles[particles_per_circle:, 0] = c2_center[0] + circle_radius * np.cos(angles)
|
|
225
|
+
particles[particles_per_circle:, 1] = c2_center[1] + circle_radius * np.sin(angles)
|
|
226
|
+
|
|
227
|
+
particle_areas = np.ones(n_particles) * self.cell_size**2
|
|
228
|
+
particle_velocities = np.zeros_like(particles)
|
|
229
|
+
particle_velocities[:particles_per_circle, 0] = self.vel
|
|
230
|
+
particle_velocities[particles_per_circle:, 0] = -self.vel
|
|
231
|
+
|
|
232
|
+
particles = wp.array(particles, dtype=wp.vec2)
|
|
233
|
+
particle_areas = wp.array(particle_areas, dtype=float)
|
|
234
|
+
particle_velocities = wp.array(particle_velocities, dtype=wp.vec2)
|
|
235
|
+
|
|
236
|
+
return particles, particle_areas, particle_velocities
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
if __name__ == "__main__":
|
|
240
|
+
import argparse
|
|
241
|
+
|
|
242
|
+
wp.set_module_options({"enable_backward": False})
|
|
243
|
+
|
|
244
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
245
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
246
|
+
parser.add_argument("--resolution", type=int, default=50, help="Grid resolution.")
|
|
247
|
+
parser.add_argument(
|
|
248
|
+
"--headless",
|
|
249
|
+
action="store_true",
|
|
250
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
251
|
+
)
|
|
252
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
253
|
+
|
|
254
|
+
args = parser.parse_known_args()[0]
|
|
255
|
+
|
|
256
|
+
with wp.ScopedDevice(args.device):
|
|
257
|
+
example = Example(quiet=args.quiet, resolution=args.resolution)
|
|
258
|
+
example.step()
|
|
259
|
+
example.render()
|
|
260
|
+
|
|
261
|
+
if not args.headless:
|
|
262
|
+
example.renderer.plot(options={"velocity": {"streamlines": {}}})
|
|
@@ -0,0 +1,352 @@
|
|
|
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 Streamlines
|
|
18
|
+
#
|
|
19
|
+
# Shows how to generate 3D streamlines by tracing through a velocity field
|
|
20
|
+
# using the `warp.fem.lookup` operator.
|
|
21
|
+
# Also illustrates using `warp.fem.Subdomain` to define subsets of elements.
|
|
22
|
+
#
|
|
23
|
+
###########################################################################
|
|
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
|
+
from warp.examples.fem.example_apic_fluid import divergence_form, solve_incompressibility
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@fem.integrand
|
|
34
|
+
def classify_boundary_sides(
|
|
35
|
+
s: fem.Sample,
|
|
36
|
+
domain: fem.Domain,
|
|
37
|
+
outflow: wp.array(dtype=int),
|
|
38
|
+
freeslip: wp.array(dtype=int),
|
|
39
|
+
inflow: wp.array(dtype=int),
|
|
40
|
+
):
|
|
41
|
+
x = fem.position(domain, s)
|
|
42
|
+
n = fem.normal(domain, s)
|
|
43
|
+
|
|
44
|
+
if n[0] < -0.5:
|
|
45
|
+
# left side
|
|
46
|
+
inflow[s.qp_index] = 1
|
|
47
|
+
elif n[0] > 0.5:
|
|
48
|
+
if x[1] > 0.33 or x[2] < 0.33:
|
|
49
|
+
# right side, top
|
|
50
|
+
freeslip[s.qp_index] = 1
|
|
51
|
+
else:
|
|
52
|
+
# right side, bottom
|
|
53
|
+
outflow[s.qp_index] = 1
|
|
54
|
+
else:
|
|
55
|
+
freeslip[s.qp_index] = 1
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@fem.integrand
|
|
59
|
+
def inflow_velocity(
|
|
60
|
+
s: fem.Sample,
|
|
61
|
+
domain: fem.Domain,
|
|
62
|
+
):
|
|
63
|
+
n = fem.normal(domain, s)
|
|
64
|
+
return -n
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@fem.integrand
|
|
68
|
+
def noslip_projector_form(
|
|
69
|
+
s: fem.Sample,
|
|
70
|
+
u: fem.Field,
|
|
71
|
+
v: fem.Field,
|
|
72
|
+
):
|
|
73
|
+
return wp.dot(u(s), v(s))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@fem.integrand
|
|
77
|
+
def freeslip_projector_form(
|
|
78
|
+
s: fem.Sample,
|
|
79
|
+
domain: fem.Domain,
|
|
80
|
+
u: fem.Field,
|
|
81
|
+
v: fem.Field,
|
|
82
|
+
):
|
|
83
|
+
n = fem.normal(domain, s)
|
|
84
|
+
return wp.dot(u(s), n) * wp.dot(n, v(s))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@fem.integrand
|
|
88
|
+
def mass_form(
|
|
89
|
+
s: fem.Sample,
|
|
90
|
+
u: fem.Field,
|
|
91
|
+
v: fem.Field,
|
|
92
|
+
):
|
|
93
|
+
return wp.dot(u(s), v(s))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@fem.integrand
|
|
97
|
+
def spawn_streamlines(s: fem.Sample, domain: fem.Domain, jitter: float):
|
|
98
|
+
rng = wp.rand_init(s.qp_index)
|
|
99
|
+
random_offset = wp.vec3(wp.randf(rng), wp.randf(rng), wp.randf(rng)) - wp.vec3(0.5)
|
|
100
|
+
|
|
101
|
+
# remove jistter along normal
|
|
102
|
+
n = fem.normal(domain, s)
|
|
103
|
+
random_offset -= wp.dot(random_offset, n) * n
|
|
104
|
+
|
|
105
|
+
return domain(s) + jitter * random_offset
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@fem.integrand
|
|
109
|
+
def gen_streamlines(
|
|
110
|
+
s: fem.Sample,
|
|
111
|
+
domain: fem.Domain,
|
|
112
|
+
u: fem.Field,
|
|
113
|
+
spawn_points: wp.array(dtype=wp.vec3),
|
|
114
|
+
point_count: int,
|
|
115
|
+
dx: float,
|
|
116
|
+
pos: wp.array2d(dtype=wp.vec3),
|
|
117
|
+
speed: wp.array2d(dtype=float),
|
|
118
|
+
):
|
|
119
|
+
idx = s.qp_index
|
|
120
|
+
|
|
121
|
+
p = spawn_points[idx]
|
|
122
|
+
s = fem.lookup(domain, p)
|
|
123
|
+
for k in range(point_count):
|
|
124
|
+
v = u(s)
|
|
125
|
+
pos[idx, k] = p
|
|
126
|
+
speed[idx, k] = wp.length(v)
|
|
127
|
+
|
|
128
|
+
flow_dir = wp.normalize(v)
|
|
129
|
+
adv_p = p + flow_dir * dx
|
|
130
|
+
adv_s = fem.lookup(domain, adv_p, s)
|
|
131
|
+
|
|
132
|
+
if adv_s.element_index != fem.NULL_ELEMENT_INDEX:
|
|
133
|
+
# if the lookup result position is different from adv_p,
|
|
134
|
+
# it means we have been projected back onto the domain;
|
|
135
|
+
# align back with flow and terminate streamline
|
|
136
|
+
new_p = domain(adv_s)
|
|
137
|
+
if wp.length_sq(new_p - adv_p) > 0.000001:
|
|
138
|
+
p = p + wp.dot(new_p - p, flow_dir) * flow_dir
|
|
139
|
+
s = fem.lookup(domain, p, s)
|
|
140
|
+
dx = 0.0
|
|
141
|
+
else:
|
|
142
|
+
s = adv_s
|
|
143
|
+
p = new_p
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class Example:
|
|
147
|
+
def __init__(self, quiet=False, degree=2, resolution=16, mesh="grid", headless: bool = False):
|
|
148
|
+
self._quiet = quiet
|
|
149
|
+
self._degree = degree
|
|
150
|
+
|
|
151
|
+
self._streamline_dx = 0.5 / resolution
|
|
152
|
+
self._streamline_point_count = 4 * resolution
|
|
153
|
+
|
|
154
|
+
res = wp.vec3i(resolution)
|
|
155
|
+
|
|
156
|
+
if mesh == "tet":
|
|
157
|
+
pos, tet_vtx_indices = fem_example_utils.gen_tetmesh(
|
|
158
|
+
res=res,
|
|
159
|
+
)
|
|
160
|
+
self._geo = fem.Tetmesh(tet_vtx_indices, pos, build_bvh=True)
|
|
161
|
+
elif mesh == "nano":
|
|
162
|
+
volume = fem_example_utils.gen_volume(
|
|
163
|
+
res=res,
|
|
164
|
+
)
|
|
165
|
+
self._geo = fem.Nanogrid(volume)
|
|
166
|
+
else:
|
|
167
|
+
self._geo = fem.Grid3D(
|
|
168
|
+
res=res,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Mark sides with boundary conditions that should apply
|
|
172
|
+
boundary = fem.BoundarySides(self._geo)
|
|
173
|
+
inflow_mask = wp.zeros(shape=boundary.element_count(), dtype=int)
|
|
174
|
+
freeslip_mask = wp.zeros(shape=boundary.element_count(), dtype=int)
|
|
175
|
+
outflow_mask = wp.zeros(shape=boundary.element_count(), dtype=int)
|
|
176
|
+
|
|
177
|
+
fem.interpolate(
|
|
178
|
+
classify_boundary_sides,
|
|
179
|
+
quadrature=fem.RegularQuadrature(boundary, order=0),
|
|
180
|
+
values={"outflow": outflow_mask, "freeslip": freeslip_mask, "inflow": inflow_mask},
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
self._inflow = fem.Subdomain(boundary, element_mask=inflow_mask)
|
|
184
|
+
self._freeslip = fem.Subdomain(boundary, element_mask=freeslip_mask)
|
|
185
|
+
self._outflow = fem.Subdomain(boundary, element_mask=outflow_mask)
|
|
186
|
+
|
|
187
|
+
self.plot = fem_example_utils.Plot()
|
|
188
|
+
|
|
189
|
+
self.renderer = None
|
|
190
|
+
if not headless:
|
|
191
|
+
try:
|
|
192
|
+
self.renderer = wp.render.OpenGLRenderer(
|
|
193
|
+
camera_pos=(2.0, 0.5, 3.0),
|
|
194
|
+
camera_front=(-0.66, 0.0, -1.0),
|
|
195
|
+
draw_axis=False,
|
|
196
|
+
)
|
|
197
|
+
except Exception as err:
|
|
198
|
+
wp.utils.warn(f"Could not initialize OpenGL renderer: {err}")
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
def step(self):
|
|
202
|
+
self._generate_incompressible_flow()
|
|
203
|
+
|
|
204
|
+
# first generate spawn points for the streamlines
|
|
205
|
+
# we do this by regularly sampling the inflow boundary with a small amount of jitter
|
|
206
|
+
streamline_spawn = fem.RegularQuadrature(
|
|
207
|
+
domain=self._inflow, order=self._degree, family=fem.Polynomial.GAUSS_LEGENDRE
|
|
208
|
+
)
|
|
209
|
+
n_streamlines = streamline_spawn.total_point_count()
|
|
210
|
+
spawn_points = wp.empty(dtype=wp.vec3, shape=n_streamlines)
|
|
211
|
+
|
|
212
|
+
jitter_amount = self._streamline_dx / self._degree
|
|
213
|
+
fem.interpolate(
|
|
214
|
+
spawn_streamlines, dest=spawn_points, quadrature=streamline_spawn, values={"jitter": jitter_amount}
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# now forward-trace the velocity field to generate the streamlines
|
|
218
|
+
# here we use a fixed number of points per streamline, otherwise we would need to
|
|
219
|
+
# do a first pass to count points, then array_scan the offsets, then a second pass
|
|
220
|
+
# to populate the per-point data
|
|
221
|
+
|
|
222
|
+
point_count = self._streamline_point_count
|
|
223
|
+
points = wp.empty(dtype=wp.vec3, shape=(n_streamlines, point_count))
|
|
224
|
+
speed = wp.empty(dtype=float, shape=(n_streamlines, point_count))
|
|
225
|
+
|
|
226
|
+
fem.interpolate(
|
|
227
|
+
gen_streamlines,
|
|
228
|
+
domain=fem.Cells(self._geo),
|
|
229
|
+
dim=n_streamlines,
|
|
230
|
+
fields={"u": self.velocity_field},
|
|
231
|
+
values={
|
|
232
|
+
"spawn_points": spawn_points,
|
|
233
|
+
"point_count": self._streamline_point_count,
|
|
234
|
+
"dx": self._streamline_dx,
|
|
235
|
+
"pos": points,
|
|
236
|
+
"speed": speed,
|
|
237
|
+
},
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
self._points = points
|
|
241
|
+
self._speed = speed
|
|
242
|
+
|
|
243
|
+
def render(self):
|
|
244
|
+
# self.renderer.add_field("solution", self.pressure_field)
|
|
245
|
+
self.plot.add_field("pressure", self.pressure_field)
|
|
246
|
+
# self.plot.add_field("velocity", self.velocity_field)
|
|
247
|
+
|
|
248
|
+
if self.renderer is not None:
|
|
249
|
+
streamline_count = self._points.shape[0]
|
|
250
|
+
point_count = self._streamline_point_count
|
|
251
|
+
|
|
252
|
+
vertices = self._points.flatten().numpy()
|
|
253
|
+
|
|
254
|
+
line_offsets = np.arange(streamline_count) * point_count
|
|
255
|
+
indices_beg = np.arange(point_count - 1)[np.newaxis, :] + line_offsets[:, np.newaxis]
|
|
256
|
+
indices_end = indices_beg + 1
|
|
257
|
+
indices = np.vstack((indices_beg.flatten(), indices_end.flatten())).T.flatten()
|
|
258
|
+
|
|
259
|
+
colors = self._speed.numpy()[:, :-1].flatten()
|
|
260
|
+
colors = [wp.render.bourke_color_map(0.0, 3.0, c) for c in colors]
|
|
261
|
+
|
|
262
|
+
self.renderer.begin_frame(0)
|
|
263
|
+
self.renderer.render_line_list("streamlines", vertices, indices)
|
|
264
|
+
self.renderer.render_line_list("streamlines", vertices, indices, colors)
|
|
265
|
+
|
|
266
|
+
self.renderer.paused = True
|
|
267
|
+
self.renderer.end_frame()
|
|
268
|
+
|
|
269
|
+
def _generate_incompressible_flow(self):
|
|
270
|
+
# Function spaces for velocity and pressure (RT1 / P0)
|
|
271
|
+
u_space = fem.make_polynomial_space(
|
|
272
|
+
geo=self._geo, element_basis=fem.ElementBasis.RAVIART_THOMAS, degree=1, dtype=wp.vec3
|
|
273
|
+
)
|
|
274
|
+
p_space = fem.make_polynomial_space(geo=self._geo, degree=0, dtype=float)
|
|
275
|
+
|
|
276
|
+
self.pressure_field = p_space.make_field()
|
|
277
|
+
self.velocity_field = u_space.make_field()
|
|
278
|
+
|
|
279
|
+
# Boundary condition projector and matrices
|
|
280
|
+
inflow_test = fem.make_test(u_space, domain=self._inflow)
|
|
281
|
+
inflow_trial = fem.make_trial(u_space, domain=self._inflow)
|
|
282
|
+
dirichlet_projector = fem.integrate(
|
|
283
|
+
noslip_projector_form, fields={"u": inflow_test, "v": inflow_trial}, nodal=True, output_dtype=float
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
freeslip_test = fem.make_test(u_space, domain=self._freeslip)
|
|
287
|
+
freeslip_trial = fem.make_trial(u_space, domain=self._freeslip)
|
|
288
|
+
dirichlet_projector += fem.integrate(
|
|
289
|
+
freeslip_projector_form,
|
|
290
|
+
fields={"u": freeslip_test, "v": freeslip_trial},
|
|
291
|
+
nodal=True,
|
|
292
|
+
output_dtype=float,
|
|
293
|
+
)
|
|
294
|
+
fem.normalize_dirichlet_projector(dirichlet_projector)
|
|
295
|
+
|
|
296
|
+
# Initialize velocity field with BC
|
|
297
|
+
fem.interpolate(inflow_velocity, dest=fem.make_restriction(self.velocity_field, domain=self._inflow))
|
|
298
|
+
|
|
299
|
+
# (Diagonal) mass matrix
|
|
300
|
+
rho_test = fem.make_test(u_space)
|
|
301
|
+
rho_trial = fem.make_trial(u_space)
|
|
302
|
+
inv_mass_matrix = fem.integrate(
|
|
303
|
+
mass_form, fields={"u": rho_trial, "v": rho_test}, nodal=True, output_dtype=float
|
|
304
|
+
)
|
|
305
|
+
fem_example_utils.invert_diagonal_bsr_matrix(inv_mass_matrix)
|
|
306
|
+
|
|
307
|
+
# Assemble divergence operator matrix
|
|
308
|
+
p_test = fem.make_test(p_space)
|
|
309
|
+
u_trial = fem.make_trial(u_space)
|
|
310
|
+
divergence_matrix = fem.integrate(
|
|
311
|
+
divergence_form,
|
|
312
|
+
fields={"u": u_trial, "psi": p_test},
|
|
313
|
+
output_dtype=float,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
# Solve incompressibility
|
|
317
|
+
solve_incompressibility(
|
|
318
|
+
divergence_matrix,
|
|
319
|
+
dirichlet_projector,
|
|
320
|
+
inv_mass_matrix.values,
|
|
321
|
+
self.pressure_field.dof_values,
|
|
322
|
+
self.velocity_field.dof_values,
|
|
323
|
+
quiet=self._quiet,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
if __name__ == "__main__":
|
|
328
|
+
import argparse
|
|
329
|
+
|
|
330
|
+
wp.set_module_options({"enable_backward": False})
|
|
331
|
+
|
|
332
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
333
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
334
|
+
parser.add_argument("--resolution", type=int, default=8, help="Grid resolution.")
|
|
335
|
+
parser.add_argument("--degree", type=int, default=2, help="Polynomial degree of shape functions.")
|
|
336
|
+
parser.add_argument("--mesh", choices=("grid", "tet", "hex", "nano"), default="grid", help="Mesh type.")
|
|
337
|
+
parser.add_argument(
|
|
338
|
+
"--headless",
|
|
339
|
+
action="store_true",
|
|
340
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
341
|
+
)
|
|
342
|
+
parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
|
|
343
|
+
|
|
344
|
+
args = parser.parse_known_args()[0]
|
|
345
|
+
|
|
346
|
+
with wp.ScopedDevice(args.device):
|
|
347
|
+
example = Example(
|
|
348
|
+
quiet=args.quiet, degree=args.degree, resolution=args.resolution, mesh=args.mesh, headless=args.headless
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
example.step()
|
|
352
|
+
example.render()
|