"""
Functions to do with molecules that are analogous to rdkit.Chem.rdchem.
"""
from typing import List, Tuple, Union, Dict, Any
from rdkit import Chem as rdChem
import numpy as np
from .utilities import isiterable
[docs]def GetSymmetricAtomIndices(
mol: rdChem.Mol,
maxMatches: int = 10000,
) -> List[Tuple[int, ...]]:
"""Get atom indices of symmetric atoms
Returns
-------
symmetric_indices: List[Tuple[int, ...]]
In this list, one item is a sorted tuple of indices,
where each index indicates an atom that is symmetric
to all the other indices in the tuple.
"""
# take care of resonance
matches = [
match
for resMol in rdChem.ResonanceMolSupplier(mol)
for match in resMol.GetSubstructMatches(
mol, uniquify=False, maxMatches=maxMatches
)
]
atom_symmetries = set(tuple(sorted(set(x))) for x in zip(*matches))
return sorted([x for x in atom_symmetries if len(x) > 1])
[docs]def GetTaggedSubstructMatches(
mol: rdChem.Mol,
query: rdChem.Mol,
uniquify: bool = False,
useChirality: bool = False,
useQueryQueryMatches: bool = False,
maxMatches: int = 1000,
mappingAsTaggedDict: bool = False,
) -> Union[List[Tuple[int, ...]], List[Dict[int, int]]]:
"""Only return tagged atoms in substruct match, in tag order"""
matches = mol.GetSubstructMatches(
query,
uniquify=uniquify,
useChirality=useChirality,
useQueryQueryMatches=useQueryQueryMatches,
maxMatches=maxMatches,
)
map_numbers = np.array([a.GetAtomMapNum() for a in query.GetAtoms()])
not_zero = np.where(map_numbers)[0]
matches = [
tuple(x for i, x in enumerate(match) if i in not_zero) for match in matches
]
matches = sorted(set(matches))
map_numbers = map_numbers[not_zero]
order = np.argsort(map_numbers)
matches = [tuple(match[i] for i in order) for match in matches]
if mappingAsTaggedDict:
map_numbers = list(map(int, map_numbers[order]))
return [dict(zip(map_numbers, match)) for match in matches]
return matches
[docs]def SetPropsFromDict(obj: Union[rdChem.Mol, rdChem.Atom], properties: Dict[str, Any]):
"""Set properties from dict, analogous to GetPropsAsDict()"""
for key, val in properties.items():
if key == "__computedProps":
continue
valtype = type(val)
if val is False or val is True or np.issubdtype(valtype, np.bool_):
obj.SetBoolProp(key, bool(val))
# exhaustively list np types for Windows
elif (isinstance(val, (int, np.int_, np.int16, np.int32, np.int64, np.int0, np.intp, np.intc))
or np.issubdtype(valtype, np.int_)):
obj.SetIntProp(key, int(val))
elif (isinstance(val, (float, np.float_, np.float16, np.float32, np.float64))
or np.issubdtype(valtype, np.float_)):
obj.SetDoubleProp(key, float(val))
elif isinstance(val, str) or np.issubdtype(valtype, str):
obj.SetProp(key, val)
elif isinstance(val, rdChem.rdBase._vecti):
obj.SetExplicitBitVectProp(key, val)
else:
raise ValueError(f"No setter function for {val} of type {valtype}")