Source code for schrodinger.comparison.chirality

from schrodinger.infra import mm
from rdkit import Chem
from schrodinger.thirdparty import rdkit_adapter


[docs]def get_chirality(st, ignore_annotations=True): """ Make list of the chiralities and stereo chemistry. :type st: Structure instance :param st: Use the atoms in this structure :type ignore_annotations: boolean :param ignore_annotations: If True then structure level properties defining the stereochemistry will be ignored and stereochemistry is computed only from geometries and current Lewis structure :rtype: list(str or None) :return: list of chirality/stereochemistry labels """ ignore_stereo, _, _ = mm.mmstereo_get_option(mm.MMSTEREO_IGNORE_STEREO_PROP) try: if ignore_annotations and st.has3dCoords(): mm.mmstereo_set_option(mm.MMSTEREO_IGNORE_STEREO_PROP, 1, 0.0, '') else: mm.mmstereo_set_option(mm.MMSTEREO_IGNORE_STEREO_PROP, 0, 0.0, '') handle = mm.mmstereo_new(st) at_chirality = [] for at in st.atom: chirality = mm.mmstereo_atom_stereo(handle, at.index) ez = mm.mmstereo_double_bond_stereo(handle, at.index) char = _assign_chirality(chirality) if char is None: char = _assign_EZ(ez) at_chirality.append(char) mm.mmstereo_delete(handle) finally: mm.mmstereo_set_option(mm.MMSTEREO_IGNORE_STEREO_PROP, ignore_stereo, 0.0, '') return at_chirality
[docs]def get_atom_numbering_chirality(st): """ Make list of the chiralities and stereo chemistry due to atom number for the atoms in st. :type st: Structure instance :param st: Use the atoms in this structure :rtype: list(str or None) :return: list of atom-numbering chirality/stereochemistry labels """ handle = mm.mmstereo_new_anc(st) at_chirality = [] for at in st.atom: chirality = mm.mmstereo_atom_stereo(handle, at.index) ez = mm.mmstereo_double_bond_stereo(handle, at.index) char = _assign_chirality(chirality) if char is None or char == 'undef': char = _assign_EZ(ez) at_chirality.append(char) mm.mmstereo_delete(handle) return at_chirality
[docs]def get_pseudochirality(st): """ Use RDKit to obtain pseudo-chirality labels (see SHARED-6352). We will turn any dummy atoms in the structure into Lr because RDKit doesn't handle dummy atoms properly for CIP labels. :type st: Structure instance :param st: Use the atoms in this structure :rtype: list(str or None) :return: list of pseudochirality/stereochemistry labels """ st_copy = st.copy() for at in st_copy.atom: if at.atomic_number < 1: at.element = 'Lr' mol = rdkit_adapter.to_rdkit(st_copy, include_stereo=False, sanitize=False) mol.UpdatePropertyCache(strict=False) Chem.FastFindRings(mol) Chem.AssignStereochemistryFrom3D(mol) Chem.rdCIPLabeler.AssignCIPLabels(mol) p_ch = [None] * st.atom_total for at in mol.GetAtoms(): try: label = at.GetProp("_CIPCode") except KeyError: continue if label in 'rs': st_idx = at.GetIntProp(rdkit_adapter.adapter.SCHRODINGER_INDEX) p_ch[st_idx - 1] = label return p_ch
[docs]def get_chiral_centers(st): """ Return indices of CIP chiral centers in structure. :type st: Structure instance :param st: Use the atoms in this structure """ ch = get_chirality(st) return [idx for idx, label in enumerate(ch, 1) if label in {'R', 'S'}]
[docs]def valid_chiral_comp(ch1, ch2): """ Maestro's chirality checker returns both E/Z double bond isomer labels and R/S chirality labels. If a reaction (e.g. and addition or elimination reaction) changes a molecule from a double bond to a single bond, merely checking if the chirality labels match will always lead to an apparent mismatch, even though there is no actual problem. This function returns True if the chirality types can be correctly compared and False if not. :type ch1: string :param ch1: chirality label of atom 1 :type ch2: string :param ch2: chirality label of atom 2 :return: True if chiralities are comparable else False """ comparable_stereo = [{"R", "S"}, {"E", "Z"}, {"P", "M"}, {"ANS", "ANR"}, {"ANE", "ANZ"}, {"ANP", "ANM"}, {"r", "s"}] if ch1 is None or ch2 is None: return True elif any({ch1, ch2}.issubset(comp_set) for comp_set in comparable_stereo): return True else: return False
def _assign_EZ(ez): key = { mm.MMSTEREO_no_EZPM: None, mm.MMSTEREO_P: 'P', mm.MMSTEREO_M: 'M', mm.MMSTEREO_E: 'E', mm.MMSTEREO_Z: 'Z', mm.MMSTEREO_ANP: 'ANP', mm.MMSTEREO_ANM: 'ANM', mm.MMSTEREO_ANZ: 'ANZ', mm.MMSTEREO_ANE: 'ANE' } return key.get(ez, 'undef') def _assign_chirality(chirality): key = { mm.MMSTEREO_NO_CHIRALITY: None, mm.MMSTEREO_CHIRALITY_R: 'R', mm.MMSTEREO_CHIRALITY_S: 'S', mm.MMSTEREO_CHIRALITY_ANR: 'ANR', mm.MMSTEREO_CHIRALITY_ANS: 'ANS' } return key.get(chirality, 'undef')