Skip to content

Commit 3b739a2

Browse files
authored
fix motif drift for symmetric fused-motif designs (#324)
Issue When scaffolding a fused/contiguous motif under symmetry (inference_sampler.kind=symmetry), the motif drifts over the trajectory so the output no longer matches the input motif. Symmetric inference applies a per-step COM recenter, then rebuilds the symmetric copies from the ASU. A fused motif is part of the generated chain, so it isn't marked FIXED_ENTITY_ID and nothing corrects for the shift. The recenter, propagated through the symmetry transforms, moves the motif off its input pose and the error accumulates over the trajectory. Fix In SampleDiffusionWithSymmetry.apply_symmetry_to_X_L, we skip the COM recenter when a contiguous motif is present, so it stays put, and the symmetric copies rebuild from it correctly. Scope Scoped to is_motif_atom_with_fixed_coord & is_sym_asu & ~FIXED_ENTITY_ID and guarded by not self.allow_realignment, so it's a no-op for de novo symmetric, unindexed motifs and the non-symmetric sampler.
1 parent d6c07df commit 3b739a2

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

models/rfd3/src/rfd3/model/inference_sampler.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import torch
88
from jaxtyping import Float
9+
from rfd3.inference.symmetry.atom_array import FIXED_ENTITY_ID
910
from rfd3.inference.symmetry.symmetry_utils import apply_symmetry_to_xyz_atomwise
1011
from rfd3.model.cfg_utils import strip_X
1112

@@ -381,9 +382,18 @@ def apply_symmetry_to_X_L(self, X_L, f):
381382
# update symmetric frames to correct for change in global frame
382383
symmetry_feats = {k: v for k, v in f.items() if "sym" in k}
383384

385+
# a contiguous motif anchors the frame, so skip the COM recenter (avoids drift)
386+
fixed = f.get("is_motif_atom_with_fixed_coord")
387+
asu, ent = symmetry_feats["is_sym_asu"], symmetry_feats["sym_entity_id"]
388+
held_motif = (
389+
not self.allow_realignment
390+
and fixed is not None
391+
and bool((fixed & asu & (ent != FIXED_ENTITY_ID)).any())
392+
)
393+
384394
# apply symmetry frame shift to X_L
385395
X_L = apply_symmetry_to_xyz_atomwise(
386-
X_L, symmetry_feats, partial_diffusion=("partial_t" in f)
396+
X_L, symmetry_feats, partial_diffusion=("partial_t" in f) or held_motif
387397
)
388398

389399
return X_L

0 commit comments

Comments
 (0)