warp-lang 1.2.2__py3-none-macosx_10_13_universal2.whl → 1.3.1__py3-none-macosx_10_13_universal2.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.
- warp/__init__.py +8 -6
- warp/autograd.py +823 -0
- warp/bin/libwarp.dylib +0 -0
- warp/build.py +6 -2
- warp/builtins.py +1412 -888
- warp/codegen.py +503 -166
- warp/config.py +48 -18
- warp/context.py +400 -198
- warp/dlpack.py +8 -0
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/benchmarks/benchmark_cloth_warp.py +1 -1
- warp/examples/benchmarks/benchmark_interop_torch.py +158 -0
- warp/examples/benchmarks/benchmark_launches.py +1 -1
- warp/examples/core/example_cupy.py +78 -0
- warp/examples/fem/example_apic_fluid.py +17 -36
- warp/examples/fem/example_burgers.py +9 -18
- warp/examples/fem/example_convection_diffusion.py +7 -17
- warp/examples/fem/example_convection_diffusion_dg.py +27 -47
- warp/examples/fem/example_deformed_geometry.py +11 -22
- warp/examples/fem/example_diffusion.py +7 -18
- warp/examples/fem/example_diffusion_3d.py +24 -28
- warp/examples/fem/example_diffusion_mgpu.py +7 -14
- warp/examples/fem/example_magnetostatics.py +190 -0
- warp/examples/fem/example_mixed_elasticity.py +111 -80
- warp/examples/fem/example_navier_stokes.py +30 -34
- warp/examples/fem/example_nonconforming_contact.py +290 -0
- warp/examples/fem/example_stokes.py +17 -32
- warp/examples/fem/example_stokes_transfer.py +12 -21
- warp/examples/fem/example_streamlines.py +350 -0
- warp/examples/fem/utils.py +936 -0
- warp/fabric.py +5 -2
- warp/fem/__init__.py +13 -3
- warp/fem/cache.py +161 -11
- warp/fem/dirichlet.py +37 -28
- warp/fem/domain.py +105 -14
- warp/fem/field/__init__.py +14 -3
- warp/fem/field/field.py +454 -11
- warp/fem/field/nodal_field.py +33 -18
- warp/fem/geometry/deformed_geometry.py +50 -15
- warp/fem/geometry/hexmesh.py +12 -24
- warp/fem/geometry/nanogrid.py +106 -31
- warp/fem/geometry/quadmesh_2d.py +6 -11
- warp/fem/geometry/tetmesh.py +103 -61
- warp/fem/geometry/trimesh_2d.py +98 -47
- warp/fem/integrate.py +231 -186
- warp/fem/operator.py +14 -9
- warp/fem/quadrature/pic_quadrature.py +35 -9
- warp/fem/quadrature/quadrature.py +119 -32
- warp/fem/space/basis_space.py +98 -22
- warp/fem/space/collocated_function_space.py +3 -1
- warp/fem/space/function_space.py +7 -2
- warp/fem/space/grid_2d_function_space.py +3 -3
- warp/fem/space/grid_3d_function_space.py +4 -4
- warp/fem/space/hexmesh_function_space.py +3 -2
- warp/fem/space/nanogrid_function_space.py +12 -14
- warp/fem/space/partition.py +45 -47
- warp/fem/space/restriction.py +19 -16
- warp/fem/space/shape/cube_shape_function.py +91 -3
- warp/fem/space/shape/shape_function.py +7 -0
- warp/fem/space/shape/square_shape_function.py +32 -0
- warp/fem/space/shape/tet_shape_function.py +11 -7
- warp/fem/space/shape/triangle_shape_function.py +10 -1
- warp/fem/space/topology.py +116 -42
- warp/fem/types.py +8 -1
- warp/fem/utils.py +301 -83
- warp/native/array.h +16 -0
- warp/native/builtin.h +0 -15
- warp/native/cuda_util.cpp +14 -6
- warp/native/exports.h +1348 -1308
- warp/native/quat.h +79 -0
- warp/native/rand.h +27 -4
- warp/native/sparse.cpp +83 -81
- warp/native/sparse.cu +381 -453
- warp/native/vec.h +64 -0
- warp/native/volume.cpp +40 -49
- warp/native/volume_builder.cu +2 -3
- warp/native/volume_builder.h +12 -17
- warp/native/warp.cu +3 -3
- warp/native/warp.h +69 -59
- warp/render/render_opengl.py +17 -9
- warp/sim/articulation.py +117 -17
- warp/sim/collide.py +35 -29
- warp/sim/model.py +123 -18
- warp/sim/render.py +3 -1
- warp/sparse.py +867 -203
- warp/stubs.py +312 -541
- warp/tape.py +29 -1
- warp/tests/disabled_kinematics.py +1 -1
- warp/tests/test_adam.py +1 -1
- warp/tests/test_arithmetic.py +1 -1
- warp/tests/test_array.py +58 -1
- warp/tests/test_array_reduce.py +1 -1
- warp/tests/test_async.py +1 -1
- warp/tests/test_atomic.py +1 -1
- warp/tests/test_bool.py +1 -1
- warp/tests/test_builtins_resolution.py +1 -1
- warp/tests/test_bvh.py +6 -1
- warp/tests/test_closest_point_edge_edge.py +1 -1
- warp/tests/test_codegen.py +91 -1
- warp/tests/test_compile_consts.py +1 -1
- warp/tests/test_conditional.py +1 -1
- warp/tests/test_copy.py +1 -1
- warp/tests/test_ctypes.py +1 -1
- warp/tests/test_dense.py +1 -1
- warp/tests/test_devices.py +1 -1
- warp/tests/test_dlpack.py +1 -1
- warp/tests/test_examples.py +33 -4
- warp/tests/test_fabricarray.py +5 -2
- warp/tests/test_fast_math.py +1 -1
- warp/tests/test_fem.py +213 -6
- warp/tests/test_fp16.py +1 -1
- warp/tests/test_func.py +1 -1
- warp/tests/test_future_annotations.py +90 -0
- warp/tests/test_generics.py +1 -1
- warp/tests/test_grad.py +1 -1
- warp/tests/test_grad_customs.py +1 -1
- warp/tests/test_grad_debug.py +247 -0
- warp/tests/test_hash_grid.py +6 -1
- warp/tests/test_implicit_init.py +354 -0
- warp/tests/test_import.py +1 -1
- warp/tests/test_indexedarray.py +1 -1
- warp/tests/test_intersect.py +1 -1
- warp/tests/test_jax.py +1 -1
- warp/tests/test_large.py +1 -1
- warp/tests/test_launch.py +1 -1
- warp/tests/test_lerp.py +1 -1
- warp/tests/test_linear_solvers.py +1 -1
- warp/tests/test_lvalue.py +1 -1
- warp/tests/test_marching_cubes.py +5 -2
- warp/tests/test_mat.py +34 -35
- warp/tests/test_mat_lite.py +2 -1
- warp/tests/test_mat_scalar_ops.py +1 -1
- warp/tests/test_math.py +1 -1
- warp/tests/test_matmul.py +20 -16
- warp/tests/test_matmul_lite.py +1 -1
- warp/tests/test_mempool.py +1 -1
- warp/tests/test_mesh.py +5 -2
- warp/tests/test_mesh_query_aabb.py +1 -1
- warp/tests/test_mesh_query_point.py +1 -1
- warp/tests/test_mesh_query_ray.py +1 -1
- warp/tests/test_mlp.py +1 -1
- warp/tests/test_model.py +1 -1
- warp/tests/test_module_hashing.py +77 -1
- warp/tests/test_modules_lite.py +1 -1
- warp/tests/test_multigpu.py +1 -1
- warp/tests/test_noise.py +1 -1
- warp/tests/test_operators.py +1 -1
- warp/tests/test_options.py +1 -1
- warp/tests/test_overwrite.py +542 -0
- warp/tests/test_peer.py +1 -1
- warp/tests/test_pinned.py +1 -1
- warp/tests/test_print.py +1 -1
- warp/tests/test_quat.py +15 -1
- warp/tests/test_rand.py +1 -1
- warp/tests/test_reload.py +1 -1
- warp/tests/test_rounding.py +1 -1
- warp/tests/test_runlength_encode.py +1 -1
- warp/tests/test_scalar_ops.py +95 -0
- warp/tests/test_sim_grad.py +1 -1
- warp/tests/test_sim_kinematics.py +1 -1
- warp/tests/test_smoothstep.py +1 -1
- warp/tests/test_sparse.py +82 -15
- warp/tests/test_spatial.py +1 -1
- warp/tests/test_special_values.py +2 -11
- warp/tests/test_streams.py +11 -1
- warp/tests/test_struct.py +1 -1
- warp/tests/test_tape.py +1 -1
- warp/tests/test_torch.py +194 -1
- warp/tests/test_transient_module.py +1 -1
- warp/tests/test_types.py +1 -1
- warp/tests/test_utils.py +1 -1
- warp/tests/test_vec.py +15 -63
- warp/tests/test_vec_lite.py +2 -1
- warp/tests/test_vec_scalar_ops.py +65 -1
- warp/tests/test_verify_fp.py +1 -1
- warp/tests/test_volume.py +28 -2
- warp/tests/test_volume_write.py +1 -1
- warp/tests/unittest_serial.py +1 -1
- warp/tests/unittest_suites.py +9 -1
- warp/tests/walkthrough_debug.py +1 -1
- warp/thirdparty/unittest_parallel.py +2 -5
- warp/torch.py +103 -41
- warp/types.py +341 -224
- warp/utils.py +11 -2
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/METADATA +99 -46
- warp_lang-1.3.1.dist-info/RECORD +368 -0
- warp/examples/fem/bsr_utils.py +0 -378
- warp/examples/fem/mesh_utils.py +0 -133
- warp/examples/fem/plot_utils.py +0 -292
- warp_lang-1.2.2.dist-info/RECORD +0 -359
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/WHEEL +0 -0
- {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/top_level.txt +0 -0
warp/dlpack.py
CHANGED
|
@@ -60,10 +60,18 @@ PyCapsule_SetName.restype = ctypes.c_int
|
|
|
60
60
|
class _DLPackTensorHolder:
|
|
61
61
|
"""Class responsible for deleting DLManagedTensor memory after ownership is transferred from a capsule."""
|
|
62
62
|
|
|
63
|
+
def __new__(cls, *args, **kwargs):
|
|
64
|
+
instance = super(_DLPackTensorHolder, cls).__new__(cls)
|
|
65
|
+
instance.mem_ptr = None
|
|
66
|
+
return instance
|
|
67
|
+
|
|
63
68
|
def __init__(self, mem_ptr):
|
|
64
69
|
self.mem_ptr = mem_ptr
|
|
65
70
|
|
|
66
71
|
def __del__(self):
|
|
72
|
+
if not self.mem_ptr:
|
|
73
|
+
return
|
|
74
|
+
|
|
67
75
|
managed_tensor = DLManagedTensor.from_address(self.mem_ptr)
|
|
68
76
|
if managed_tensor.deleter:
|
|
69
77
|
managed_tensor.deleter(self.mem_ptr)
|
warp/examples/assets/bunny.usd
CHANGED
|
Binary file
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved.
|
|
2
|
+
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
|
3
|
+
# and proprietary rights in and to this software, related documentation
|
|
4
|
+
# and any modifications thereto. Any use, reproduction, disclosure or
|
|
5
|
+
# distribution of this software and related documentation without an express
|
|
6
|
+
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
|
7
|
+
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
import torch
|
|
11
|
+
|
|
12
|
+
import warp as wp
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_simple_kernel(dtype):
|
|
16
|
+
def simple_kernel(
|
|
17
|
+
a: wp.array(dtype=dtype),
|
|
18
|
+
b: wp.array(dtype=dtype),
|
|
19
|
+
c: wp.array(dtype=dtype),
|
|
20
|
+
d: wp.array(dtype=dtype),
|
|
21
|
+
e: wp.array(dtype=dtype),
|
|
22
|
+
):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
return wp.Kernel(simple_kernel)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_from_torch(kernel, num_iters, array_size, device, warp_dtype=None):
|
|
29
|
+
warp_device = wp.get_device(device)
|
|
30
|
+
torch_device = wp.device_to_torch(warp_device)
|
|
31
|
+
|
|
32
|
+
if hasattr(warp_dtype, "_shape_"):
|
|
33
|
+
torch_shape = (array_size, *warp_dtype._shape_)
|
|
34
|
+
torch_dtype = wp.dtype_to_torch(warp_dtype._wp_scalar_type_)
|
|
35
|
+
else:
|
|
36
|
+
torch_shape = (array_size,)
|
|
37
|
+
torch_dtype = torch.float32 if warp_dtype is None else wp.dtype_to_torch(warp_dtype)
|
|
38
|
+
|
|
39
|
+
_a = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
40
|
+
_b = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
41
|
+
_c = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
42
|
+
_d = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
43
|
+
_e = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
44
|
+
|
|
45
|
+
wp.synchronize()
|
|
46
|
+
|
|
47
|
+
# profiler = Profiler(interval=0.000001)
|
|
48
|
+
# profiler.start()
|
|
49
|
+
|
|
50
|
+
t1 = time.time_ns()
|
|
51
|
+
|
|
52
|
+
for _ in range(num_iters):
|
|
53
|
+
a = wp.from_torch(_a, dtype=warp_dtype)
|
|
54
|
+
b = wp.from_torch(_b, dtype=warp_dtype)
|
|
55
|
+
c = wp.from_torch(_c, dtype=warp_dtype)
|
|
56
|
+
d = wp.from_torch(_d, dtype=warp_dtype)
|
|
57
|
+
e = wp.from_torch(_e, dtype=warp_dtype)
|
|
58
|
+
wp.launch(kernel, dim=array_size, inputs=[a, b, c, d, e])
|
|
59
|
+
|
|
60
|
+
t2 = time.time_ns()
|
|
61
|
+
print(f"{(t2 - t1) / 1_000_000 :8.0f} ms from_torch(...)")
|
|
62
|
+
|
|
63
|
+
# profiler.stop()
|
|
64
|
+
# profiler.print()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_array_ctype_from_torch(kernel, num_iters, array_size, device, warp_dtype=None):
|
|
68
|
+
warp_device = wp.get_device(device)
|
|
69
|
+
torch_device = wp.device_to_torch(warp_device)
|
|
70
|
+
|
|
71
|
+
if hasattr(warp_dtype, "_shape_"):
|
|
72
|
+
torch_shape = (array_size, *warp_dtype._shape_)
|
|
73
|
+
torch_dtype = wp.dtype_to_torch(warp_dtype._wp_scalar_type_)
|
|
74
|
+
else:
|
|
75
|
+
torch_shape = (array_size,)
|
|
76
|
+
torch_dtype = torch.float32 if warp_dtype is None else wp.dtype_to_torch(warp_dtype)
|
|
77
|
+
|
|
78
|
+
_a = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
79
|
+
_b = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
80
|
+
_c = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
81
|
+
_d = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
82
|
+
_e = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
83
|
+
|
|
84
|
+
wp.synchronize()
|
|
85
|
+
|
|
86
|
+
# profiler = Profiler(interval=0.000001)
|
|
87
|
+
# profiler.start()
|
|
88
|
+
|
|
89
|
+
t1 = time.time_ns()
|
|
90
|
+
|
|
91
|
+
for _ in range(num_iters):
|
|
92
|
+
a = wp.from_torch(_a, dtype=warp_dtype, return_ctype=True)
|
|
93
|
+
b = wp.from_torch(_b, dtype=warp_dtype, return_ctype=True)
|
|
94
|
+
c = wp.from_torch(_c, dtype=warp_dtype, return_ctype=True)
|
|
95
|
+
d = wp.from_torch(_d, dtype=warp_dtype, return_ctype=True)
|
|
96
|
+
e = wp.from_torch(_e, dtype=warp_dtype, return_ctype=True)
|
|
97
|
+
wp.launch(kernel, dim=array_size, inputs=[a, b, c, d, e])
|
|
98
|
+
|
|
99
|
+
t2 = time.time_ns()
|
|
100
|
+
print(f"{(t2 - t1) / 1_000_000 :8.0f} ms from_torch(..., return_ctype=True)")
|
|
101
|
+
|
|
102
|
+
# profiler.stop()
|
|
103
|
+
# profiler.print()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_direct_from_torch(kernel, num_iters, array_size, device, warp_dtype=None):
|
|
107
|
+
warp_device = wp.get_device(device)
|
|
108
|
+
torch_device = wp.device_to_torch(warp_device)
|
|
109
|
+
|
|
110
|
+
if hasattr(warp_dtype, "_shape_"):
|
|
111
|
+
torch_shape = (array_size, *warp_dtype._shape_)
|
|
112
|
+
torch_dtype = wp.dtype_to_torch(warp_dtype._wp_scalar_type_)
|
|
113
|
+
else:
|
|
114
|
+
torch_shape = (array_size,)
|
|
115
|
+
torch_dtype = torch.float32 if warp_dtype is None else wp.dtype_to_torch(warp_dtype)
|
|
116
|
+
|
|
117
|
+
_a = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
118
|
+
_b = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
119
|
+
_c = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
120
|
+
_d = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
121
|
+
_e = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
|
|
122
|
+
|
|
123
|
+
wp.synchronize()
|
|
124
|
+
|
|
125
|
+
# profiler = Profiler(interval=0.000001)
|
|
126
|
+
# profiler.start()
|
|
127
|
+
|
|
128
|
+
t1 = time.time_ns()
|
|
129
|
+
|
|
130
|
+
for _ in range(num_iters):
|
|
131
|
+
wp.launch(kernel, dim=array_size, inputs=[_a, _b, _c, _d, _e])
|
|
132
|
+
|
|
133
|
+
t2 = time.time_ns()
|
|
134
|
+
print(f"{(t2 - t1) / 1_000_000 :8.0f} ms direct from torch")
|
|
135
|
+
|
|
136
|
+
# profiler.stop()
|
|
137
|
+
# profiler.print()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
wp.init()
|
|
141
|
+
|
|
142
|
+
params = [
|
|
143
|
+
# (warp_dtype arg, kernel)
|
|
144
|
+
(None, create_simple_kernel(wp.float32)),
|
|
145
|
+
(wp.float32, create_simple_kernel(wp.float32)),
|
|
146
|
+
(wp.vec3f, create_simple_kernel(wp.vec3f)),
|
|
147
|
+
(wp.mat22f, create_simple_kernel(wp.mat22f)),
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
wp.load_module()
|
|
151
|
+
|
|
152
|
+
num_iters = 100000
|
|
153
|
+
|
|
154
|
+
for warp_dtype, kernel in params:
|
|
155
|
+
print(f"\ndtype={wp.context.type_str(warp_dtype)}")
|
|
156
|
+
test_from_torch(kernel, num_iters, 10, "cuda:0", warp_dtype=warp_dtype)
|
|
157
|
+
test_array_ctype_from_torch(kernel, num_iters, 10, "cuda:0", warp_dtype=warp_dtype)
|
|
158
|
+
test_direct_from_torch(kernel, num_iters, 10, "cuda:0", warp_dtype=warp_dtype)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved.
|
|
2
|
+
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
|
3
|
+
# and proprietary rights in and to this software, related documentation
|
|
4
|
+
# and any modifications thereto. Any use, reproduction, disclosure or
|
|
5
|
+
# distribution of this software and related documentation without an express
|
|
6
|
+
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
|
7
|
+
|
|
8
|
+
###########################################################################
|
|
9
|
+
# Example CuPy
|
|
10
|
+
#
|
|
11
|
+
# The example demonstrates interoperability with CuPy on CUDA devices
|
|
12
|
+
# and NumPy on CPU devices.
|
|
13
|
+
###########################################################################
|
|
14
|
+
|
|
15
|
+
import warp as wp
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@wp.kernel
|
|
19
|
+
def saxpy(x: wp.array(dtype=float), y: wp.array(dtype=float), a: float):
|
|
20
|
+
i = wp.tid()
|
|
21
|
+
y[i] = a * x[i] + y[i]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Example:
|
|
25
|
+
def __init__(self):
|
|
26
|
+
device = wp.get_device()
|
|
27
|
+
|
|
28
|
+
self.n = 10
|
|
29
|
+
self.a = 1.0
|
|
30
|
+
|
|
31
|
+
if device.is_cuda:
|
|
32
|
+
# use CuPy arrays on CUDA devices
|
|
33
|
+
import cupy as cp
|
|
34
|
+
|
|
35
|
+
print(f"Using CuPy on device {device}")
|
|
36
|
+
|
|
37
|
+
# tell CuPy to use the same device
|
|
38
|
+
with cp.cuda.Device(device.ordinal):
|
|
39
|
+
self.x = cp.arange(self.n, dtype=cp.float32)
|
|
40
|
+
self.y = cp.ones(self.n, dtype=cp.float32)
|
|
41
|
+
else:
|
|
42
|
+
# use NumPy arrays on CPU
|
|
43
|
+
import numpy as np
|
|
44
|
+
|
|
45
|
+
print("Using NumPy on CPU")
|
|
46
|
+
|
|
47
|
+
self.x = np.arange(self.n, dtype=np.float32)
|
|
48
|
+
self.y = np.ones(self.n, dtype=np.float32)
|
|
49
|
+
|
|
50
|
+
def step(self):
|
|
51
|
+
# Launch a Warp kernel on the pre-allocated arrays.
|
|
52
|
+
# When running on a CUDA device, these are CuPy arrays.
|
|
53
|
+
# When running on the CPU, these are NumPy arrays.
|
|
54
|
+
#
|
|
55
|
+
# Note that the arrays can be passed to Warp kernels directly. Under the hood,
|
|
56
|
+
# Warp uses the __cuda_array_interface__ and __array_interface__ protocols to
|
|
57
|
+
# access the data.
|
|
58
|
+
wp.launch(saxpy, dim=self.n, inputs=[self.x, self.y, self.a])
|
|
59
|
+
|
|
60
|
+
def render(self):
|
|
61
|
+
print(self.y)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
import argparse
|
|
66
|
+
|
|
67
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
68
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
69
|
+
parser.add_argument("--num_frames", type=int, default=10, help="Total number of frames.")
|
|
70
|
+
|
|
71
|
+
args = parser.parse_known_args()[0]
|
|
72
|
+
|
|
73
|
+
with wp.ScopedDevice(args.device):
|
|
74
|
+
example = Example()
|
|
75
|
+
|
|
76
|
+
for _ in range(args.num_frames):
|
|
77
|
+
example.step()
|
|
78
|
+
example.render()
|
|
@@ -15,17 +15,13 @@
|
|
|
15
15
|
import numpy as np
|
|
16
16
|
|
|
17
17
|
import warp as wp
|
|
18
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
18
19
|
import warp.fem as fem
|
|
19
20
|
import warp.sim.render
|
|
20
21
|
from warp.fem import Domain, Field, Sample, at_node, div, grad, integrand
|
|
21
22
|
from warp.sim import Model, State
|
|
22
23
|
from warp.sparse import BsrMatrix, bsr_mm, bsr_mv, bsr_transposed
|
|
23
24
|
|
|
24
|
-
try:
|
|
25
|
-
from .bsr_utils import bsr_cg
|
|
26
|
-
except ImportError:
|
|
27
|
-
from bsr_utils import bsr_cg
|
|
28
|
-
|
|
29
25
|
|
|
30
26
|
@wp.func
|
|
31
27
|
def collision_sdf(x: wp.vec3):
|
|
@@ -130,7 +126,7 @@ def scale_transposed_divergence_mat(
|
|
|
130
126
|
tr_divergence_mat_values: wp.array(dtype=wp.mat(shape=(3, 1), dtype=float)),
|
|
131
127
|
inv_fraction_int: wp.array(dtype=float),
|
|
132
128
|
):
|
|
133
|
-
# In-place scaling of gradient operator rows
|
|
129
|
+
# In-place scaling of gradient operator rows with inverse mass
|
|
134
130
|
|
|
135
131
|
u_i = wp.tid()
|
|
136
132
|
block_beg = tr_divergence_mat_offsets[u_i]
|
|
@@ -140,22 +136,24 @@ def scale_transposed_divergence_mat(
|
|
|
140
136
|
tr_divergence_mat_values[b] = tr_divergence_mat_values[b] * inv_fraction_int[u_i]
|
|
141
137
|
|
|
142
138
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
p = wp.tid()
|
|
148
|
-
pos = positions[p] / voxel_size
|
|
149
|
-
ijks[p] = wp.vec3i(int(wp.floor(pos[0])), int(wp.floor(pos[1])), int(wp.floor(pos[2])))
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False):
|
|
139
|
+
def solve_incompressibility(
|
|
140
|
+
divergence_mat: BsrMatrix, dirichlet_projector: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False
|
|
141
|
+
):
|
|
153
142
|
"""Solve for divergence-free velocity delta:
|
|
154
143
|
|
|
155
144
|
delta_velocity = inv_volume * transpose(divergence_mat) * pressure
|
|
156
145
|
divergence_mat * (velocity + delta_velocity) = 0
|
|
146
|
+
dirichlet_projector * delta_velocity = 0
|
|
157
147
|
"""
|
|
158
148
|
|
|
149
|
+
# Constraint-free divergence -- computed *before* projection of divergence_mat
|
|
150
|
+
rhs = wp.empty_like(pressure)
|
|
151
|
+
bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0)
|
|
152
|
+
|
|
153
|
+
# Project matrix to enforce boundary conditions
|
|
154
|
+
# divergence_matrix -= divergence_matrix * vel_projector
|
|
155
|
+
bsr_mm(alpha=-1.0, x=divergence_mat, y=dirichlet_projector, z=divergence_mat, beta=1.0)
|
|
156
|
+
|
|
159
157
|
# Build transposed gradient matrix, scale with inverse fraction
|
|
160
158
|
transposed_divergence_mat = bsr_transposed(divergence_mat)
|
|
161
159
|
wp.launch(
|
|
@@ -171,9 +169,7 @@ def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, vel
|
|
|
171
169
|
# For simplicity, assemble Schur complement and solve with CG
|
|
172
170
|
schur = bsr_mm(divergence_mat, transposed_divergence_mat)
|
|
173
171
|
|
|
174
|
-
rhs =
|
|
175
|
-
bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0, beta=0.0)
|
|
176
|
-
bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6)
|
|
172
|
+
fem_example_utils.bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6)
|
|
177
173
|
|
|
178
174
|
# Apply pressure to velocity
|
|
179
175
|
bsr_mv(A=transposed_divergence_mat, x=pressure, y=velocity, alpha=1.0, beta=1.0)
|
|
@@ -249,23 +245,11 @@ class Example:
|
|
|
249
245
|
|
|
250
246
|
self.current_frame = self.current_frame + 1
|
|
251
247
|
|
|
252
|
-
particle_ijk = wp.empty(self.state_0.particle_count, dtype=wp.vec3i)
|
|
253
|
-
|
|
254
248
|
with wp.ScopedTimer(f"simulate frame {self.current_frame}", active=True):
|
|
255
249
|
for _s in range(self.sim_substeps):
|
|
256
|
-
# Compute the voxel coordinates for each particle.
|
|
257
|
-
# `Volume.allocate_by_voxels` accepts world positions, but allocates
|
|
258
|
-
# the voxels with the closest origin rather than the enclosing ones
|
|
259
|
-
# (i.e, it "round"s the positions, while here we eant to "floor" it)
|
|
260
|
-
wp.launch(
|
|
261
|
-
compute_particle_ijk,
|
|
262
|
-
dim=particle_ijk.shape,
|
|
263
|
-
inputs=[self.state_0.particle_q, self.voxel_size, particle_ijk],
|
|
264
|
-
)
|
|
265
|
-
|
|
266
250
|
# Allocate the voxels and create the warp.fem geometry
|
|
267
251
|
volume = wp.Volume.allocate_by_voxels(
|
|
268
|
-
voxel_points=
|
|
252
|
+
voxel_points=self.state_0.particle_q,
|
|
269
253
|
voxel_size=self.voxel_size,
|
|
270
254
|
)
|
|
271
255
|
grid = fem.Nanogrid(volume)
|
|
@@ -354,13 +338,10 @@ class Example:
|
|
|
354
338
|
output_dtype=float,
|
|
355
339
|
)
|
|
356
340
|
|
|
357
|
-
# Project matrix to enforce boundary conditions
|
|
358
|
-
# divergence_matrix -= divergence_matrix * vel_projector
|
|
359
|
-
bsr_mm(alpha=-1.0, x=divergence_matrix, y=vel_projector, z=divergence_matrix, beta=1.0)
|
|
360
|
-
|
|
361
341
|
# Solve unilateral incompressibility
|
|
362
342
|
solve_incompressibility(
|
|
363
343
|
divergence_matrix,
|
|
344
|
+
vel_projector,
|
|
364
345
|
inv_volume,
|
|
365
346
|
pressure_field.dof_values,
|
|
366
347
|
velocity_field.dof_values,
|
|
@@ -16,17 +16,8 @@
|
|
|
16
16
|
###########################################################################
|
|
17
17
|
|
|
18
18
|
import warp as wp
|
|
19
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
19
20
|
import warp.fem as fem
|
|
20
|
-
import warp.sparse as sp
|
|
21
|
-
|
|
22
|
-
# Import example utilities
|
|
23
|
-
# Make sure that works both when imported as module and run as standalone file
|
|
24
|
-
try:
|
|
25
|
-
from .bsr_utils import invert_diagonal_bsr_mass_matrix
|
|
26
|
-
from .plot_utils import Plot
|
|
27
|
-
except ImportError:
|
|
28
|
-
from bsr_utils import invert_diagonal_bsr_mass_matrix
|
|
29
|
-
from plot_utils import Plot
|
|
30
21
|
|
|
31
22
|
|
|
32
23
|
@fem.integrand
|
|
@@ -97,7 +88,7 @@ def slope_limiter(domain: fem.Domain, s: fem.Sample, u: fem.Field, dx: wp.vec2):
|
|
|
97
88
|
# Assumes regular grid topology
|
|
98
89
|
|
|
99
90
|
center_coords = fem.Coords(0.5, 0.5, 0.0)
|
|
100
|
-
cell_center = fem.
|
|
91
|
+
cell_center = fem.make_free_sample(s.element_index, center_coords)
|
|
101
92
|
center_pos = domain(cell_center)
|
|
102
93
|
|
|
103
94
|
u_center = u(cell_center)
|
|
@@ -149,19 +140,19 @@ class Example:
|
|
|
149
140
|
matrix_inertia = fem.integrate(
|
|
150
141
|
vel_mass_form, fields={"u": trial, "v": self._test}, output_dtype=wp.float32, nodal=True
|
|
151
142
|
)
|
|
152
|
-
self._inv_mass_matrix =
|
|
153
|
-
|
|
143
|
+
self._inv_mass_matrix = wp.sparse.bsr_copy(matrix_inertia)
|
|
144
|
+
fem_example_utils.invert_diagonal_bsr_matrix(self._inv_mass_matrix)
|
|
154
145
|
|
|
155
146
|
# Initial condition
|
|
156
147
|
self.velocity_field = vector_space.make_field()
|
|
157
148
|
fem.interpolate(initial_condition, dest=self.velocity_field)
|
|
158
149
|
|
|
159
|
-
# Velocity
|
|
150
|
+
# Velocity norm field -- for visualization purposes
|
|
160
151
|
self.velocity_norm_field = scalar_space.make_field()
|
|
161
152
|
fem.interpolate(velocity_norm, dest=self.velocity_norm_field, fields={"u": self.velocity_field})
|
|
162
153
|
|
|
163
|
-
self.renderer = Plot()
|
|
164
|
-
self.renderer.
|
|
154
|
+
self.renderer = fem_example_utils.Plot()
|
|
155
|
+
self.renderer.add_field("u_norm", self.velocity_norm_field)
|
|
165
156
|
|
|
166
157
|
def _velocity_delta(self, trial_velocity):
|
|
167
158
|
# Integration on sides
|
|
@@ -186,7 +177,7 @@ class Example:
|
|
|
186
177
|
alpha=1.0,
|
|
187
178
|
beta=1.0,
|
|
188
179
|
)
|
|
189
|
-
return
|
|
180
|
+
return self._inv_mass_matrix @ rhs
|
|
190
181
|
|
|
191
182
|
def step(self):
|
|
192
183
|
self.current_frame += 1
|
|
@@ -223,7 +214,7 @@ class Example:
|
|
|
223
214
|
|
|
224
215
|
def render(self):
|
|
225
216
|
self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
|
|
226
|
-
self.renderer.
|
|
217
|
+
self.renderer.add_field("u_norm", self.velocity_norm_field)
|
|
227
218
|
self.renderer.end_frame()
|
|
228
219
|
|
|
229
220
|
|
|
@@ -15,19 +15,9 @@
|
|
|
15
15
|
###########################################################################
|
|
16
16
|
|
|
17
17
|
import warp as wp
|
|
18
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
18
19
|
import warp.fem as fem
|
|
19
20
|
|
|
20
|
-
# Import example utilities
|
|
21
|
-
# Make sure that works both when imported as module and run as standalone file
|
|
22
|
-
try:
|
|
23
|
-
from .bsr_utils import bsr_cg
|
|
24
|
-
from .mesh_utils import gen_trimesh
|
|
25
|
-
from .plot_utils import Plot
|
|
26
|
-
except ImportError:
|
|
27
|
-
from bsr_utils import bsr_cg
|
|
28
|
-
from mesh_utils import gen_trimesh
|
|
29
|
-
from plot_utils import Plot
|
|
30
|
-
|
|
31
21
|
|
|
32
22
|
@fem.integrand
|
|
33
23
|
def initial_condition(domain: fem.Domain, s: fem.Sample):
|
|
@@ -94,8 +84,8 @@ class Example:
|
|
|
94
84
|
self.current_frame = 0
|
|
95
85
|
|
|
96
86
|
if tri_mesh:
|
|
97
|
-
positions, tri_vidx = gen_trimesh(res=wp.vec2i(res))
|
|
98
|
-
geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
87
|
+
positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(res))
|
|
88
|
+
geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions, build_bvh=True)
|
|
99
89
|
else:
|
|
100
90
|
geo = fem.Grid2D(res=wp.vec2i(res))
|
|
101
91
|
|
|
@@ -116,8 +106,8 @@ class Example:
|
|
|
116
106
|
output_dtype=float,
|
|
117
107
|
)
|
|
118
108
|
|
|
119
|
-
self.renderer = Plot()
|
|
120
|
-
self.renderer.
|
|
109
|
+
self.renderer = fem_example_utils.Plot()
|
|
110
|
+
self.renderer.add_field("phi", self._phi_field)
|
|
121
111
|
|
|
122
112
|
def step(self):
|
|
123
113
|
self.current_frame += 1
|
|
@@ -131,11 +121,11 @@ class Example:
|
|
|
131
121
|
)
|
|
132
122
|
|
|
133
123
|
# Solve linear system
|
|
134
|
-
bsr_cg(self._matrix, x=self._phi_field.dof_values, b=rhs, quiet=self._quiet, tol=1.0e-12)
|
|
124
|
+
fem_example_utils.bsr_cg(self._matrix, x=self._phi_field.dof_values, b=rhs, quiet=self._quiet, tol=1.0e-12)
|
|
135
125
|
|
|
136
126
|
def render(self):
|
|
137
127
|
self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
|
|
138
|
-
self.renderer.
|
|
128
|
+
self.renderer.add_field("phi", self._phi_field)
|
|
139
129
|
self.renderer.end_frame()
|
|
140
130
|
|
|
141
131
|
|
|
@@ -15,31 +15,14 @@
|
|
|
15
15
|
###########################################################################
|
|
16
16
|
|
|
17
17
|
import warp as wp
|
|
18
|
+
import warp.examples.fem.utils as fem_example_utils
|
|
18
19
|
import warp.fem as fem
|
|
19
|
-
from warp.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
from .example_convection_diffusion import (
|
|
26
|
-
diffusion_form,
|
|
27
|
-
inertia_form,
|
|
28
|
-
initial_condition,
|
|
29
|
-
velocity,
|
|
30
|
-
)
|
|
31
|
-
from .mesh_utils import gen_quadmesh, gen_trimesh
|
|
32
|
-
from .plot_utils import Plot
|
|
33
|
-
except ImportError:
|
|
34
|
-
from bsr_utils import bsr_cg
|
|
35
|
-
from example_convection_diffusion import (
|
|
36
|
-
diffusion_form,
|
|
37
|
-
inertia_form,
|
|
38
|
-
initial_condition,
|
|
39
|
-
velocity,
|
|
40
|
-
)
|
|
41
|
-
from mesh_utils import gen_quadmesh, gen_trimesh
|
|
42
|
-
from plot_utils import Plot
|
|
20
|
+
from warp.examples.fem.example_convection_diffusion import (
|
|
21
|
+
diffusion_form,
|
|
22
|
+
inertia_form,
|
|
23
|
+
initial_condition,
|
|
24
|
+
velocity,
|
|
25
|
+
)
|
|
43
26
|
|
|
44
27
|
|
|
45
28
|
# Standard transport term, on cells' interior
|
|
@@ -58,6 +41,10 @@ def upwind_transport_form(s: fem.Sample, domain: fem.Domain, phi: fem.Field, psi
|
|
|
58
41
|
vel = velocity(pos, ang_vel)
|
|
59
42
|
vel_n = wp.dot(vel, fem.normal(domain, s))
|
|
60
43
|
|
|
44
|
+
if wp.min(pos) <= 0.0 or wp.max(pos) >= 1.0: # boundary side
|
|
45
|
+
return phi(s) * (-psi(s) * vel_n + 0.5 * psi(s) * wp.abs(vel_n))
|
|
46
|
+
|
|
47
|
+
# interior side
|
|
61
48
|
return fem.jump(phi, s) * (-fem.average(psi, s) * vel_n + 0.5 * fem.jump(psi, s) * wp.abs(vel_n))
|
|
62
49
|
|
|
63
50
|
|
|
@@ -79,7 +66,7 @@ def sip_diffusion_form(
|
|
|
79
66
|
|
|
80
67
|
|
|
81
68
|
class Example:
|
|
82
|
-
def __init__(self, quiet=False, degree=2, resolution=50, mesh="grid", viscosity=0.
|
|
69
|
+
def __init__(self, quiet=False, degree=2, resolution=50, mesh="grid", viscosity=0.0001, ang_vel=1.0):
|
|
83
70
|
self._quiet = quiet
|
|
84
71
|
|
|
85
72
|
res = resolution
|
|
@@ -87,10 +74,10 @@ class Example:
|
|
|
87
74
|
self.current_frame = 0
|
|
88
75
|
|
|
89
76
|
if mesh == "tri":
|
|
90
|
-
positions, tri_vidx = gen_trimesh(res=wp.vec2i(resolution))
|
|
77
|
+
positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(resolution))
|
|
91
78
|
geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
|
|
92
79
|
elif mesh == "quad":
|
|
93
|
-
positions, quad_vidx = gen_quadmesh(res=wp.vec2i(resolution))
|
|
80
|
+
positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
|
|
94
81
|
geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
|
|
95
82
|
else:
|
|
96
83
|
geo = fem.Grid2D(res=wp.vec2i(resolution))
|
|
@@ -124,37 +111,30 @@ class Example:
|
|
|
124
111
|
side_test = fem.make_test(space=scalar_space, domain=sides)
|
|
125
112
|
side_trial = fem.make_trial(space=scalar_space, domain=sides)
|
|
126
113
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
values={"ang_vel": ang_vel},
|
|
132
|
-
),
|
|
133
|
-
y=matrix_transport,
|
|
114
|
+
matrix_transport += fem.integrate(
|
|
115
|
+
upwind_transport_form,
|
|
116
|
+
fields={"phi": side_trial, "psi": side_test},
|
|
117
|
+
values={"ang_vel": ang_vel},
|
|
134
118
|
)
|
|
135
119
|
|
|
136
120
|
matrix_diffusion = fem.integrate(
|
|
137
121
|
diffusion_form,
|
|
138
122
|
fields={"u": trial, "v": self._test},
|
|
139
123
|
)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
),
|
|
145
|
-
y=matrix_diffusion,
|
|
124
|
+
|
|
125
|
+
matrix_diffusion += fem.integrate(
|
|
126
|
+
sip_diffusion_form,
|
|
127
|
+
fields={"phi": side_trial, "psi": side_test},
|
|
146
128
|
)
|
|
147
129
|
|
|
148
|
-
self._matrix = matrix_inertia
|
|
149
|
-
bsr_axpy(x=matrix_transport, y=self._matrix)
|
|
150
|
-
bsr_axpy(x=matrix_diffusion, y=self._matrix, alpha=viscosity)
|
|
130
|
+
self._matrix = matrix_inertia + matrix_transport + viscosity * matrix_diffusion
|
|
151
131
|
|
|
152
132
|
# Initial condition
|
|
153
133
|
self._phi_field = scalar_space.make_field()
|
|
154
134
|
fem.interpolate(initial_condition, dest=self._phi_field)
|
|
155
135
|
|
|
156
|
-
self.renderer = Plot()
|
|
157
|
-
self.renderer.
|
|
136
|
+
self.renderer = fem_example_utils.Plot()
|
|
137
|
+
self.renderer.add_field("phi", self._phi_field)
|
|
158
138
|
|
|
159
139
|
def step(self):
|
|
160
140
|
self.current_frame += 1
|
|
@@ -166,13 +146,13 @@ class Example:
|
|
|
166
146
|
)
|
|
167
147
|
|
|
168
148
|
phi = wp.zeros_like(rhs)
|
|
169
|
-
bsr_cg(self._matrix, b=rhs, x=phi, method="bicgstab", quiet=self._quiet)
|
|
149
|
+
fem_example_utils.bsr_cg(self._matrix, b=rhs, x=phi, method="bicgstab", quiet=self._quiet)
|
|
170
150
|
|
|
171
151
|
wp.utils.array_cast(in_array=phi, out_array=self._phi_field.dof_values)
|
|
172
152
|
|
|
173
153
|
def render(self):
|
|
174
154
|
self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
|
|
175
|
-
self.renderer.
|
|
155
|
+
self.renderer.add_field("phi", self._phi_field)
|
|
176
156
|
self.renderer.end_frame()
|
|
177
157
|
|
|
178
158
|
|