Skip to content

Commit 93d7299

Browse files
committed
Merge remote-tracking branch 'origin/main' into HEAD
2 parents 397fec6 + d386d0d commit 93d7299

File tree

23 files changed

+353
-209
lines changed

23 files changed

+353
-209
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Generic - CPU only
1+
name: Generic
22

33
on:
44
pull_request:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Linux x86 - Nvidia GPU
1+
name: Production
22

33
on:
44
# Trigger the workflow on push on the master branch, or for any pull request

.pre-commit-config.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
repos:
22
- repo: https://github.com/psf/black
3-
rev: 25.1.0 # Use the latest version or specify the version you prefer
3+
rev: 25.1.0
44
hooks:
55
- id: black
6-
args:
7-
- --line-length=120
8-
- .

examples/rigid/suction_cup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ def main():
9696

9797
# add suction / weld constraint
9898
rigid = scene.sim.rigid_solver
99-
link_cube = np.array([cube.get_link("box_baselink").idx], dtype=gs.np_int)
100-
link_franka = np.array([franka.get_link("hand").idx], dtype=gs.np_int)
99+
link_cube = cube.get_link("box_baselink").idx
100+
link_franka = franka.get_link("hand").idx
101101
rigid.add_weld_constraint(link_cube, link_franka)
102102

103103
# lift

genesis/engine/entities/emitter.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def emit(
150150
positions = gu.transform_by_trans_R(
151151
positions,
152152
pos,
153-
gu.z_up_to_R(direction) @ gu.axis_angle_to_R(np.array([0, 0, 1]), theta),
153+
gu.z_up_to_R(direction) @ gu.axis_angle_to_R(np.array([0.0, 0.0, 1.0], dtype=gs.np_float), theta),
154154
).astype(gs.np_float)
155155

156156
positions = np.tile(positions[np.newaxis], (self._sim._B, 1, 1))
@@ -206,17 +206,21 @@ def emit_omni(self, source_radius=0.1, pos=(0.5, 0.5, 1.0), speed=1.0, particle_
206206
Parameters:
207207
----------
208208
source_radius: float, optional
209-
The radius of the sphere source. Particles will be emitted from a shell with inner radius using 0.8 * source_radius and outer radius using source_radius.
209+
The radius of the sphere source. Particles will be emitted from a shell with inner radius using
210+
'0.8 * source_radius' and outer radius using source_radius.
210211
pos: array_like, shape=(3,)
211212
The center of the sphere source.
212213
speed: float
213214
The speed of the emitted particles.
214215
particle_size: float | None
215-
The size (diameter) of the emitted particles. The actual number of particles emitted is determined by the volume of the sphere source and the size of the particles. If None, the solver's particle size is used. Note that this particle size only affects computation for number of particles emitted, not the actual size of the particles in simulation and rendering.
216+
The size (diameter) of the emitted particles. The actual number of particles emitted is determined by the
217+
volume of the sphere source and the size of the particles. If None, the solver's particle size is used.
218+
Note that this particle size only affects computation for number of particles emitted, not the actual size
219+
of the particles in simulation and rendering.
216220
"""
217221
assert self._entity is not None
218222

219-
pos = np.array(pos)
223+
pos = np.asarray(pos, dtype=gs.np_float)
220224

221225
if particle_size is None:
222226
particle_size = self._solver.particle_size
@@ -227,20 +231,20 @@ def emit_omni(self, source_radius=0.1, pos=(0.5, 0.5, 1.0), speed=1.0, particle_
227231
inner_radius=source_radius * 0.4,
228232
sampler=self._entity.sampler,
229233
)
230-
231-
positions = gu.transform_by_T(positions_, gu.trans_to_T(pos)).astype(gs.np_float)
234+
positions = pos + positions_
232235

233236
if not self._solver.boundary.is_inside(positions):
234237
gs.raise_exception("Emitted particles are outside the boundary.")
235238

236-
n_particles = len(positions)
237-
dists = np.linalg.norm(positions_, axis=1, keepdims=True)
238-
positions[np.where(dists < gs.EPS)[0]] = np.array([gs.EPS, gs.EPS, gs.EPS])
239-
vels = (positions_ / dists * speed).astype(gs.np_float)
239+
dists = np.linalg.norm(positions_, axis=1)
240+
positions[dists < gs.EPS] = gs.EPS
241+
vels = (speed / (dists + gs.EPS)) * positions_
240242

243+
n_particles = len(positions)
241244
if n_particles > self._entity.n_particles:
242245
gs.logger.warning(
243-
f"Number of particles to emit ({n_particles}) at the current step is larger than the maximum number of particles ({self._entity.n_particles})."
246+
f"Number of particles to emit ({n_particles}) at the current step is larger than the maximum number "
247+
f"of particles ({self._entity.n_particles})."
244248
)
245249

246250
self._solver._kernel_set_particles_pos(

genesis/engine/entities/mpm_entity.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,9 @@ def set_pos(self, f, pos):
8989
f : int
9090
The current substep index.
9191
pos : gs.Tensor
92-
A tensor of shape (n_particles, 3) representing particle positions.
92+
A tensor of shape (n_envs, n_particles, 3) representing particle positions.
9393
"""
94-
self.solver._kernel_set_particles_pos(
95-
f,
96-
self._particle_start,
97-
self._n_particles,
98-
pos,
99-
)
94+
self.solver._kernel_set_particles_pos(f, self._particle_start, self._n_particles, pos)
10095

10196
def set_pos_grad(self, f, pos_grad):
10297
"""

genesis/engine/entities/rigid_entity/rigid_entity.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -796,14 +796,17 @@ def _add_equality(self, name, type, objs_name, data, sol_params):
796796
# ------------------------------------------------------------------------------------
797797

798798
@gs.assert_built
799-
def get_jacobian(self, link):
799+
def get_jacobian(self, link, local_point=None):
800800
"""
801-
Get the Jacobian matrix for a target link.
801+
Get the spatial Jacobian for a point on a target link.
802802
803803
Parameters
804804
----------
805805
link : RigidLink
806806
The target link.
807+
local_point : torch.Tensor or None, shape (3,)
808+
Coordinates of the point in the link’s *local* frame.
809+
If None, the link origin is used (back-compat).
807810
808811
Returns
809812
-------
@@ -818,31 +821,48 @@ def get_jacobian(self, link):
818821
if self.n_dofs == 0:
819822
gs.raise_exception("Entity has zero dofs.")
820823

821-
self._kernel_get_jacobian(link.idx)
824+
if local_point is None:
825+
self._kernel_get_jacobian_zero(link.idx)
826+
else:
827+
p_local = torch.as_tensor(local_point, dtype=gs.tc_float, device=gs.device)
828+
if p_local.shape != (3,):
829+
gs.raise_exception("Must be a vector of length 3")
830+
self._kernel_get_jacobian(link.idx, p_local)
822831

823832
jacobian = self._jacobian.to_torch(gs.device).permute(2, 0, 1)
824833
if self._solver.n_envs == 0:
825834
jacobian = jacobian.squeeze(0)
826835

827836
return jacobian
828837

838+
@ti.func
839+
def _impl_get_jacobian(self, tgt_link_idx, i_b, p_vec):
840+
self._func_get_jacobian(
841+
tgt_link_idx,
842+
i_b,
843+
p_vec,
844+
ti.Vector.one(gs.ti_int, 3),
845+
ti.Vector.one(gs.ti_int, 3),
846+
)
847+
829848
@ti.kernel
830-
def _kernel_get_jacobian(self, tgt_link_idx: ti.i32):
831-
ti.loop_config(serialize=self._solver._para_level < gs.PARA_LEVEL.ALL)
849+
def _kernel_get_jacobian(self, tgt_link_idx: ti.i32, p_local: ti.types.ndarray()):
850+
p_vec = ti.Vector([p_local[0], p_local[1], p_local[2]], dt=gs.ti_float)
832851
for i_b in range(self._solver._B):
833-
self._func_get_jacobian(
834-
tgt_link_idx,
835-
i_b,
836-
ti.Vector.one(gs.ti_int, 3),
837-
ti.Vector.one(gs.ti_int, 3),
838-
)
852+
self._impl_get_jacobian(tgt_link_idx, i_b, p_vec)
853+
854+
@ti.kernel
855+
def _kernel_get_jacobian_zero(self, tgt_link_idx: ti.i32):
856+
for i_b in range(self._solver._B):
857+
self._impl_get_jacobian(tgt_link_idx, i_b, ti.Vector.zero(gs.ti_float, 3))
839858

840859
@ti.func
841-
def _func_get_jacobian(self, tgt_link_idx, i_b, pos_mask, rot_mask):
860+
def _func_get_jacobian(self, tgt_link_idx, i_b, p_local, pos_mask, rot_mask):
842861
for i_row, i_d in ti.ndrange(6, self.n_dofs):
843862
self._jacobian[i_row, i_d, i_b] = 0.0
844863

845-
tgt_link_pos = self._solver.links_state[tgt_link_idx, i_b].pos
864+
tgt_link_state = self._solver.links_state[tgt_link_idx, i_b]
865+
tgt_link_pos = tgt_link_state.pos + gu.ti_transform_by_quat(p_local, tgt_link_state.quat)
846866
i_l = tgt_link_idx
847867
while i_l > -1:
848868
I_l = [i_l, i_b] if ti.static(self.solver._options.batch_links_info) else i_l
@@ -1318,7 +1338,7 @@ def _kernel_inverse_kinematics(
13181338
# update jacobian for ee link
13191339
i_l_ee = links_idx[i_ee]
13201340
self._func_get_jacobian(
1321-
i_l_ee, i_b, pos_mask, rot_mask
1341+
i_l_ee, i_b, ti.Vector.zero(gs.ti_float, 3), pos_mask, rot_mask
13221342
) # NOTE: we still compute jacobian for all dofs as we haven't found a clean way to implement this
13231343

13241344
# copy to multi-link jacobian (only for the effective n_dofs instead of self.n_dofs)

genesis/engine/entities/rigid_entity/rigid_link.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,24 @@ def __init__(
5555
self._entity_idx_in_solver = entity.idx
5656

5757
self._uid = gs.UID()
58-
self._idx = idx
59-
self._parent_idx = parent_idx
60-
self._root_idx = root_idx
61-
self._child_idxs = list()
62-
self._invweight = invweight
63-
64-
self._joint_start = joint_start
65-
self._n_joints = n_joints
66-
67-
self._geom_start = geom_start
68-
self._cell_start = cell_start
69-
self._vert_start = vert_start
70-
self._face_start = face_start
71-
self._edge_start = edge_start
72-
self._verts_state_start = verts_state_start
73-
self._vgeom_start = vgeom_start
74-
self._vvert_start = vvert_start
75-
self._vface_start = vface_start
58+
self._idx: int = idx
59+
self._parent_idx: int = parent_idx # -1 if no parent
60+
self._root_idx: int | None = root_idx # None if no root
61+
self._child_idxs: list[int] = list()
62+
self._invweight: float | None = invweight
63+
64+
self._joint_start: int = joint_start
65+
self._n_joints: int = n_joints
66+
67+
self._geom_start: int = geom_start
68+
self._cell_start: int = cell_start
69+
self._vert_start: int = vert_start
70+
self._face_start: int = face_start
71+
self._edge_start: int = edge_start
72+
self._verts_state_start: int = verts_state_start
73+
self._vgeom_start: int = vgeom_start
74+
self._vvert_start: int = vvert_start
75+
self._vface_start: int = vface_start
7676

7777
# Link position & rotation at creation time:
7878
self._pos: ArrayLike = pos

genesis/engine/entities/sph_entity.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,7 @@ def set_pos(self, f, pos):
9292
pos : ndarray
9393
Array of particle positions of shape (n_envs, n_particles, 3).
9494
"""
95-
self.solver._kernel_set_particles_pos(
96-
f,
97-
self._particle_start,
98-
self._n_particles,
99-
pos,
100-
)
95+
self.solver._kernel_set_particles_pos(f, self._particle_start, self._n_particles, pos)
10196

10297
def set_pos_grad(self, f: ti.i32, pos_grad: ti.types.ndarray()):
10398
"""

genesis/engine/solvers/mpm_solver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,9 @@ def _kernel_set_particles_pos(
720720
self.particles[f, i_global, i_b].pos[k] = pos[i_b, i_p, k]
721721

722722
# we restore these whenever directly setting positions
723-
self.particles[f, i_global, i_b].vel = ti.Vector.zero(gs.ti_float, 3)
723+
self.particles[f, i_global, i_b].vel.fill(0.0)
724724
self.particles[f, i_global, i_b].F = ti.Matrix.identity(gs.ti_float, 3)
725-
self.particles[f, i_global, i_b].C = ti.Matrix.zero(gs.ti_float, 3, 3)
725+
self.particles[f, i_global, i_b].C.fill(0.0)
726726
self.particles[f, i_global, i_b].Jp = self.particles_info[i_global].default_Jp
727727

728728
@ti.kernel

0 commit comments

Comments
 (0)