pranamanam's picture Jingjie00's picture
Upload Staplebridge files (#1)
bb6d2aa
Raw History Blame Contribute Delete
3.63 kB
"""Hydrocarbon geometry oracle.
The lactam oracles in :mod:`staplebridge.oracles.geometry` (``MockGeometryOracle``,
``CPComposerStapledOracle``) are **not modified**. This is a separate oracle for
the hydrocarbon branch, because the two chemistries have genuinely different
feasibility criteria:
* lactam K-D/E closes at i,i+3 / i,i+4 with a 4.0-6.5 A Cα window;
* hydrocarbon RCM staples span one helical turn (i,i+4) or two (i,i+7), so the
i,i+7 window sits much further out.
``ctype`` here additionally requires that the anchor residues really are the
anchor monomers the block names, which the lactam oracle has no notion of.
"""
from __future__ import annotations
import math
from typing import Any
from staplebridge.data.schemas import BuildingBlock
from staplebridge.hydrocarbon.actions import FailureReason, validate_hydrocarbon_staple
from staplebridge.hydrocarbon.catalog import is_hydrocarbon_block
from staplebridge.oracles.base import GeometryOracleBase
def _ca_distance(
coords: list[tuple[float, float, float]] | None, i: int, j: int
) -> float | None:
"""Cα(i)-Cα(j) distance, or ``None`` when coordinates are unavailable."""
if coords is None or i < 0 or j < 0 or i >= len(coords) or j >= len(coords):
return None
xi, yi, zi = coords[i]
xj, yj, zj = coords[j]
return math.sqrt((xi - xj) ** 2 + (yi - yj) ** 2 + (zi - zj) ** 2)
class HydrocarbonGeometryOracle(GeometryOracleBase):
"""Feasibility for hydrocarbon staples.
Args:
catalog: the hydrocarbon blocks in play, used for topology validation.
sentinel_cgeom: penalty returned when the staple is not even
type-feasible. Matches the lactam oracles' convention of a large
sentinel so that stage-aware geometry can detect it.
"""
def __init__(
self,
catalog: list[BuildingBlock] | None = None,
sentinel_cgeom: float = 10.0,
) -> None:
self.catalog = list(catalog or [])
self.sentinel_cgeom = float(sentinel_cgeom)
def ctype(
self,
sequence: list[str],
anchor_pair: tuple[int, int] | None,
block: BuildingBlock | None,
*,
peptide_ca: Any = None,
) -> bool:
"""True when ``(sequence, anchor_pair, block)`` is a legal hydrocarbon staple.
Sequence-level only; the Cα window is scored by :meth:`cgeom`.
"""
del peptide_ca
if block is None or not is_hydrocarbon_block(block):
return False
catalog = self.catalog or [block]
verdict = validate_hydrocarbon_staple(sequence, anchor_pair, block, catalog)
return verdict is FailureReason.OK
def cgeom(
self,
sequence: list[str],
anchor_pair: tuple[int, int] | None,
block: BuildingBlock | None,
*,
peptide_ca: Any = None,
) -> float:
"""Distance of Cα(i)-Cα(j) from the block's allowed window, in Å.
Returns ``0.0`` inside the window. Without coordinates, falls back to a
sequence-only verdict: ``0.0`` when type-feasible, else the sentinel.
"""
if not self.ctype(sequence, anchor_pair, block):
return self.sentinel_cgeom
assert anchor_pair is not None and block is not None # ctype guarantees
i, j = anchor_pair
distance = _ca_distance(peptide_ca, i, j)
if distance is None:
return 0.0
low, high = block.ca_window
if distance < low:
return float(low - distance)
if distance > high:
return float(distance - high)
return 0.0