warp-lang 0.11.0__py3-none-manylinux2014_x86_64.whl → 1.0.0__py3-none-manylinux2014_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 +8 -0
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +7 -6
- warp/build_dll.py +70 -79
- warp/builtins.py +10 -6
- warp/codegen.py +51 -19
- warp/config.py +7 -8
- warp/constants.py +3 -0
- warp/context.py +948 -245
- warp/dlpack.py +198 -113
- 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.usda +42 -0
- warp/examples/assets/nv_ant.xml +92 -0
- warp/examples/assets/nv_humanoid.xml +183 -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.usda +56 -0
- warp/examples/assets/torus.usda +105 -0
- warp/examples/benchmarks/benchmark_api.py +383 -0
- warp/examples/benchmarks/benchmark_cloth.py +279 -0
- warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -0
- warp/examples/benchmarks/benchmark_cloth_jax.py +100 -0
- warp/examples/benchmarks/benchmark_cloth_numba.py +142 -0
- warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -0
- warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -0
- warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -0
- warp/examples/benchmarks/benchmark_cloth_warp.py +146 -0
- warp/examples/benchmarks/benchmark_launches.py +295 -0
- warp/examples/core/example_dem.py +221 -0
- warp/examples/core/example_fluid.py +267 -0
- warp/examples/core/example_graph_capture.py +129 -0
- warp/examples/core/example_marching_cubes.py +177 -0
- warp/examples/core/example_mesh.py +154 -0
- warp/examples/core/example_mesh_intersect.py +193 -0
- warp/examples/core/example_nvdb.py +169 -0
- warp/examples/core/example_raycast.py +89 -0
- warp/examples/core/example_raymarch.py +178 -0
- warp/examples/core/example_render_opengl.py +141 -0
- warp/examples/core/example_sph.py +389 -0
- warp/examples/core/example_torch.py +181 -0
- warp/examples/core/example_wave.py +249 -0
- warp/examples/fem/bsr_utils.py +380 -0
- warp/examples/fem/example_apic_fluid.py +391 -0
- warp/examples/fem/example_convection_diffusion.py +168 -0
- warp/examples/fem/example_convection_diffusion_dg.py +209 -0
- warp/examples/fem/example_convection_diffusion_dg0.py +194 -0
- warp/examples/fem/example_deformed_geometry.py +159 -0
- warp/examples/fem/example_diffusion.py +173 -0
- warp/examples/fem/example_diffusion_3d.py +152 -0
- warp/examples/fem/example_diffusion_mgpu.py +214 -0
- warp/examples/fem/example_mixed_elasticity.py +222 -0
- warp/examples/fem/example_navier_stokes.py +243 -0
- warp/examples/fem/example_stokes.py +192 -0
- warp/examples/fem/example_stokes_transfer.py +249 -0
- warp/examples/fem/mesh_utils.py +109 -0
- warp/examples/fem/plot_utils.py +287 -0
- warp/examples/optim/example_bounce.py +248 -0
- warp/examples/optim/example_cloth_throw.py +210 -0
- warp/examples/optim/example_diffray.py +535 -0
- warp/examples/optim/example_drone.py +850 -0
- warp/examples/optim/example_inverse_kinematics.py +169 -0
- warp/examples/optim/example_inverse_kinematics_torch.py +170 -0
- warp/examples/optim/example_spring_cage.py +234 -0
- warp/examples/optim/example_trajectory.py +201 -0
- warp/examples/sim/example_cartpole.py +128 -0
- warp/examples/sim/example_cloth.py +184 -0
- warp/examples/sim/example_granular.py +113 -0
- warp/examples/sim/example_granular_collision_sdf.py +185 -0
- warp/examples/sim/example_jacobian_ik.py +213 -0
- warp/examples/sim/example_particle_chain.py +106 -0
- warp/examples/sim/example_quadruped.py +179 -0
- warp/examples/sim/example_rigid_chain.py +191 -0
- warp/examples/sim/example_rigid_contact.py +176 -0
- warp/examples/sim/example_rigid_force.py +126 -0
- warp/examples/sim/example_rigid_gyroscopic.py +97 -0
- warp/examples/sim/example_rigid_soft_contact.py +124 -0
- warp/examples/sim/example_soft_body.py +178 -0
- warp/fabric.py +29 -20
- warp/fem/cache.py +0 -1
- warp/fem/dirichlet.py +0 -2
- warp/fem/integrate.py +0 -1
- warp/jax.py +45 -0
- warp/jax_experimental.py +339 -0
- warp/native/builtin.h +12 -0
- warp/native/bvh.cu +18 -18
- warp/native/clang/clang.cpp +8 -3
- warp/native/cuda_util.cpp +94 -5
- warp/native/cuda_util.h +35 -6
- warp/native/cutlass_gemm.cpp +1 -1
- warp/native/cutlass_gemm.cu +4 -1
- warp/native/error.cpp +66 -0
- warp/native/error.h +27 -0
- warp/native/mesh.cu +2 -2
- warp/native/reduce.cu +4 -4
- warp/native/runlength_encode.cu +2 -2
- warp/native/scan.cu +2 -2
- warp/native/sparse.cu +0 -1
- warp/native/temp_buffer.h +2 -2
- warp/native/warp.cpp +95 -60
- warp/native/warp.cu +1053 -218
- warp/native/warp.h +49 -32
- warp/optim/linear.py +33 -16
- warp/render/render_opengl.py +202 -101
- warp/render/render_usd.py +82 -40
- warp/sim/__init__.py +13 -4
- warp/sim/articulation.py +4 -5
- warp/sim/collide.py +320 -175
- warp/sim/import_mjcf.py +25 -30
- warp/sim/import_urdf.py +94 -63
- warp/sim/import_usd.py +51 -36
- warp/sim/inertia.py +3 -2
- warp/sim/integrator.py +233 -0
- warp/sim/integrator_euler.py +447 -469
- warp/sim/integrator_featherstone.py +1991 -0
- warp/sim/integrator_xpbd.py +1420 -640
- warp/sim/model.py +765 -487
- warp/sim/particles.py +2 -1
- warp/sim/render.py +35 -13
- warp/sim/utils.py +222 -11
- warp/stubs.py +8 -0
- warp/tape.py +16 -1
- warp/tests/aux_test_grad_customs.py +23 -0
- warp/tests/test_array.py +190 -1
- warp/tests/test_async.py +656 -0
- warp/tests/test_bool.py +50 -0
- warp/tests/test_dlpack.py +164 -11
- warp/tests/test_examples.py +166 -74
- warp/tests/test_fem.py +8 -1
- warp/tests/test_generics.py +15 -5
- warp/tests/test_grad.py +1 -1
- warp/tests/test_grad_customs.py +172 -12
- warp/tests/test_jax.py +254 -0
- warp/tests/test_large.py +29 -6
- warp/tests/test_launch.py +25 -0
- warp/tests/test_linear_solvers.py +20 -3
- warp/tests/test_matmul.py +61 -16
- warp/tests/test_matmul_lite.py +13 -13
- warp/tests/test_mempool.py +186 -0
- warp/tests/test_multigpu.py +3 -0
- warp/tests/test_options.py +16 -2
- warp/tests/test_peer.py +137 -0
- warp/tests/test_print.py +3 -1
- warp/tests/test_quat.py +23 -0
- warp/tests/test_sim_kinematics.py +97 -0
- warp/tests/test_snippet.py +126 -3
- warp/tests/test_streams.py +108 -79
- warp/tests/test_torch.py +16 -8
- warp/tests/test_utils.py +32 -27
- warp/tests/test_verify_fp.py +65 -0
- warp/tests/test_volume.py +1 -1
- warp/tests/unittest_serial.py +2 -0
- warp/tests/unittest_suites.py +12 -0
- warp/tests/unittest_utils.py +14 -7
- warp/thirdparty/unittest_parallel.py +15 -3
- warp/torch.py +10 -8
- warp/types.py +363 -246
- warp/utils.py +143 -19
- warp_lang-1.0.0.dist-info/LICENSE.md +126 -0
- warp_lang-1.0.0.dist-info/METADATA +394 -0
- {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +167 -86
- warp/sim/optimizer.py +0 -138
- warp_lang-0.11.0.dist-info/LICENSE.md +0 -36
- warp_lang-0.11.0.dist-info/METADATA +0 -238
- /warp/tests/{walkthough_debug.py → walkthrough_debug.py} +0 -0
- {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
- {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Copyright (c) 2022 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 Sim Rigid Kinematics
|
|
10
|
+
#
|
|
11
|
+
# Tests rigid body forward and backwards kinematics through the
|
|
12
|
+
# wp.sim.eval_ik() and wp.sim.eval_fk() methods.
|
|
13
|
+
#
|
|
14
|
+
###########################################################################
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
import warp as wp
|
|
21
|
+
import warp.sim
|
|
22
|
+
import warp.sim.render
|
|
23
|
+
|
|
24
|
+
wp.init()
|
|
25
|
+
|
|
26
|
+
TARGET = wp.constant(wp.vec3(2.0, 1.0, 0.0))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@wp.kernel
|
|
30
|
+
def compute_loss(body_q: wp.array(dtype=wp.transform), body_index: int, loss: wp.array(dtype=float)):
|
|
31
|
+
x = wp.transform_get_translation(body_q[body_index])
|
|
32
|
+
|
|
33
|
+
delta = x - TARGET
|
|
34
|
+
loss[0] = wp.dot(delta, delta)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@wp.kernel
|
|
38
|
+
def step_kernel(x: wp.array(dtype=float), grad: wp.array(dtype=float), alpha: float):
|
|
39
|
+
tid = wp.tid()
|
|
40
|
+
|
|
41
|
+
# gradient descent step
|
|
42
|
+
x[tid] = x[tid] - grad[tid] * alpha
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Example:
|
|
46
|
+
def __init__(self, stage, device=None, verbose=False):
|
|
47
|
+
self.verbose = verbose
|
|
48
|
+
if device is None:
|
|
49
|
+
self.device = wp.get_device()
|
|
50
|
+
else:
|
|
51
|
+
self.device = device
|
|
52
|
+
|
|
53
|
+
self.frame_dt = 1.0 / 60.0
|
|
54
|
+
self.render_time = 0.0
|
|
55
|
+
|
|
56
|
+
builder = wp.sim.ModelBuilder()
|
|
57
|
+
builder.add_articulation()
|
|
58
|
+
|
|
59
|
+
chain_length = 4
|
|
60
|
+
chain_width = 1.0
|
|
61
|
+
|
|
62
|
+
for i in range(chain_length):
|
|
63
|
+
if i == 0:
|
|
64
|
+
parent = -1
|
|
65
|
+
parent_joint_xform = wp.transform([0.0, 0.0, 0.0], wp.quat_identity())
|
|
66
|
+
else:
|
|
67
|
+
parent = builder.joint_count - 1
|
|
68
|
+
parent_joint_xform = wp.transform([chain_width, 0.0, 0.0], wp.quat_identity())
|
|
69
|
+
|
|
70
|
+
# create body
|
|
71
|
+
b = builder.add_body(origin=wp.transform([i, 0.0, 0.0], wp.quat_identity()), armature=0.1)
|
|
72
|
+
|
|
73
|
+
builder.add_joint_revolute(
|
|
74
|
+
parent=parent,
|
|
75
|
+
child=b,
|
|
76
|
+
axis=(0.0, 0.0, 1.0),
|
|
77
|
+
parent_xform=parent_joint_xform,
|
|
78
|
+
child_xform=wp.transform_identity(),
|
|
79
|
+
limit_lower=-np.deg2rad(60.0),
|
|
80
|
+
limit_upper=np.deg2rad(60.0),
|
|
81
|
+
target_ke=0.0,
|
|
82
|
+
target_kd=0.0,
|
|
83
|
+
limit_ke=30.0,
|
|
84
|
+
limit_kd=30.0,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if i == chain_length - 1:
|
|
88
|
+
# create end effector
|
|
89
|
+
builder.add_shape_sphere(pos=wp.vec3(0.0, 0.0, 0.0), radius=0.1, density=10.0, body=b)
|
|
90
|
+
|
|
91
|
+
else:
|
|
92
|
+
# create shape
|
|
93
|
+
builder.add_shape_box(
|
|
94
|
+
pos=wp.vec3(chain_width * 0.5, 0.0, 0.0), hx=chain_width * 0.5, hy=0.1, hz=0.1, density=10.0, body=b
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# finalize model
|
|
98
|
+
self.model = builder.finalize(self.device)
|
|
99
|
+
self.model.ground = False
|
|
100
|
+
|
|
101
|
+
self.state = self.model.state()
|
|
102
|
+
|
|
103
|
+
self.renderer = None
|
|
104
|
+
if stage:
|
|
105
|
+
self.renderer = wp.sim.render.SimRenderer(self.model, stage, scaling=50.0)
|
|
106
|
+
|
|
107
|
+
# optimization variables
|
|
108
|
+
self.loss = wp.zeros(1, dtype=float, device=self.device)
|
|
109
|
+
|
|
110
|
+
self.model.joint_q.requires_grad = True
|
|
111
|
+
self.state.body_q.requires_grad = True
|
|
112
|
+
self.loss.requires_grad = True
|
|
113
|
+
|
|
114
|
+
self.train_rate = 0.01
|
|
115
|
+
|
|
116
|
+
def forward(self):
|
|
117
|
+
wp.sim.eval_fk(self.model, self.model.joint_q, self.model.joint_qd, None, self.state)
|
|
118
|
+
|
|
119
|
+
wp.launch(
|
|
120
|
+
compute_loss,
|
|
121
|
+
dim=1,
|
|
122
|
+
inputs=[self.state.body_q, len(self.state.body_q) - 1, self.loss],
|
|
123
|
+
device=self.device,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def step(self):
|
|
127
|
+
tape = wp.Tape()
|
|
128
|
+
with tape:
|
|
129
|
+
self.forward()
|
|
130
|
+
tape.backward(loss=self.loss)
|
|
131
|
+
|
|
132
|
+
if self.verbose:
|
|
133
|
+
print(f"loss: {self.loss}")
|
|
134
|
+
print(f"joint_grad: {tape.gradients[self.model.joint_q]}")
|
|
135
|
+
|
|
136
|
+
# gradient descent
|
|
137
|
+
wp.launch(
|
|
138
|
+
step_kernel,
|
|
139
|
+
dim=len(self.model.joint_q),
|
|
140
|
+
inputs=[self.model.joint_q, tape.gradients[self.model.joint_q], self.train_rate],
|
|
141
|
+
device=self.device,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# zero gradients
|
|
145
|
+
tape.zero()
|
|
146
|
+
|
|
147
|
+
def render(self):
|
|
148
|
+
if self.renderer is None:
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
self.renderer.begin_frame(self.render_time)
|
|
152
|
+
self.renderer.render(self.state)
|
|
153
|
+
self.renderer.render_sphere(name="target", pos=TARGET, rot=wp.quat_identity(), radius=0.1, color=(1.0, 0.0, 0.0))
|
|
154
|
+
self.renderer.end_frame()
|
|
155
|
+
self.render_time += self.frame_dt
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
if __name__ == "__main__":
|
|
159
|
+
stage_path = os.path.join(os.path.dirname(__file__), "example_inverse_kinematics.usd")
|
|
160
|
+
example = Example(stage_path, device=wp.get_preferred_device(), verbose=True)
|
|
161
|
+
|
|
162
|
+
train_iters = 512
|
|
163
|
+
|
|
164
|
+
for _ in range(train_iters):
|
|
165
|
+
example.step()
|
|
166
|
+
example.render()
|
|
167
|
+
|
|
168
|
+
if example.renderer:
|
|
169
|
+
example.renderer.save()
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Copyright (c) 2022 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 Sim Rigid Kinematics
|
|
10
|
+
#
|
|
11
|
+
# Tests rigid body forward and backwards kinematics through the
|
|
12
|
+
# wp.sim.eval_ik() and wp.sim.eval_fk() methods. Shows how to connect
|
|
13
|
+
# gradients from Warp to PyTorch, through custom autograd nodes.
|
|
14
|
+
#
|
|
15
|
+
###########################################################################
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
import torch
|
|
21
|
+
|
|
22
|
+
import warp as wp
|
|
23
|
+
import warp.sim
|
|
24
|
+
import warp.sim.render
|
|
25
|
+
|
|
26
|
+
wp.init()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ForwardKinematics(torch.autograd.Function):
|
|
30
|
+
@staticmethod
|
|
31
|
+
def forward(ctx, joint_q, joint_qd, model):
|
|
32
|
+
|
|
33
|
+
ctx.tape = wp.Tape()
|
|
34
|
+
ctx.model = model
|
|
35
|
+
ctx.joint_q = wp.from_torch(joint_q)
|
|
36
|
+
ctx.joint_qd = wp.from_torch(joint_qd)
|
|
37
|
+
|
|
38
|
+
# allocate output
|
|
39
|
+
ctx.state = model.state()
|
|
40
|
+
|
|
41
|
+
with ctx.tape:
|
|
42
|
+
wp.sim.eval_fk(model, ctx.joint_q, ctx.joint_qd, None, ctx.state)
|
|
43
|
+
|
|
44
|
+
return (wp.to_torch(ctx.state.body_q), wp.to_torch(ctx.state.body_qd))
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def backward(ctx, adj_body_q, adj_body_qd):
|
|
48
|
+
|
|
49
|
+
# map incoming Torch grads to our output variables
|
|
50
|
+
ctx.state.body_q.grad = wp.from_torch(adj_body_q, dtype=wp.transform)
|
|
51
|
+
ctx.state.body_qd.grad = wp.from_torch(adj_body_qd, dtype=wp.spatial_vector)
|
|
52
|
+
|
|
53
|
+
ctx.tape.backward()
|
|
54
|
+
|
|
55
|
+
# return adjoint w.r.t. inputs
|
|
56
|
+
return (wp.to_torch(ctx.tape.gradients[ctx.joint_q]), wp.to_torch(ctx.tape.gradients[ctx.joint_qd]), None)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Example:
|
|
60
|
+
def __init__(self, stage, device=None, verbose=False):
|
|
61
|
+
self.verbose = verbose
|
|
62
|
+
|
|
63
|
+
self.frame_dt = 1.0 / 60.0
|
|
64
|
+
self.render_time = 0.0
|
|
65
|
+
|
|
66
|
+
builder = wp.sim.ModelBuilder()
|
|
67
|
+
builder.add_articulation()
|
|
68
|
+
|
|
69
|
+
chain_length = 4
|
|
70
|
+
chain_width = 1.0
|
|
71
|
+
|
|
72
|
+
for i in range(chain_length):
|
|
73
|
+
if i == 0:
|
|
74
|
+
parent = -1
|
|
75
|
+
parent_joint_xform = wp.transform([0.0, 0.0, 0.0], wp.quat_identity())
|
|
76
|
+
else:
|
|
77
|
+
parent = builder.joint_count - 1
|
|
78
|
+
parent_joint_xform = wp.transform([chain_width, 0.0, 0.0], wp.quat_identity())
|
|
79
|
+
|
|
80
|
+
# create body
|
|
81
|
+
b = builder.add_body(origin=wp.transform([i, 0.0, 0.0], wp.quat_identity()), armature=0.1)
|
|
82
|
+
|
|
83
|
+
builder.add_joint_revolute(
|
|
84
|
+
parent=parent,
|
|
85
|
+
child=b,
|
|
86
|
+
axis=wp.vec3(0.0, 0.0, 1.0),
|
|
87
|
+
parent_xform=parent_joint_xform,
|
|
88
|
+
child_xform=wp.transform_identity(),
|
|
89
|
+
limit_lower=-np.deg2rad(60.0),
|
|
90
|
+
limit_upper=np.deg2rad(60.0),
|
|
91
|
+
target_ke=0.0,
|
|
92
|
+
target_kd=0.0,
|
|
93
|
+
limit_ke=30.0,
|
|
94
|
+
limit_kd=30.0,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if i == chain_length - 1:
|
|
98
|
+
# create end effector
|
|
99
|
+
builder.add_shape_sphere(pos=wp.vec3(0.0, 0.0, 0.0), radius=0.1, density=10.0, body=b)
|
|
100
|
+
|
|
101
|
+
else:
|
|
102
|
+
# create shape
|
|
103
|
+
builder.add_shape_box(
|
|
104
|
+
pos=wp.vec3(chain_width * 0.5, 0.0, 0.0), hx=chain_width * 0.5, hy=0.1, hz=0.1, density=10.0, body=b
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# finalize model
|
|
108
|
+
self.model = builder.finalize(device)
|
|
109
|
+
self.model.ground = False
|
|
110
|
+
|
|
111
|
+
self.torch_device = wp.device_to_torch(self.model.device)
|
|
112
|
+
|
|
113
|
+
self.renderer = None
|
|
114
|
+
if stage:
|
|
115
|
+
self.renderer = wp.sim.render.SimRenderer(self.model, stage, scaling=50.0)
|
|
116
|
+
|
|
117
|
+
self.target = torch.from_numpy(np.array((2.0, 1.0, 0.0))).to(self.torch_device)
|
|
118
|
+
|
|
119
|
+
self.body_q = None
|
|
120
|
+
self.body_qd = None
|
|
121
|
+
|
|
122
|
+
# optimization variable
|
|
123
|
+
self.joint_q = torch.zeros(len(self.model.joint_q), requires_grad=True, device=self.torch_device)
|
|
124
|
+
self.joint_qd = torch.zeros(len(self.model.joint_qd), requires_grad=True, device=self.torch_device)
|
|
125
|
+
|
|
126
|
+
self.train_rate = 0.01
|
|
127
|
+
|
|
128
|
+
def forward(self):
|
|
129
|
+
(self.body_q, self.body_qd) = ForwardKinematics.apply(self.joint_q, self.joint_qd, self.model)
|
|
130
|
+
self.loss = torch.norm(self.body_q[self.model.body_count - 1][0:3] - self.target) ** 2.0
|
|
131
|
+
|
|
132
|
+
def step(self):
|
|
133
|
+
self.forward()
|
|
134
|
+
self.loss.backward()
|
|
135
|
+
|
|
136
|
+
if self.verbose:
|
|
137
|
+
print(f"loss: {self.loss}")
|
|
138
|
+
print(f"loss: {self.joint_q.grad}")
|
|
139
|
+
|
|
140
|
+
with torch.no_grad():
|
|
141
|
+
self.joint_q -= self.joint_q.grad * self.train_rate
|
|
142
|
+
self.joint_q.grad.zero_()
|
|
143
|
+
|
|
144
|
+
def render(self):
|
|
145
|
+
if self.renderer is None:
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
s = self.model.state()
|
|
149
|
+
s.body_q = wp.from_torch(self.body_q, dtype=wp.transform, requires_grad=False)
|
|
150
|
+
s.body_qd = wp.from_torch(self.body_qd, dtype=wp.spatial_vector, requires_grad=False)
|
|
151
|
+
|
|
152
|
+
self.renderer.begin_frame(self.render_time)
|
|
153
|
+
self.renderer.render(s)
|
|
154
|
+
self.renderer.render_sphere(name="target", pos=self.target, rot=wp.quat_identity(), radius=0.1, color=(1.0, 0.0, 0.0))
|
|
155
|
+
self.renderer.end_frame()
|
|
156
|
+
self.render_time += self.frame_dt
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
if __name__ == "__main__":
|
|
160
|
+
stage_path = os.path.join(os.path.dirname(__file__), "example_inverse_kinematics_torch.usd")
|
|
161
|
+
example = Example(stage_path, device=wp.get_preferred_device(), verbose=True)
|
|
162
|
+
|
|
163
|
+
train_iters = 512
|
|
164
|
+
|
|
165
|
+
for _ in range(train_iters):
|
|
166
|
+
example.step()
|
|
167
|
+
example.render()
|
|
168
|
+
|
|
169
|
+
if example.renderer:
|
|
170
|
+
example.renderer.save()
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Copyright (c) 2023 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 Diff Sim Spring Cage
|
|
10
|
+
#
|
|
11
|
+
# A single particle is attached with springs to each point of a cage.
|
|
12
|
+
# The objective is to optimize the rest length of the springs in order
|
|
13
|
+
# for the particle to be pulled towards a target position.
|
|
14
|
+
#
|
|
15
|
+
###########################################################################
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
import warp as wp
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
wp.init()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@wp.kernel
|
|
27
|
+
def compute_loss_kernel(
|
|
28
|
+
pos: wp.array(dtype=wp.vec3),
|
|
29
|
+
target_pos: wp.vec3,
|
|
30
|
+
loss: wp.array(dtype=float),
|
|
31
|
+
):
|
|
32
|
+
loss[0] = wp.length_sq(pos[0] - target_pos)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@wp.kernel(enable_backward=False)
|
|
36
|
+
def apply_gradient_kernel(
|
|
37
|
+
spring_rest_lengths_grad: wp.array(dtype=float),
|
|
38
|
+
train_rate: float,
|
|
39
|
+
spring_rest_lengths: wp.array(dtype=float),
|
|
40
|
+
):
|
|
41
|
+
tid = wp.tid()
|
|
42
|
+
|
|
43
|
+
spring_rest_lengths[tid] -= spring_rest_lengths_grad[tid] * train_rate
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Example:
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
stage=None,
|
|
50
|
+
verbose=False,
|
|
51
|
+
):
|
|
52
|
+
import warp.sim
|
|
53
|
+
|
|
54
|
+
# Duration of the simulation, in seconds.
|
|
55
|
+
duration = 1.0
|
|
56
|
+
|
|
57
|
+
# Number of frames per second.
|
|
58
|
+
self.fps = 30.0
|
|
59
|
+
|
|
60
|
+
# Duration of a single simulation iteration in number of frames.
|
|
61
|
+
self.frame_count = int(duration * self.fps)
|
|
62
|
+
|
|
63
|
+
# Number of simulation steps to take per frame.
|
|
64
|
+
self.sim_substep_count = 1
|
|
65
|
+
|
|
66
|
+
# Delta time between each simulation substep.
|
|
67
|
+
self.sim_dt = 1.0 / (self.fps * self.sim_substep_count)
|
|
68
|
+
|
|
69
|
+
# Target position that we want the main particle to reach by optimising
|
|
70
|
+
# the rest lengths of the springs.
|
|
71
|
+
self.target_pos = (0.125, 0.25, 0.375)
|
|
72
|
+
|
|
73
|
+
# Number of training iterations.
|
|
74
|
+
self.train_iters = 100
|
|
75
|
+
|
|
76
|
+
# Factor by which the rest lengths of the springs are adjusted after each
|
|
77
|
+
# iteration, relatively to the corresponding gradients. Lower values
|
|
78
|
+
# converge more slowly but have less chances to miss the local minimum.
|
|
79
|
+
self.train_rate = 0.5
|
|
80
|
+
|
|
81
|
+
# Initialize the helper to build a physics scene.
|
|
82
|
+
builder = warp.sim.ModelBuilder()
|
|
83
|
+
|
|
84
|
+
# Define the main particle at the origin.
|
|
85
|
+
particle_mass = 1.0
|
|
86
|
+
builder.add_particle((0.0, 0.0, 0.0), (0.0, 0.0, 0.0), particle_mass)
|
|
87
|
+
|
|
88
|
+
# Define the cage made of points that will be pulling our main particle
|
|
89
|
+
# using springs.
|
|
90
|
+
# fmt: off
|
|
91
|
+
builder.add_particle((-0.7, 0.8, 0.2), (0.0, 0.0, 0.0), 0.0)
|
|
92
|
+
builder.add_particle(( 0.0, 0.2, 1.1), (0.0, 0.0, 0.0), 0.0)
|
|
93
|
+
builder.add_particle(( 0.1, 0.1, -1.2), (0.0, 0.0, 0.0), 0.0)
|
|
94
|
+
builder.add_particle(( 0.6, 0.4, 0.4), (0.0, 0.0, 0.0), 0.0)
|
|
95
|
+
builder.add_particle(( 0.7, -0.9, -0.2), (0.0, 0.0, 0.0), 0.0)
|
|
96
|
+
builder.add_particle((-0.8, -0.8, 0.1), (0.0, 0.0, 0.0), 0.0)
|
|
97
|
+
builder.add_particle((-0.9, 0.2, -0.8), (0.0, 0.0, 0.0), 0.0)
|
|
98
|
+
builder.add_particle(( 1.0, 0.4, -0.1), (0.0, 0.0, 0.0), 0.0)
|
|
99
|
+
# fmt: on
|
|
100
|
+
|
|
101
|
+
# Define the spring constraints between the main particle and the cage points.
|
|
102
|
+
spring_elastic_stiffness = 100.0
|
|
103
|
+
spring_elastic_damping = 10.0
|
|
104
|
+
for i in range(1, builder.particle_count):
|
|
105
|
+
builder.add_spring(0, i, spring_elastic_stiffness, spring_elastic_damping, 0)
|
|
106
|
+
|
|
107
|
+
# Build the model and set-up its properties.
|
|
108
|
+
self.model = builder.finalize(requires_grad=True)
|
|
109
|
+
self.model.gravity = np.array((0.0, 0.0, 0.0))
|
|
110
|
+
self.model.ground = False
|
|
111
|
+
|
|
112
|
+
# Use the Euler integrator for stepping through the simulation.
|
|
113
|
+
self.integrator = warp.sim.SemiImplicitIntegrator()
|
|
114
|
+
|
|
115
|
+
# Initialize a state for each simulation step.
|
|
116
|
+
self.states = tuple(self.model.state() for _ in range(self.frame_count * self.sim_substep_count + 1))
|
|
117
|
+
|
|
118
|
+
# Initialize a loss value that will represent the distance of the main
|
|
119
|
+
# particle to the target position. It needs to be defined as an array
|
|
120
|
+
# so that it can be written out by a kernel.
|
|
121
|
+
self.loss = wp.zeros(1, dtype=float, requires_grad=True)
|
|
122
|
+
|
|
123
|
+
if stage:
|
|
124
|
+
import warp.sim.render
|
|
125
|
+
|
|
126
|
+
# Helper to render the physics scene as a USD file.
|
|
127
|
+
self.renderer = warp.sim.render.SimRenderer(self.model, stage, fps=self.fps, scaling=10.0)
|
|
128
|
+
|
|
129
|
+
# Allows rendering one simulation to USD every N training iterations.
|
|
130
|
+
self.render_iteration_steps = 2
|
|
131
|
+
|
|
132
|
+
# Frame number used to render the simulation iterations onto the USD file.
|
|
133
|
+
self.render_frame = 0
|
|
134
|
+
else:
|
|
135
|
+
self.renderer = None
|
|
136
|
+
|
|
137
|
+
self.use_graph = wp.get_device().is_cuda
|
|
138
|
+
if self.use_graph:
|
|
139
|
+
# Capture all the kernel launches into a CUDA graph so that they can
|
|
140
|
+
# all be run in a single graph launch, which helps with performance.
|
|
141
|
+
with wp.ScopedCapture() as capture:
|
|
142
|
+
self.tape = wp.Tape()
|
|
143
|
+
with self.tape:
|
|
144
|
+
self.forward()
|
|
145
|
+
self.tape.backward(loss=self.loss)
|
|
146
|
+
self.graph = capture.graph
|
|
147
|
+
|
|
148
|
+
self.verbose = verbose
|
|
149
|
+
|
|
150
|
+
def forward(self):
|
|
151
|
+
for i in range(1, len(self.states)):
|
|
152
|
+
prev = self.states[i - 1]
|
|
153
|
+
curr = self.states[i]
|
|
154
|
+
prev.clear_forces()
|
|
155
|
+
self.integrator.simulate(
|
|
156
|
+
self.model,
|
|
157
|
+
prev,
|
|
158
|
+
curr,
|
|
159
|
+
self.sim_dt,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
last_state = self.states[-1]
|
|
163
|
+
wp.launch(
|
|
164
|
+
compute_loss_kernel,
|
|
165
|
+
dim=1,
|
|
166
|
+
inputs=(
|
|
167
|
+
last_state.particle_q,
|
|
168
|
+
self.target_pos,
|
|
169
|
+
),
|
|
170
|
+
outputs=(self.loss,),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def step(self):
|
|
174
|
+
if self.use_graph:
|
|
175
|
+
wp.capture_launch(self.graph)
|
|
176
|
+
else:
|
|
177
|
+
self.tape = wp.Tape()
|
|
178
|
+
with self.tape:
|
|
179
|
+
self.forward()
|
|
180
|
+
self.tape.backward(loss=self.loss)
|
|
181
|
+
|
|
182
|
+
wp.launch(
|
|
183
|
+
apply_gradient_kernel,
|
|
184
|
+
dim=self.model.spring_count,
|
|
185
|
+
inputs=(
|
|
186
|
+
self.model.spring_rest_length.grad,
|
|
187
|
+
self.train_rate,
|
|
188
|
+
),
|
|
189
|
+
outputs=(self.model.spring_rest_length,),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
self.tape.zero()
|
|
193
|
+
|
|
194
|
+
def render(self):
|
|
195
|
+
if self.renderer is None:
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
self.renderer.begin_frame(0.0)
|
|
199
|
+
self.renderer.render_box(
|
|
200
|
+
name="target",
|
|
201
|
+
pos=self.target_pos,
|
|
202
|
+
rot=wp.quat_identity(),
|
|
203
|
+
extents=(0.1, 0.1, 0.1),
|
|
204
|
+
color=(1.0, 0.0, 0.0),
|
|
205
|
+
)
|
|
206
|
+
self.renderer.end_frame()
|
|
207
|
+
|
|
208
|
+
for frame in range(self.frame_count):
|
|
209
|
+
self.renderer.begin_frame(self.render_frame / self.fps)
|
|
210
|
+
self.renderer.render(self.states[frame * self.sim_substep_count])
|
|
211
|
+
self.renderer.end_frame()
|
|
212
|
+
|
|
213
|
+
self.render_frame += 1
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
if __name__ == "__main__":
|
|
217
|
+
|
|
218
|
+
stage_path = os.path.join(os.path.dirname(__file__), "example_spring_cage.usd")
|
|
219
|
+
|
|
220
|
+
example = Example(stage_path, verbose=True)
|
|
221
|
+
|
|
222
|
+
for iteration in range(example.train_iters):
|
|
223
|
+
example.step()
|
|
224
|
+
|
|
225
|
+
loss = example.loss.numpy()[0]
|
|
226
|
+
|
|
227
|
+
if example.verbose:
|
|
228
|
+
print(f"[{iteration:3d}] loss={loss:.8f}")
|
|
229
|
+
|
|
230
|
+
if iteration == example.train_iters - 1 or iteration % example.render_iteration_steps == 0:
|
|
231
|
+
example.render()
|
|
232
|
+
|
|
233
|
+
if example.renderer:
|
|
234
|
+
example.renderer.save()
|