Skip to content

[FEATURE] get_weld_constraints API #1370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

LeonLiu4
Copy link
Contributor

@LeonLiu4 LeonLiu4 commented Jul 7, 2025

Adds RigidSolver.get_weld_constraints() – returns an (N, 3) NumPy array (env_id, link1_idx, link2_idx) of all active weld constraints, enabling quick inspection and test assertions without poking internal Taichi fields.

Resolves #1365

@LeonLiu4 LeonLiu4 force-pushed the feature/get-weld branch from 00f2534 to c176525 Compare July 7, 2025 22:39
Copy link
Collaborator

@duburcqa duburcqa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you take inspiration of get_contacts? i.e. return a dict instead of a raw tensor, and fetch all relevent taichi field values in a single kernel call.

@LeonLiu4 LeonLiu4 requested a review from duburcqa July 8, 2025 19:16
@LeonLiu4 LeonLiu4 requested a review from duburcqa July 10, 2025 19:05
@LeonLiu4 LeonLiu4 requested a review from duburcqa July 14, 2025 19:35
@@ -5715,6 +5715,68 @@ def _kernel_delete_weld_constraint(
]
self.constraint_solver.ti_n_equalities[i_b] = self.constraint_solver.ti_n_equalities[i_b] - 1

@gs.assert_built
def get_weld_constraints(self, as_tensor: bool = True, to_torch: bool = True):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still wrong. If you look more closely, there is no such thing as valid_mask in RigidSolver.get_contacts, only in RigidEntity.get_contacts. You should do the same here.


@ti.kernel
def _kernel_collect_welds(self, buf: ti.types.ndarray()):
WELD = gs.EQUALITY_TYPE.WELD
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove all these variables and use their value directly in the implementation.

"obj_b": obj_b,
"valid_mask": zeros((n_envs, 0), dtype=bool),
}
shape3 = (n_envs, stride, 3)
Copy link
Collaborator

@duburcqa duburcqa Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you follow more strictly the pattern in RigidSolver.get_contacts? You should not pass a 3D tensor because it would allocate more memory than necessary but most importantly, it will break "C"-contiguity, which would be problematic if forwarded as input argument of another taichi kernel.

for _ in range(200):
scene.step()

vel1 = np.asarray(cube1.get_vel())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to call np.asarray here

vel1 = np.asarray(cube1.get_vel())
vel2 = np.asarray(cube2.get_vel())

assert_allclose(vel1, vel2, tol=1e-7)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just do assert_allclose(cube1.get_vel(), cube2.get_vel(), tol=1e-7)

welds_single = cube1.get_weld_constraints(as_tensor=True, to_torch=False)

assert_allclose(
np.array([int(welds_single["obj_a"][0]), int(welds_single["obj_b"][0])]),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove np.array and int


assert_allclose(
np.array([int(welds_single["obj_a"][0]), int(welds_single["obj_b"][0])]),
np.array([link_a.item(), link_b.item()], dtype=np.int32),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.


scene.build(n_envs=1)

rigid = scene.sim.rigid_solver
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not define this alias. This is useless here.

@pytest.mark.parametrize("backend", [gs.cpu])
def test_get_weld_constraints_entity(show_viewer, tol):
scene = gs.Scene(show_viewer=show_viewer)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to skip line here.


cube1 = scene.add_entity(gs.morphs.Box(size=(0.05,) * 3, pos=(0.0, 0.0, 0.05)))
cube2 = scene.add_entity(gs.morphs.Box(size=(0.05,) * 3, pos=(0.2, 0.0, 0.05)))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature]: Create an API to get weld constraints
3 participants