Source code for bbprep._internal.processes.ditopicfitter

import numpy as np
import stk
import stko

from bbprep._internal.ensemble.ensemble import Conformer, Ensemble
from bbprep._internal.selectors.binders import BindersSelector
from bbprep._internal.selectors.notplacers import NotPlacersSelector
from bbprep._internal.selectors.selector import NullSelector

from .process import Process


[docs] class DitopicFitter(Process): r"""Get the conformer best for binding as ditopic linker. The process finds the conformer with the minimum angle between binder-COM vectors:: |- - - O <-- binder | | | COM | | | |- - - O <-- binder """ def __init__(self, ensemble: Ensemble) -> None: """Initialise the process.""" self._data: dict[str, float] self._ensemble = ensemble self._selector = NullSelector() self._data = {} def _run_process( self, conformer: Conformer, conformer_id: int, ) -> float: key = stk.Smiles().get_key(conformer.molecule) + f"__{conformer_id}" if key in self._data: return self._data[key] expected = 2 if conformer.molecule.get_num_functional_groups() != expected: msg = ( f"Found {conformer.molecule.get_num_functional_groups()}" " functional groups, not 2." ) raise RuntimeError(msg) notplacers = NotPlacersSelector().yield_stepwise(conformer.molecule) binders = BindersSelector().yield_stepwise(conformer.molecule) notplacers_centroids = [ conformer.molecule.get_centroid(pl) for pl in notplacers ] binders_centroids = [ conformer.molecule.get_centroid(pl) for pl in binders ] vectors = [] for i, j in zip(notplacers_centroids, binders_centroids, strict=False): vectors.append((j - i) / np.linalg.norm(j - i)) value = stko.vector_angle(*vectors) self._save_to_data(conformer, conformer_id, value) return self._data[key]