def testIssue3231(self): mol = Chem.MolFromSmiles( 'C[C@H](OC1=C(N)N=CC(C2=CN(C3C[C@H](C)NCC3)N=C2)=C1)C4=C(Cl)C=CC(F)=C4Cl' ) Chem.AssignStereochemistry(mol, force=True, flagPossibleStereoCenters=True) l = Chem.FindMolChiralCenters(mol, includeUnassigned=True) self.assertEqual(l, [(1, 'S'), (12, '?'), (14, 'S')]) enumsi_opt = AllChem.StereoEnumerationOptions(maxIsomers=20, onlyUnassigned=False) isomers = list(AllChem.EnumerateStereoisomers(mol, enumsi_opt)) chi_cents = [] for iso in isomers: Chem.AssignStereochemistry(iso) chi_cents.append( Chem.FindMolChiralCenters(iso, includeUnassigned=True)) self.assertEqual( sorted(chi_cents), [[(1, 'R'), (12, 'R'), (14, 'R')], [(1, 'R'), (12, 'R'), (14, 'S')], [(1, 'R'), (12, 'S'), (14, 'R')], [(1, 'R'), (12, 'S'), (14, 'S')], [(1, 'S'), (12, 'R'), (14, 'R')], [(1, 'S'), (12, 'R'), (14, 'S')], [(1, 'S'), (12, 'S'), (14, 'R')], [(1, 'S'), (12, 'S'), (14, 'S')]])
def enumerate_stereoisomers( mol, n_variants: int = 20, undefined_only: bool = False, rationalise: bool = True, ): """Enumerate the stereocenters and bonds of the current molecule. Original source: the `openff-toolkit` lib. Warning: this function can be computationnaly intensive. Args: mol: The molecule whose state we should enumerate. n_variants: The maximum amount of molecules that should be returned. undefined_only: If we should enumerate all stereocenters and bonds or only those with undefined stereochemistry. rationalise: If we should try to build and rationalise the molecule to ensure it can exist. """ from rdkit.Chem.EnumerateStereoisomers import EnumerateStereoisomers from rdkit.Chem.EnumerateStereoisomers import StereoEnumerationOptions # safety first mol = copy_mol(mol) # in case any bonds/centers are missing stereo chem flag it here Chem.AssignStereochemistry(mol, force=False, flagPossibleStereoCenters=True, cleanIt=True) # type: ignore Chem.FindPotentialStereoBonds(mol, cleanIt=True) # type: ignore # set up the options stereo_opts = StereoEnumerationOptions( tryEmbedding=rationalise, onlyUnassigned=undefined_only, maxIsomers=n_variants, ) try: isomers = tuple(EnumerateStereoisomers(mol, options=stereo_opts)) except: # NOTE(hadim): often got "Stereo atoms should be specified before specifying CIS/TRANS bond stereochemistry" # for the ligand of reference (coming from the PDB). Not sure how to handle that. isomers = [] variants = [] for isomer in isomers: # isomer has CIS/TRANS tags so convert back to E/Z Chem.SetDoubleBondNeighborDirections(isomer) # type: ignore Chem.AssignStereochemistry(isomer, force=True, cleanIt=True) # type: ignore variants.append(isomer) return variants
def setup(self, starting_ligand_file): if self.config.starting_smiles is None: self.start_smiles = Chem.MolFromMol2File(starting_ligand_file, sanitize=False) else: self.start_smiles = Chem.MolFromSmiles(self.config.starting_smiles) if np.abs( Chem.GetFormalCharge(self.start_smiles) - int(Chem.GetFormalCharge(self.start_smiles))) != 0: print("NONINTEGRAL START CHARGE", Chem.GetFormalCharge(self.start_smiles)) Chem.SanitizeMol(self.start_smiles) Chem.AssignStereochemistry(self.start_smiles, cleanIt=True, force=True) mol = oechem.OEMol() ifs = oechem.oemolistream(starting_ligand_file) oechem.OEReadMolecule(ifs, mol) self.mol_aligner = mol ifs.close() self.mol = molecules.Molecule( self.config.atoms, self.start_smiles, allow_removal=self.config.allow_removal, allow_no_modification=self.config.allow_no_modification, allow_bonds_between_rings=self.config.allow_no_modification, allowed_ring_sizes=self.config.allowed_ring_sizes, max_steps=100) self.mol.initialize()
def initialize_rxn_from_smarts(reaction_smarts): # Initialize reaction rxn = AllChem.ReactionFromSmarts(reaction_smarts) rxn.Initialize() if rxn.Validate()[1] != 0: raise ValueError('validation failed') if PLEVEL >= 2: print('Validated rxn without errors') unmapped = 700 for rct in rxn.GetReactants(): rct.UpdatePropertyCache() Chem.AssignStereochemistry(rct) # Fill in atom map numbers for a in rct.GetAtoms(): if not a.HasProp('molAtomMapNumber'): a.SetIntProp('molAtomMapNumber', unmapped) unmapped += 1 if PLEVEL >= 2: print( ('Added {} map nums to unmapped reactants'.format(unmapped - 700))) if unmapped > 800: raise ValueError( 'Why do you have so many unmapped atoms in the template reactants?' ) return rxn
def enumerateStereoChem(compoundID, sampleDir, db, xtal): # first need to recreate the original CIF file with phenix.elbow because we cannot be sure # which program was used to create the initial restrains # this is because funny things happen to aromatic rings in case the file was made with GRADE os.chdir(os.path.join(sampleDir, 'compound')) sql = "select CompoundSMILESproduct from mainTable where CrystalName = '%s'" % xtal query = db.execute_statement(sql) originalSMILES = query[0][0] cmd = 'phenix.elbow --smiles="%s" --id=LIG --output=tmp' % (originalSMILES) os.system(cmd) stereosmiles = None if os.path.isfile(os.path.join(sampleDir, 'compound', 'tmp.pdb')): pdb = os.path.join(sampleDir, 'compound', 'tmp.pdb') else: print 'cannot find tmp.pdb' pass mol = Chem.MolFromPDBFile(pdb) Chem.AssignStereochemistry(mol, cleanIt=True, force=True, flagPossibleStereoCenters=True) if Chem.FindMolChiralCenters(mol, includeUnassigned=True) == []: print 'no chiral centres found' db_dict = {} db_dict['CompoundStereo'] = 'FALSE' updateDB(db, db_dict, xtal) else: stereosmiles = Chem.MolToSmiles(mol, isomericSmiles=True) generateRestraints(compoundID, sampleDir, db, stereosmiles, xtal)
def chiral_stereo_check(mol): Chem.SanitizeMol(mol) Chem.DetectBondStereochemistry(mol, -1) Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) Chem.AssignAtomChiralTagsFromStructure(mol, -1) return mol
def pdbqt2molblock(pdbqt_block, smi, mol_id): mol_block = None mol = Chem.MolFromPDBBlock('\n'.join( [i[:66] for i in pdbqt_block.split('MODEL')[1].split('\n')]), removeHs=False, sanitize=False) if mol: try: template_mol = Chem.MolFromSmiles(smi) # explicit hydrogends are removed from carbon atoms (chiral hydrogens) to match pdbqt mol, # e.g. [NH3+][C@H](C)C(=O)[O-] template_mol = Chem.AddHs(template_mol, explicitOnly=True, onlyOnAtoms=[ a.GetIdx() for a in template_mol.GetAtoms() if a.GetAtomicNum() != 6 ]) mol = AllChem.AssignBondOrdersFromTemplate(template_mol, mol) Chem.SanitizeMol(mol) Chem.AssignStereochemistry(mol, cleanIt=True, force=True, flagPossibleStereoCenters=True) mol.SetProp('_Name', mol_id) mol_block = Chem.MolToMolBlock(mol) except Exception: sys.stderr.write( f'Could not assign bond orders while parsing PDB: {mol_id}\n') return mol_block
def standardize(self, mol): """Return a standardized version the given molecule. The standardization process consists of the following stages: RDKit :rdkit:`RemoveHs <Chem.rdmolops-module.html#RemoveHs>`, RDKit :rdkit:`SanitizeMol <Chem.rdmolops-module.html#SanitizeMol>`, :class:`~molvs.metal.MetalDisconnector`, :class:`~molvs.normalize.Normalizer`, :class:`~molvs.charge.Reionizer`, RDKit :rdkit:`AssignStereochemistry <Chem.rdmolops-module.html#AssignStereochemistry>`. :param mol: The molecule to standardize. :type mol: :rdkit:`Mol <Chem.rdchem.Mol-class.html>` :returns: The standardized molecule. :rtype: :rdkit:`Mol <Chem.rdchem.Mol-class.html>` """ mol_props = mol.GetPropsAsDict() mol = copy.deepcopy(mol) Chem.SanitizeMol(mol) mol = Chem.RemoveHs(mol) mol = self.disconnect_metals(mol) mol = self.normalize(mol) mol = self.reionize(mol) Chem.AssignStereochemistry(mol, force=True, cleanIt=True) for k, v in mol_props.items(): mol.SetProp(k, v) # TODO: Check this removes symmetric stereocenters return mol
def graph_from_smiles(smiles): graph = MolGraph() mol = MolFromSmiles(smiles) Chem.DetectBondStereochemistry(mol, -1) Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) Chem.AssignAtomChiralTagsFromStructure(mol, -1) if not mol: raise ValueError("Could not parse SMILES string:", smiles) atoms_by_rd_idx = {} for atom in mol.GetAtoms(): new_atom_node = graph.new_node('atom', features=atom_features(atom), rdkit_ix=atom.GetIdx()) atoms_by_rd_idx[atom.GetIdx()] = new_atom_node for bond in mol.GetBonds(): atom1_node = atoms_by_rd_idx[bond.GetBeginAtom().GetIdx()] atom2_node = atoms_by_rd_idx[bond.GetEndAtom().GetIdx()] new_bond_node = graph.new_node('bond', features=bond_features(bond)) new_bond_node.add_neighbors((atom1_node, atom2_node)) atom1_node.add_neighbors((atom2_node, )) mol_node = graph.new_node('molecule') mol_node.add_neighbors(graph.nodes['atom']) return graph
def initialize_rxn_from_smarts(reaction_smarts): # Initialize reaction rxn = AllChem.ReactionFromSmarts(reaction_smarts) rxn.Initialize() if rxn.Validate()[1] != 0: raise ValueError('validation failed') if PLEVEL >= 2: print('Validated rxn without errors') # Figure out if there are unnecessary atom map numbers (that are not balanced) # e.g., leaving groups for retrosynthetic templates. This is because additional # atom map numbers in the input SMARTS template may conflict with the atom map # numbers of the molecules themselves prd_maps = [ a.GetAtomMapNum() for prd in rxn.GetProducts() for a in prd.GetAtoms() if a.GetAtomMapNum() ] unmapped = 700 for rct in rxn.GetReactants(): rct.UpdatePropertyCache() Chem.AssignStereochemistry(rct) # Fill in atom map numbers for a in rct.GetAtoms(): if not a.GetAtomMapNum() or a.GetAtomMapNum() not in prd_maps: a.SetAtomMapNum(unmapped) unmapped += 1 if PLEVEL >= 2: print('Added {} map nums to unmapped reactants'.format(unmapped - 700)) if unmapped > 800: raise ValueError( 'Why do you have so many unmapped atoms in the template reactants?' ) return rxn
def fragment_into_dummy_smiles(offmol, cleave_bonds=[], unique_r_groups=True): rdmol = Chem.RWMol(offmol.to_rdkit()) for atom in rdmol.GetAtoms(): atom.SetAtomMapNum(0) utils.assign_stereochemistry(rdmol) dummy = Chem.Atom("*") r_linkages = {} if unique_r_groups: r_groups = [(i, i + 1) for i in range(1, (len(cleave_bonds) + 1) * 2, 2)] else: r_groups = [(1, 2)] * len(cleave_bonds) for bond, rs in zip(cleave_bonds, r_groups): bond_type = rdmol.GetBondBetweenAtoms(*bond).GetBondType() rdmol.RemoveBond(*bond) r_linkages[rs[0]] = [rs[1]] for atom_index, r in zip(bond, rs): dummy_copy = Chem.Atom(dummy) dummy_copy.SetAtomMapNum(r) new_atom_index = rdmol.AddAtom(dummy_copy) rdmol.AddBond(atom_index, new_atom_index, bond_type) mols = Chem.GetMolFrags(rdmol, asMols=True) for mol in mols: counter = 1 Chem.AssignStereochemistry(mol) for atom in mol.GetAtoms(): if atom.GetSymbol() != "*": atom.SetAtomMapNum(counter) counter += 1 smiles = [utils.mol_to_smiles(m) for m in mols] return smiles, r_linkages
def find_symmetry_classes(self, mol): """ Generate list of tuples of symmetry-equivalent (homotopic) atoms in the molecular graph based on: https://sourceforge.net/p/rdkit/mailman/message/27897393/ Our thanks to Dr Michal Krompiec for the symmetrisation method and its implementation. :param mol: molecule to find symmetry classes for (rdkit mol class object) :return: A dict where the keys are the atom indices and the values are their type (type is arbitrarily based on index; only consistency is needed, no specific values) """ # Check CIPRank is present for first atom (can assume it is present for all afterwards) if not mol.GetAtomWithIdx(0).HasProp('_CIPRank'): Chem.AssignStereochemistry(mol, cleanIt=True, force=True, flagPossibleStereoCenters=True) # Array of ranks showing matching atoms cip_ranks = np.array( [int(atom.GetProp('_CIPRank')) for atom in mol.GetAtoms()]) # Map the ranks to the atoms to produce a list of symmetrical atoms atom_symmetry_classes = [ np.where(cip_ranks == rank)[0].tolist() for rank in range(max(cip_ranks) + 1) ] # Convert from list of classes to dict where each key is an atom and each value is its class (just a str) atom_symmetry_classes_dict = {} # i will be used to define the class (just index based) for i, sym_class in enumerate(atom_symmetry_classes): for atom in sym_class: atom_symmetry_classes_dict[atom] = str(i) return atom_symmetry_classes_dict
def init_search(self, smiles, algorithmname, algorithm_tag): print('Conformational search with a ' + algorithmname + ' method') print('Energy method: ' + self.method) print('Smiles: ' + smiles) print('Job name: ' + self.jobname) #init molecule and optimise mol = Chem.MolFromSmiles(self.smiles) mol = Chem.AddHs(mol, explicitOnly=False) AllChem.EmbedMolecule(mol, randomSeed=int(time.time()), useRandomCoords=True) #write pre optimised molecule self.write_pdb(mol, self.jobname + algorithm_tag + 'preoptimised.pdb') #optimise start molecule AllChem.MMFFOptimizeMolecule(mol) mp = AllChem.MMFFGetMoleculeProperties(mol) ffm = AllChem.MMFFGetMoleculeForceField(mol, mp) #write optimised molecule self.write_pdb(mol, self.jobname + algorithm_tag + 'optimised.pdb') Chem.SanitizeMol(mol) Chem.DetectBondStereochemistry(mol, -1) Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) Chem.AssignAtomChiralTagsFromStructure(mol, -1) self.ring_atoms_nr = self.count_ringatoms(mol) print('Number of non aromatic ring atoms:', str(self.ring_atoms_nr)) #create start conformer start_conformer = Conformer(mol) start_conformer.update_molecule('MMFF94') self.min_conformer = start_conformer self.min_energy = start_conformer.energy print('Start energy:', self.min_energy) self.original_conformer = self.min_conformer self.original_smiles = self.get_smiles( self.original_conformer.molecule) start_angles = start_conformer.get_dihedrals() print('Initial angles') start_angles_only = [] for angle in start_angles: print(angle) self.dihedral_atom_id.append( (angle[0], angle[1], angle[2], angle[3])) start_angles_only.append(angle) print('Number of dihedrals:', len(start_angles)) return start_conformer
def pct_stereocentres(mol): n_atoms = mol.GetNumAtoms() if n_atoms > 0: Chem.AssignStereochemistry(mol) pct_stereo = CalcNumAtomStereoCenters(mol) / n_atoms else: pct_stereo = 0 return pct_stereo
def chiral_stereo_check(mol): # avoid sanitization error e.g., dsgdb9nsd_037900.xyz Chem.SanitizeMol(mol, SanitizeFlags.SANITIZE_ALL - SanitizeFlags.SANITIZE_PROPERTIES) Chem.DetectBondStereochemistry(mol,-1) # ignore stereochemistry for now Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) Chem.AssignAtomChiralTagsFromStructure(mol,-1) return mol
def updateStereoChemAssignments(self): if not self.__rdMol: return False try: Chem.AssignAtomChiralTagsFromStructure(self.__rdMol) Chem.AssignStereochemistry(self.__rdMol, True, True, True) # self.__rdMol.Debug() except Exception as e: logger.exception("Failing with %s", str(e)) return False
def enumerate_double_bond_stereo(mol): bonds = get_unspec_double_bonds(mol) res = [] for p in product([0, 1], repeat=len(bonds)): m = deepcopy(mol) for value, bond in zip(p, bonds): set_double_bond_stereo(m.GetBondWithIdx(bond), value) Chem.AssignStereochemistry(m, force=True, cleanIt=True) res.append(m) return res
def prepare_mol(self, compute_conformer): """Prepares molecule. Args: compute_conformer: If true, compute a default conformer for molecule. """ if compute_conformer: self.mol.Compute2DCoords() # Clears any existing conformers. Chem.AssignStereochemistry(self.mol) self.check_indices()
def initialize_reactants_from_smiles(reactant_smiles): # Initialize reactants reactants = Chem.MolFromSmiles(reactant_smiles) Chem.AssignStereochemistry(reactants, flagPossibleStereoCenters=True) reactants.UpdatePropertyCache() # To have the product atoms match reactant atoms, we # need to populate the Isotope field, since this field # gets copied over during the reaction. [a.SetIsotope(i+1) for (i, a) in enumerate(reactants.GetAtoms())] vprint(2, 'Initialized reactants, assigned isotopes, stereochem, flagpossiblestereocenters') return reactants
def chiral_stereo_check(mol): """ Find and embed chiral information into the model based on the coordinates args: mol - rdkit molecule, with embeded conformer """ Chem.SanitizeMol(mol) Chem.DetectBondStereochemistry(mol, -1) Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) Chem.AssignAtomChiralTagsFromStructure(mol, -1) return
def chiral_stereo_check(mol): # Chem.SanitizeMol(mol) # Chem.DetectBondStereochemistry(mol, -1) # Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) # Chem.AssignAtomChiralTagsFromStructure(mol, -1) from rdkit.Chem.rdmolops import SanitizeFlags Chem.SanitizeMol( mol, SanitizeFlags.SANITIZE_ALL - SanitizeFlags.SANITIZE_PROPERTIES) Chem.DetectBondStereochemistry(mol, -1) Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) return mol
def molecule_from_smiles(smiles): # MolFromSmiles(m, sanitize=True) should be equivalent to # MolFromSmiles(m, sanitize=False) -> SanitizeMol(m) -> AssignStereochemistry(m, ...) molecule = Chem.MolFromSmiles(smiles, sanitize=False) # If sanitization is unsuccessful, catch the error, and try again without # the sanitization step that caused the error flag = Chem.SanitizeMol(molecule, catchErrors=True) if flag != Chem.SanitizeFlags.SANITIZE_NONE: Chem.SanitizeMol(molecule, sanitizeOps=Chem.SanitizeFlags.SANITIZE_ALL ^ flag) Chem.AssignStereochemistry(molecule, cleanIt=True, force=True) return molecule
def _removeHs(data): mols = _parseMolData(data, loadMol=False, useRDKitChemistry=False) ms = [] for molblock in mols: mol = parse_molblock(molblock, useRDKitChemistry=False) props = molblock.split("M END")[1].strip() props = props if len(props) > 1 else None Chem.FastFindRings(mol) mol.UpdatePropertyCache(strict=False) Chem.AssignAtomChiralTagsFromStructure(mol) Chem.AssignStereochemistry(mol, cleanIt=True, force=True) ms.append((remove_hs_from_mol(mol), props)) return _getSDFString(ms)
def read_one_molecule(input): res_mol = Chem.RWMol() atoms_header = input.readline().strip() if atoms_header == '': raise common.End_of_file # no EOF in Python... nb_atoms, name = common.read_atoms_header(atoms_header) old2new = {} for _i in range(nb_atoms): line = input.readline().strip() (index, nb_pi, atomic_num, nb_HA, charge, stereo) = \ common.read_atom(line) # add atom a = Chem.Atom(atomic_num) a.SetFormalCharge(charge) if stereo > 0: # set chirality a.SetChiralTag(common.atom_stereo_code_to_chiral_tag(stereo)) j = res_mol.AddAtom(a) # we need to convert atom indexes old2new[index] = j bonds_header = input.readline().strip() nb_bonds = common.read_bonds_header(bonds_header) stereo_bonds = [] for i in range(nb_bonds): line = input.readline().strip() (start_i, bt, stop_i, (stereo, c, d)) = common.read_bond(line) start = old2new[start_i] stop = old2new[stop_i] # add bond n = res_mol.AddBond(start, stop, bt) if stereo != rdkit.Chem.rdchem.BondStereo.STEREONONE: bi = n - 1 # convert stereo bond stereo atoms indexes a = old2new[c] b = old2new[d] stereo_bonds.append((bi, stereo, a, b)) # all atoms and bonds are here now # so stereo bonds info can be set for (bi, stereo, a, b) in stereo_bonds: bond = res_mol.GetBondWithIdx(bi) bond.SetStereo(stereo) bond.SetStereoAtoms(a, b) print('%s stereo %s on bond %d (%d, %d)' % (name, common.char_of_bond_stereo(stereo), bi, a, b), file=sys.stderr) try: Chem.SanitizeMol(res_mol) Chem.AssignStereochemistry(res_mol) # ! MANDATORY; AFTER SanitizeMol ! except rdkit.Chem.rdchem.KekulizeException: print("KekulizeException in %s" % name, file=sys.stderr) smi = Chem.MolToSmiles(res_mol) return (smi, name)
def get_atom_features(self, mol): AllChem.ComputeGasteigerCharges(mol) Chem.AssignStereochemistry(mol) hydrogen_donor_match = sum(mol.GetSubstructMatches(self.hydrogen_donor), ()) hydrogen_acceptor_match = sum(mol.GetSubstructMatches(self.hydrogen_acceptor), ()) acidic_match = sum(mol.GetSubstructMatches(self.acidic), ()) basic_match = sum(mol.GetSubstructMatches(self.basic), ()) ring = mol.GetRingInfo() m = [] for atom_idx in range(mol.GetNumAtoms()): atom = mol.GetAtomWithIdx(atom_idx) o = [] o += one_hot(atom.GetSymbol(), ['C', 'O', 'N', 'S', 'Cl', 'F', 'Br', 'P', 'I', 'Si', 'B', 'Na', 'Sn', 'Se', 'other']) if self.use_atom_symbol else [] o += one_hot(atom.GetDegree(), [0, 1, 2, 3, 4, 5, 6]) if self.use_degree else [] o += one_hot(atom.GetHybridization(), [Chem.rdchem.HybridizationType.SP, Chem.rdchem.HybridizationType.SP2, Chem.rdchem.HybridizationType.SP3, Chem.rdchem.HybridizationType.SP3D, Chem.rdchem.HybridizationType.SP3D2]) if self.use_hybridization else [] o += one_hot(atom.GetImplicitValence(), [0, 1, 2, 3, 4, 5, 6]) if self.use_implicit_valence else [] o += one_hot(atom.GetFormalCharge(), [-3, -2, -1, 0, 1, 2, 3]) if self.use_degree else [] # o += [atom.GetProp("_GasteigerCharge")] if self.use_partial_charge else [] # some molecules return NaN o += [atom.GetIsAromatic()] if self.use_aromaticity else [] o += [ring.IsAtomInRingOfSize(atom_idx, 3), ring.IsAtomInRingOfSize(atom_idx, 4), ring.IsAtomInRingOfSize(atom_idx, 5), ring.IsAtomInRingOfSize(atom_idx, 6), ring.IsAtomInRingOfSize(atom_idx, 7), ring.IsAtomInRingOfSize(atom_idx, 8)] if self.use_ring_size else [] o += one_hot(atom.GetTotalNumHs(), [0, 1, 2, 3, 4]) if self.use_num_hydrogen else [] if self.use_chirality: try: o += one_hot(atom.GetProp('_CIPCode'), ["R", "S"]) + [atom.HasProp("_ChiralityPossible")] except: o += [False, False] + [atom.HasProp("_ChiralityPossible")] if self.use_hydrogen_bonding: o += [atom_idx in hydrogen_donor_match] o += [atom_idx in hydrogen_acceptor_match] if self.use_acid_base: o += [atom_idx in acidic_match] o += [atom_idx in basic_match] m.append(o) return np.array(m, dtype=float)
def _stereoInfo(mrv): ret = { "headers": { "tetraHedral": { "name": "tetraHedral", "type": "COMPLEX", "source": "CALCULATOR" }, "doubleBond": { "name": "doubleBond", "type": "COMPLEX", "source": "CALCULATOR" } }, "tetraHedral": [], "doubleBond": [] } block = MarvinToMol(mrv) mol = Chem.MolFromMolBlock(block) if not mol: print "No mol for block:\n %s" % block return ret Chem.AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) for atom in mol.GetAtoms(): atomIndex = atom.GetIdx() if atom.HasProp('_CIPCode'): ret["tetraHedral"].append({ "atomIndex": atomIndex, "chirality": atom.GetProp('_CIPCode') }) for bond in mol.GetBonds(): stereo = str(bond.GetStereo()) if stereo != "STEREONONE": atom1Index = bond.GetBeginAtomIdx() atom2Index = bond.GetEndAtomIdx() bondIndex = bond.GetIdx() if stereo == "STEREOANY": cistrans = "E/Z" elif stereo == "STEREOZ": cistrans = "Z" elif stereo == "STEREOE": cistrans = "E" ret["doubleBond"].append({ "atom1Index": atom1Index, "atom2Index": atom2Index, "bondIndex": bondIndex, "cistrans": cistrans }) return ret
def _find_rd_stereocenters( molecule: Molecule, ) -> Tuple[List[int], List[Tuple[int, int]]]: """A method which returns the of the stereogenic atom and bonds of a molecule using the RDKit. Parameters ---------- molecule The molecule whose stereocenters should be returned. Notes ----- * This method currently deals with RDKit directly and should be removed once the API points suggested in openff-toolkit issue #903 have been added. Returns ------- The indices of the stereogenic atoms in the molecule and the indices of the atoms involved in stereogenic bonds in the molecule. """ from rdkit import Chem rd_molecule = molecule.to_rdkit() Chem.AssignStereochemistry( rd_molecule, cleanIt=True, force=True, flagPossibleStereoCenters=True ) stereogenic_atoms = { atom.GetIdx() for atom in rd_molecule.GetAtoms() if atom.HasProp("_ChiralityPossible") } # Clear any previous assignments on the bonds, since FindPotentialStereo # may not overwrite it for bond in rd_molecule.GetBonds(): bond.SetStereo(Chem.BondStereo.STEREONONE) Chem.FindPotentialStereoBonds(rd_molecule, cleanIt=True) stereogenic_bonds = { (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()) for bond in rd_molecule.GetBonds() if bond.GetStereo() == Chem.BondStereo.STEREOANY } return sorted(stereogenic_atoms), sorted(stereogenic_bonds)
def standardize_mol(mol): """Accepts `mol` rdkit molecule returns a sanitized version with properly assigend stereochemistry. Parameters ---------- mol : rdkit.Chem.rdchem.Mol object Returns ------- mol : rdkit.Chem.rdchem.Mol object """ flag1 = Chem.SanitizeMol(mol) flag2 = Chem.AssignStereochemistry(mol) return mol
def initialize_reactants_from_smiles(reactant_smiles): # Initialize reactants reactants = Chem.MolFromSmiles(reactant_smiles) Chem.AssignStereochemistry(reactants, flagPossibleStereoCenters=True) reactants.UpdatePropertyCache(strict=False) # To have the product atoms match reactant atoms, we # need to populate the map number field, since this field # gets copied over during the reaction via reactant_atom_idx. [a.SetAtomMapNum(i + 1) for (i, a) in enumerate(reactants.GetAtoms())] if PLEVEL >= 2: print( 'Initialized reactants, assigned map numbers, stereochem, flagpossiblestereocenters' ) return reactants
def embed(self, mol): """ Gives the molecule intial 3D coordinates. Args: mol (RDKit Mol): The molecule to embed. """ Chem.AssignStereochemistry( mol, cleanIt=True, force=True) # necessary if bond had been cut next to double bond while not AllChem.EmbedMultipleConfs( mol, numConfs=self.num_confs, params=self.params.params): self.params.randomSeed = int(time( )) # find new seed because last seed wasnt able to embed molecule