Source code for stko._internal.molecular.molecule_modifiers.molecule_transformer

import logging
from collections import abc

import stk
from rdkit.Chem import AllChem as rdkit  # noqa: N813

from stko._internal.molecular.atoms.dummy_atom import Du

logger = logging.getLogger(__name__)


[docs] class MoleculeTransformer: """Split an stk.molecule into many with new functional groups. Parameters: replacer_smarts: SMARTS string of atom to replace dummy atoms with. This must be a single atom. functional_groups: Functional group factories to use to define new building block. Raises: :class:`ValueError`: If `replacer_smarts` does not correspond to a single atom. Examples: Given a molecule, this class allows you to cap a split molecule (see :class:`MoleculeSplitter`) at the broken bond with an atom defined in `replacer_smarts`. .. testcode:: mol-transform import stk import stko full_mol = stk.BuildingBlock('C1=CC=NC(=C1)C=NC2=CC=C(C=C2)Br') splitter = stko.MoleculeSplitter( breaker_smarts='[#6X3]~[#7X2]~[#6X3H1]~[#6X3!H1]', bond_deleter_ids=(0, 1), ) split_mols = splitter.split(full_mol) transformer = stko.MoleculeTransformer( replacer_smarts='[Br]', functional_groups=(stk.BromoFactory(), ), ) for split in split_mols: transformed_mol = transformer.transform(split) """ def __init__( self, replacer_smarts: str, functional_groups: abc.Iterable[stk.FunctionalGroupFactory], ) -> None: # Add replacers bonded to * atoms. _atom_list = list(rdkit.MolFromSmarts(replacer_smarts).GetAtoms()) if len(_atom_list) != 1: msg = ( f"{replacer_smarts} corresponds {len(_atom_list)} " "atoms. Should be 1." ) raise ValueError(msg) for i in _atom_list: self._replacer = stk.Atom( id=0, atomic_number=i.GetAtomicNum(), charge=0, ) self._functional_groups = functional_groups
[docs] def transform(self, molecule: stk.Molecule) -> stk.BuildingBlock: """Transform a molecule. Parameters molecule: Molecule to modify. Returns: The resulting molecule. """ rdkit_mol = molecule.to_rdkit_mol() rdkit.SanitizeMol(rdkit_mol) atoms = [] for a in molecule.get_atoms(): if isinstance(a, Du): # type: ignore[unreachable] atoms.append( # type: ignore[unreachable] stk.Atom( id=a.get_id(), atomic_number=self._replacer.get_atomic_number(), charge=self._replacer.get_charge(), ) ) else: atoms.append(a) bonds = tuple( stk.Bond( atom1=atoms[b.get_atom1().get_id()], atom2=atoms[b.get_atom2().get_id()], order=b.get_order(), ) for b in molecule.get_bonds() ) position_matrix = molecule.get_position_matrix() building_block = stk.BuildingBlock.init( atoms=tuple(atoms), bonds=bonds, position_matrix=position_matrix, ) return stk.BuildingBlock.init_from_molecule( molecule=building_block, functional_groups=self._functional_groups, )