Skip to content

Commit 8c39fd5

Browse files
committed
Skip pruning for degenerated contact buckets.
1 parent 192b528 commit 8c39fd5

3 files changed

Lines changed: 55 additions & 0 deletions

File tree

genesis/engine/solvers/rigid/collider/collider.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ def __init__(self, rigid_solver: "RigidSolver"):
9090
self._diff_pos_tolerance = 1e-2
9191
self._diff_normal_tolerance = 1e-2
9292
self._prune_deep_penetration_ratio = 3.0
93+
# Multiplier on the link-pair effective inertia radius squared (invweight_trans / invweight_rot) that defines
94+
# the support-polygon area threshold below which the bucket's hull pruning is skipped (all hull-dropped contacts
95+
# restored). Catches buckets too thin to absorb the first-order-Taylor bias in perturbed contact normals.
96+
self._prune_degenerate_area_ratio = 0.2
9397

9498
self._init_static_config()
9599
self._use_split_narrowphase = (
@@ -248,6 +252,7 @@ def _init_collision_fields(self) -> None:
248252
diff_normal_tolerance=self._diff_normal_tolerance,
249253
contact_pruning_tolerance=self._solver._options.contact_pruning_tolerance or 0.0,
250254
prune_deep_penetration_ratio=self._prune_deep_penetration_ratio,
255+
prune_degenerate_area_ratio=self._prune_degenerate_area_ratio,
251256
)
252257
self._init_collision_pair_idx(self._collision_pair_idx)
253258
self._init_valid_pairs()
@@ -899,6 +904,7 @@ def detection(self) -> None:
899904
)
900905
if ran_fused_dedup_coop:
901906
func_clamp_prune_and_sort_contacts_coop(
907+
self._solver.links_info,
902908
self._collider_state,
903909
self._collider_info,
904910
self._solver._rigid_global_info,
@@ -907,6 +913,7 @@ def detection(self) -> None:
907913
)
908914
else:
909915
func_clamp_prune_and_sort_contacts(
916+
self._solver.links_info,
910917
self._collider_state,
911918
self._collider_info,
912919
self._solver._rigid_global_info,

genesis/engine/solvers/rigid/collider/contact.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ def func_rotate_frame(
538538

539539
@qd.kernel(fastcache=True)
540540
def func_clamp_prune_and_sort_contacts(
541+
links_info: array_class.LinksInfo,
541542
collider_state: array_class.ColliderState,
542543
collider_info: array_class.ColliderInfo,
543544
rigid_global_info: array_class.RigidGlobalInfo,
@@ -582,6 +583,7 @@ def func_clamp_prune_and_sort_contacts(
582583
max_contact_pairs = collider_info.max_contact_pairs[None]
583584
tol = collider_info.contact_pruning_tolerance[None]
584585
prune_deep_penetration_ratio = collider_info.prune_deep_penetration_ratio[None]
586+
prune_degenerate_area_ratio = collider_info.prune_degenerate_area_ratio[None]
585587
LP_KEY_STRIDE = gs.qd_float(1.0e7)
586588
EPS = rigid_global_info.EPS[None]
587589

@@ -869,6 +871,49 @@ def func_clamp_prune_and_sort_contacts(
869871
if collider_state.contact_data.penetration[phys_i, i_b] > deep_keep_threshold:
870872
collider_state.contact_keep[i, i_b] = 1
871873

874+
# Support-polygon degeneracy gate. When the hull polygon's surface area is too small to
875+
# absorb the first-order-Taylor bias in perturbed contact normals (each contact's bias
876+
# creates a horizontal force ~ N * mc_perturbation^2; if the polygon is thin the moment arms
877+
# align rather than cancel and the LCP drifts), restore every contact the hull dropped, i.e.
878+
# skip pruning for this bucket. Closed-form shoelace area on the hull stack
879+
# contact_hull_stack[b_start..b_start+k); The threshold is the link-pair effective inertia
880+
# radius squared (invweight_trans / invweight_rot): mass cancels out, so the ratio is a
881+
# shape-and-density-distribution quantity.
882+
hull_area = gs.qd_float(0.0)
883+
if k >= 3:
884+
for i in range(k):
885+
a_pos = collider_state.contact_hull_stack[b_start + i, i_b]
886+
j = i + 1
887+
if j == k:
888+
j = 0
889+
b_pos = collider_state.contact_hull_stack[b_start + j, i_b]
890+
au = collider_state.contact_sort_key[a_pos, i_b]
891+
av = collider_state.contact_proj_v[a_pos, i_b]
892+
bu = collider_state.contact_sort_key[b_pos, i_b]
893+
bv = collider_state.contact_proj_v[b_pos, i_b]
894+
hull_area = hull_area + au * bv - bu * av
895+
hull_area = 0.5 * qd.abs(hull_area)
896+
I_la0 = (la0, i_b) if qd.static(static_rigid_sim_config.batch_links_info) else la0
897+
I_lb0 = (lb0, i_b) if qd.static(static_rigid_sim_config.batch_links_info) else lb0
898+
invw_ratio = gs.qd_float(0.0)
899+
if links_info.is_fixed[I_la0]:
900+
invw_ratio = links_info.invweight[I_lb0][0] / qd.max(
901+
links_info.invweight[I_lb0][1], EPS
902+
)
903+
elif links_info.is_fixed[I_lb0]:
904+
invw_ratio = links_info.invweight[I_la0][0] / qd.max(
905+
links_info.invweight[I_la0][1], EPS
906+
)
907+
else:
908+
invw_ratio = min(
909+
links_info.invweight[I_la0][0] / qd.max(links_info.invweight[I_la0][1], EPS),
910+
links_info.invweight[I_lb0][0] / qd.max(links_info.invweight[I_lb0][1], EPS),
911+
)
912+
if hull_area < prune_degenerate_area_ratio * invw_ratio:
913+
for i in range(b_start, b_end):
914+
if collider_state.contact_keep[i, i_b] == 0:
915+
collider_state.contact_keep[i, i_b] = 1
916+
872917
b_start = b_end
873918

874919
# Phase 3: compact contact_sort_idx by squeezing out dropped slots.
@@ -923,6 +968,7 @@ def func_clamp_prune_and_sort_contacts(
923968

924969
@qd.kernel(fastcache=True)
925970
def func_clamp_prune_and_sort_contacts_coop(
971+
links_info: array_class.LinksInfo,
926972
collider_state: array_class.ColliderState,
927973
collider_info: array_class.ColliderInfo,
928974
rigid_global_info: array_class.RigidGlobalInfo,

genesis/utils/array_class.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ class ColliderInfo:
798798
# link-pair contact pruning
799799
contact_pruning_tolerance: qd.Tensor
800800
prune_deep_penetration_ratio: qd.Tensor
801+
prune_degenerate_area_ratio: qd.Tensor
801802

802803

803804
def get_collider_info(solver, n_vert_neighbors, n_valid_pairs, collider_static_config, **kwargs):
@@ -830,6 +831,7 @@ def get_collider_info(solver, n_vert_neighbors, n_valid_pairs, collider_static_c
830831
diff_normal_tolerance=V_SCALAR_FROM(dtype=gs.qd_float, value=kwargs["diff_normal_tolerance"]),
831832
contact_pruning_tolerance=V_SCALAR_FROM(dtype=gs.qd_float, value=kwargs["contact_pruning_tolerance"]),
832833
prune_deep_penetration_ratio=V_SCALAR_FROM(dtype=gs.qd_float, value=kwargs["prune_deep_penetration_ratio"]),
834+
prune_degenerate_area_ratio=V_SCALAR_FROM(dtype=gs.qd_float, value=kwargs["prune_degenerate_area_ratio"]),
833835
)
834836

835837

0 commit comments

Comments
 (0)