def double_point_crossover(m1, m2, bf): '''double point crossover for rings''' crossed_mols = [] n1 = random.randint(1, 4) n2 = random.randint(n1 - 1, 4) print n1 print n2 if n2 == 0: n2 = 1 cp1 = return_cut_points(m1) cp2 = return_cut_points(m2) actual_cp1 = get_actual_cut_pts(m1, n1, cp1) #print actual_cp1 actual_cp2 = get_actual_cut_pts(m2, n2, cp2) #print actual_cp2 frags1 = frag_mol(m1, actual_cp1, bf) frags2 = frag_mol(m2, actual_cp2, bf) print frags1 print frags2 fm = [Chem.MolToSmiles(x, True) for x in frags1] fm2 = [Chem.MolToSmiles(x, True) for x in frags2] print fm print fm2 temp_mol1 = Chem.CombineMols(frags1[0], frags2[1]) temp_mol2 = Chem.CombineMols(frags2[0], frags1[1]) crossed_mol1 = join_mols(temp_mol1) crossed_mol2 = join_mols(temp_mol2) fixed_mol1 = ring_fixer(crossed_mol1, m1) fixed_mol2 = ring_fixer(crossed_mol2, m2) crossed_mols.append(fixed_mol1) crossed_mols.append(fixed_mol2) return crossed_mols
def clean_charges(molec): """ this is a temporary hack. The real solution is to generate several BO matrices in ac2bo and pick the one with the lowest number of atomic charges """ rxn_smarts = [ '[N+:1]=[*:2]-[O-:3]>>[N+0:1]-[*:2]=[O-0:3]', '[N+:1]=[*:2]-[*:3]=[*:4]-[O-:5]>>' '[N+0:1]-[*:2]=[*:3]-[*:4]=[O-0:5]' ] fragments = Chem.GetMolFrags(molec, asMols=True) for i, fragment in enumerate(fragments): for smarts in rxn_smarts: patt = Chem.MolFromSmarts(smarts.split(">>")[0]) while fragment.HasSubstructMatch(patt): rxn = AllChem.ReactionFromSmarts(smarts) ps = rxn.RunReactants((fragment, )) fragment = ps[0][0] if i == 0: molec = fragment else: molec = Chem.CombineMols(molec, fragment) return molec
def _compute_fragment_join( mol, fragment, mol_atom_count, bond_between_rings=True, asMols=True, ): """List all posibilities of where a fragment can be attached to a mol""" fragment = copy.copy( fragment ) # need to copy the fragment copy is faster than all the other methods with dm.without_rdkit_log(): combined = Chem.CombineMols(mol, fragment) for i1 in range(mol.GetNumAtoms()): a1 = combined.GetAtomWithIdx(i1) if a1.GetImplicitValence() == 0: continue for i2 in range(fragment.GetNumAtoms()): i2 += mol_atom_count a2 = combined.GetAtomWithIdx(i2) if a2.GetImplicitValence() == 0: continue # no bond between atoms already in rings if not bond_between_rings and a1.IsInRing() and a2.IsInRing(): continue # no bond to form large rings else: possibilities = _all_atom_join(combined, a1, a2) for x in possibilities: x = dm.sanitize_mol(x) if x is not None: if not asMols: x = dm.to_smiles(x) yield x
def normalize(self, mol): """Apply a series of Normalization transforms to correct functional groups and recombine charges. A series of transforms are applied to the molecule. For each Normalization, the transform is applied repeatedly until no further changes occur. If any changes occurred, we go back and start from the first Normalization again, in case the changes mean an earlier transform is now applicable. The molecule is returned once the entire series of Normalizations cause no further changes or if max_restarts (default 200) is reached. :param mol: The molecule to normalize. :type mol: :rdkit:`Mol <Chem.rdchem.Mol-class.html>` :return: The normalized fragment. :rtype: :rdkit:`Mol <Chem.rdchem.Mol-class.html>` """ log.debug('Running Normalizer') # Normalize each fragment separately to get around quirky RunReactants behaviour fragments = [] for fragment in Chem.GetMolFrags(mol, asMols=True): fragments.append(self._normalize_fragment(fragment)) # Join normalized fragments into a single molecule again outmol = fragments.pop() for fragment in fragments: outmol = Chem.CombineMols(outmol, fragment) return outmol
def apply_reaction_smarts(plams_mol, reaction_smarts): """ Applies reaction smirks and returns product """ def react(reactant, reaction): """ Apply reaction to reactant and return products """ ps = reaction.RunReactants([reactant]) # keep reactant if no reaction applied if len(ps) == 0: return [reactant] products = [] for p in ps: Chem.SanitizeMol(p[0]) q = Chem.AddHs(p[0]) Chem.SanitizeMol(q) gen_coords(q) products.append(q) return products rdmol = plams2rdkit(plams_mol) reaction = AllChem.ReactionFromSmarts(reaction_smarts) # RDKit removes fragments that are disconnected from the reaction center # In order to keep these, the molecule is first split in separate fragments # and the results, including non-reacting parts, are re-combined afterwards frags = (Chem.GetMolFrags(rdmol, asMols=True)) product = Chem.Mol() for frag in frags: for p in react(frag, reaction): product = Chem.CombineMols(product, p) return rdkit2plams(product)
def judge_n_move_on(self, combined, combined_map, other, possible_map, others, disregarded): """ The mutables need to be within their own scope :param combined: :param combined_map: :param other: :param possible_map: :param others: :param disregarded: :return: """ if len(possible_map) == 0: # reject combined = Chem.Mol(combined) disregarded = [*disregarded, other] # new obj else: # accept combined_map = {**combined_map, **possible_map} # new obj combined = Chem.CombineMols(combined, other) # new obj name = '-'.join([ m.GetProp('_Name') for m in (combined, other) if m.HasProp('_Name') ]) combined.SetProp('_Name', name) disregarded = disregarded.copy() # new obj # do inners accounted_for = set(combined_map.keys()) template_sorter = self.template_sorter_factory(accounted_for) sorted_others = sorted(others[1:], key=template_sorter) self.unmerge_inner(combined, combined_map, sorted_others, disregarded)
def AddArRing(mol, bond): # if double bond if all( atom.GetImplicitValence() for atom in (bond.GetBeginAtom(), bond.GetEndAtom())): pass elif bond.GetBondType() == bondorder[3]: bond.SetBondType(bondorder[2]) else: print "wrong kind of atom given" raise MutateFail #print "in AddArRing!", Chem.MolToSmiles(mol) def AwithLabel(label): return filter(lambda atom: atom.HasProp(label), mol.GetAtoms())[0].GetIdx() butadiene = Chem.MolFromSmiles('C=CC=C') butadiene.GetAtomWithIdx(0).SetBoolProp('buta1', True) butadiene.GetAtomWithIdx(3).SetBoolProp('buta2', True) bond.GetBeginAtom().SetBoolProp('ah1', True) bond.GetEndAtom().SetBoolProp('ah2', True) mol = Chem.RWMol(Chem.CombineMols(mol, butadiene)) try: mol.AddBond(AwithLabel('buta1'), AwithLabel('ah1'), bondorder[1]) mol.AddBond(AwithLabel('buta2'), AwithLabel('ah2'), bondorder[1]) except RuntimeError: raise MutateFail #print "Finished AddArRing!", Chem.MolToSmiles(mol) return mol
def _emergency_joining(self, mol): """ The last check to see if the mol is connected, before being rectified (valence fixes). """ frags = Chem.GetMolFrags(mol, asMols=True, sanitizeFrags=False) n = len(frags) while n > 1: log.warning(f'Molecule disconnected in {n} parts. Please inspect final product!') name = mol.GetProp('_Name') for i, frag in enumerate(frags): frag.SetProp('_Name', f'name.{i}') closeness = np.ones([n, n]) closeness.fill(float('nan')) for a, b in itertools.combinations(list(range(n)), 2): closeness[a, b] = self._find_closest(frags[a], frags[b])[3] p = np.where(closeness == np.nanmin(closeness)) frags = list(frags) first = frags[p[0][0]] second = frags[p[1][0]] mol = self.join_neighboring_mols(first, second) frags.remove(first) frags.remove(second) for part in frags: mol = Chem.CombineMols(mol, part) mol.SetProp('_Name', name) frags = Chem.GetMolFrags(mol, asMols=True, sanitizeFrags=False) n = len(frags) return mol
def clean_charges(mol): Chem.SanitizeMol(mol) #rxn_smarts = ['[N+:1]=[*:2]-[C-:3]>>[N+0:1]-[*:2]=[C-0:3]', # '[N+:1]=[*:2]-[O-:3]>>[N+0:1]-[*:2]=[O-0:3]', # '[N+:1]=[*:2]-[*:3]=[*:4]-[O-:5]>>[N+0:1]-[*:2]=[*:3]-[*:4]=[O-0:5]', # '[#8:1]=[#6:2]([!-:6])[*:3]=[*:4][#6-:5]>>[*-:1][*:2]([*:6])=[*:3][*:4]=[*+0:5]', # '[O:1]=[c:2][c-:3]>>[*-:1][*:2][*+0:3]', # '[O:1]=[C:2][C-:3]>>[*-:1][*:2]=[*+0:3]'] rxn_smarts = [ '[#6,#7:1]1=[#6,#7:2][#6,#7:3]=[#6,#7:4][CX3-,NX3-:5][#6,#7:6]1=[#6,#7:7]>>\ [#6,#7:1]1=[#6,#7:2][#6,#7:3]=[#6,#7:4][-0,-0:5]=[#6,#7:6]1[#6-,#7-:7]', '[#6,#7:1]1=[#6,#7:2][#6,#7:3](=[#6,#7:4])[#6,#7:5]=[#6,#7:6][CX3-,NX3-:7]1>>\ [#6,#7:1]1=[#6,#7:2][#6,#7:3]([#6-,#7-:4])=[#6,#7:5][#6,#7:6]=[-0,-0:7]1' ] fragments = Chem.GetMolFrags(mol, asMols=True, sanitizeFrags=False) for i, fragment in enumerate(fragments): for smarts in rxn_smarts: patt = Chem.MolFromSmarts(smarts.split(">>")[0]) while fragment.HasSubstructMatch(patt): rxn = AllChem.ReactionFromSmarts(smarts) ps = rxn.RunReactants((fragment, )) fragment = ps[0][0] Chem.SanitizeMol(fragment) #print(Chem.MolToSmiles(fragment)) if i == 0: mol = fragment else: mol = Chem.CombineMols(mol, fragment) return mol
def clean_charges(mol): # this is a temporary hack. The real solution is to generate several BO matrices in AC2BO and pick the one # with the lowest number of atomic charges # #print 'clean_charges',Chem.MolToSmiles(mol) rxn_smarts = [ '[N+:1]=[*:2]-[O-:3]>>[N+0:1]-[*:2]=[O-0:3]', '[N+:1]=[*:2]-[*:3]=[*:4]-[O-:5]>>[N+0:1]-[*:2]=[*:3]-[*:4]=[O-0:5]', '[#8:1]=[#6:2]([!-:6])[*:3]=[*:4][#6-:5]>>[*-:1][*:2]([*:6])=[*:3][*:4]=[*+0:5]', '[O:1]=[c:2][c-:3]>>[*-:1][*:2][*+0:3]', '[O:1]=[C:2][C-:3]>>[*-:1][*:2]=[*+0:3]' ] fragments = Chem.GetMolFrags(mol, asMols=True) for i, fragment in enumerate(fragments): for smarts in rxn_smarts: patt = Chem.MolFromSmarts(smarts.split(">>")[0]) while fragment.HasSubstructMatch(patt): rxn = AllChem.ReactionFromSmarts(smarts) ps = rxn.RunReactants((fragment, )) fragment = ps[0][0] if i == 0: mol = fragment else: mol = Chem.CombineMols(mol, fragment) #print Chem.MolToSmiles(mol) return mol
def clean_charges(mol): # this hack should not be needed any more but is kept just in case # rxn_smarts = [ '[N+:1]=[*:2]-[C-:3]>>[N+0:1]-[*:2]=[C-0:3]', '[N+:1]=[*:2]-[O-:3]>>[N+0:1]-[*:2]=[O-0:3]', '[N+:1]=[*:2]-[*:3]=[*:4]-[O-:5]>>[N+0:1]-[*:2]=[*:3]-[*:4]=[O-0:5]', '[#8:1]=[#6:2]([!-:6])[*:3]=[*:4][#6-:5]>>[*-:1][*:2]([*:6])=[*:3][*:4]=[*+0:5]', '[O:1]=[c:2][c-:3]>>[*-:1][*:2][*+0:3]', '[O:1]=[C:2][C-:3]>>[*-:1][*:2]=[*+0:3]' ] fragments = Chem.GetMolFrags(mol, asMols=True, sanitizeFrags=False) for i, fragment in enumerate(fragments): for smarts in rxn_smarts: patt = Chem.MolFromSmarts(smarts.split(">>")[0]) while fragment.HasSubstructMatch(patt): rxn = AllChem.ReactionFromSmarts(smarts) ps = rxn.RunReactants((fragment, )) fragment = ps[0][0] if i == 0: mol = fragment else: mol = Chem.CombineMols(mol, fragment) return mol
def ModifyMolInPlace(self, reactants): # This applies transformation for all the matching pattern found in mol if len(self.reactantquery) != 1: raise ReactionQueryError('ModifyMolInPlace: Only usable for', 'monomolecular transformation') if isinstance(reactants, Chem.Mol): reactants = [reactants] elif isinstance(reactants, tuple): reactants = list(reactants) # Error test if len(reactants) != len(self.reactantquery): raise ReactionQueryError('Number of reactant mis-match') for i in range(0, len(reactants)): if not isinstance(reactants[i], Chem.Mol): raise ReactionQueryError("Unrecognized instance'" + type(reactants[i]) + "'") reactants[i] = Chem.AddHs(reactants[i]) # make matrix of matching index self.match_indexes = list() i = 0 for reactant_name in self.reactantquery: if isinstance(self.reactantquery[reactant_name], Chem.Mol): match = reactants[i].GetSubstructMatches( self.reactantquery[reactant_name]) if not match: return tuple() else: self.match_indexes.append(match) elif isinstance(self.reactantquery[reactant_name], MolQuery): match = self.reactantquery[reactant_name].\ GetQueryMatches(reactants[i]) if not match: return tuple() else: self.match_indexes.append(match) i += 1 # make a index for combined reactants mol object self.combined_mol_match_index = list() for match in itpd(*self.match_indexes): row = list() modifier = 0 for i in range(0, len(match)): if i != 0: modifier = reactants[i - 1].GetNumAtoms() row += list( map(add, list(match[i]), [modifier] * len(match[i]))) self.combined_mol_match_index.append(row) # Combine reactants self.combined_mol = reactants[0] for i in range(1, len(reactants)): self.combined_mol = Chem.CombineMols(self.combined_mol, reactants[i]) self.combined_mol = Chem.RWMol(self.combined_mol) # Transform!! product_list = list() for matches in self.combined_mol_match_index: for transform in self.transformations: transform(self.combined_mol, matches) return self.combined_mol
def single_point_crossover(m1, m2, bf): '''single point crossover for rings''' crossed_mols = [] n1 = random.randint(1, 4) cp1 = return_cut_points(m1) cp2 = return_cut_points(m2) actual_cp1 = get_actual_cut_pts(m1, n1, cp1) actual_cp2 = get_actual_cut_pts(m2, n1, cp2) frags1 = frag_mol(m1, actual_cp1, bf) frags2 = frag_mol(m2, actual_cp2, bf) temp_mol1 = Chem.CombineMols(frags1[0], frags2[1]) temp_mol2 = Chem.CombineMols(frags2[0], frags1[1]) crossed_mol1 = join_mols(temp_mol1) crossed_mol2 = join_mols(temp_mol2) crossed_mols.append(crossed_mol1) crossed_mols.append(crossed_mol2) return crossed_mols
def make_complex(mol): """ PRE: Takes in a molecule aligned with the macrocycle POST: combines it with the macrocycle and returns a complex molecule """ macrocycle=Chem.MolFromMolBlock(get_CB_BLOCK(), removeHs=False) complex_CB_guest = Chem.CombineMols(mol, macrocycle) return complex_CB_guest
def NormalCrossover(m1, m2): #Fragment molecules m1fs = GetFragment(m1) m2fs = GetFragment(m2) #pick fragments for crossover checking: # 1. Molecular weight Choices = [] #maxWeight = mprms.maxWeight if maxWeight > 0: w1 = [Descriptors.MolWt(f) for f in m1fs] w2 = [Descriptors.MolWt(f) for f in m2fs] for i, j in ((i, j) for i in xrange(2) for j in xrange(2)): if w1[i] + w2[j] < maxWeight + 50.0: Choices.append((i, j)) # 2. Number of Atoms #MxAtm=mprms.MxAtm if MxAtm > 0: a1 = [f.GetNumAtoms() for f in m1fs] a2 = [f.GetNumAtoms() for f in m2fs] for i, j in ((i, j) for i in xrange(2) for j in xrange(2)): if a1[i] + a2[j] < MxAtm + 4: Choices.append((i, j)) if len(Choices) == 0: raise MutateFail() else: choice = random.choice(Choices) mol1 = m1fs[choice[0]] mol2 = m2fs[choice[1]] # now mol2 has to be connected to mol1 # but what happens here? mol1.SetProp('parent1', m1.GetProp('isosmi')) mol2.SetProp('parent2', m2.GetProp('isosmi')) #Append molecule 2 to molecule 1. newmol = Chem.CombineMols(mol1, mol2) newids = Chem.GetMolFrags(newmol) # Now, bond the two fragments to create the child molecule. # We choose a random pair of possible atoms to do the attachment; possibleA1 = [ atom for atom in GetIAtoms(newids[0], newmol) if EmptyValence(atom) > 0 ] possibleA2 = [ atom for atom in GetIAtoms(newids[1], newmol) if EmptyValence(atom) > 0 ] if len(possibleA1) == 0 or len(possibleA2) == 0: #print "no possible atoms!" raise MutateFail() newmolRW = Chem.RWMol(newmol) atom1 = random.choice(possibleA1) atom2 = random.choice(possibleA2) newmolRW.AddBond(atom1.GetIdx(), atom2.GetIdx(), Chem.BondType.SINGLE) #print "new mol!", Chem.MolToSmiles(newmolRW) mol = newmolRW.GetMol() return mol
def join(scaffold_smi, decoration_smi, keep_label_on_atoms=False): """ Joins a SMILES scaffold with a decoration. They must be labelled. :param scaffold_smi: SMILES of the scaffold. :param decoration_smi: SMILES of the decoration. :param keep_label_on_atoms: Add the labels to the atoms after attaching the molecule. This is useful when debugging, but it can give problems. :return: A Mol object of the joined scaffold. """ scaffold = uc.to_mol(scaffold_smi) decoration = uc.to_mol(decoration_smi) if scaffold and decoration: # obtain id in the decoration try: attachment_points = [atom.GetProp("molAtomMapNumber") for atom in decoration.GetAtoms() if atom.GetSymbol() == ATTACHMENT_POINT_TOKEN] if len(attachment_points) != 1: return None # more than one attachment point... attachment_point = attachment_points[0] except KeyError: return None combined_scaffold = rkc.RWMol(rkc.CombineMols(decoration, scaffold)) attachments = [atom for atom in combined_scaffold.GetAtoms() if atom.GetSymbol() == ATTACHMENT_POINT_TOKEN and atom.HasProp("molAtomMapNumber") and atom.GetProp("molAtomMapNumber") == attachment_point] if len(attachments) != 2: return None # something weird neighbors = [] for atom in attachments: if atom.GetDegree() != 1: return None # the attachment is wrongly generated neighbors.append(atom.GetNeighbors()[0]) bonds = [atom.GetBonds()[0] for atom in attachments] bond_type = rkc.BondType.SINGLE if any(bond for bond in bonds if bond.GetBondType() == rkc.BondType.DOUBLE): bond_type = rkc.BondType.DOUBLE combined_scaffold.AddBond(neighbors[0].GetIdx(), neighbors[1].GetIdx(), bond_type) combined_scaffold.RemoveAtom(attachments[0].GetIdx()) combined_scaffold.RemoveAtom(attachments[1].GetIdx()) if keep_label_on_atoms: for neigh in neighbors: _add_attachment_point_num(neigh, attachment_point) scaffold = combined_scaffold.GetMol() try: rkc.SanitizeMol(scaffold) except ValueError: # sanitization error return None else: return None return scaffold
def test_dual_topology_standard_decoupling(): # this class is used in double decoupling stages of the RABFE protocol. It modifies the # DualTopology class in one ways: # 1) the nonbonded terms are interpolated at lambda=0 such that the epsilons and charges are at half strength. ff = Forcefield.load_from_file("smirnoff_1_1_0_sc.py") mol_a = Chem.AddHs(Chem.MolFromSmiles("c1ccccc1O")) mol_b = Chem.AddHs(Chem.MolFromSmiles("c1ccccc1F")) mol_c = Chem.CombineMols(mol_a, mol_b) mol_top = topology.DualTopologyStandardDecoupling(mol_a, mol_b, ff) decouple_torsion_params, torsion_potential = mol_top.parameterize_proper_torsion( ff.pt_handle.params) combined_decouple_torsion_params, combined_torsion_potential = mol_top.parameterize_periodic_torsion( ff.pt_handle.params, ff.it_handle.params) assert len(combined_torsion_potential.get_lambda_mult()) == len( combined_torsion_potential.get_idxs()) assert len(combined_torsion_potential.get_lambda_mult()) == len( combined_torsion_potential.get_lambda_offset()) # impropers should always be turned on. # num_proper_torsions = len(torsion_potential.get_idxs()) assert np.all(combined_torsion_potential.get_lambda_mult() == 0) assert np.all(combined_torsion_potential.get_lambda_offset() == 1) qlj_params, nonbonded_potential = mol_top.parameterize_nonbonded( ff.q_handle.params, ff.lj_handle.params) assert isinstance(nonbonded_potential, potentials.NonbondedInterpolated) expected_qlj = topology.standard_qlj_typer(mol_c) expected_qlj[:, 0] = expected_qlj[:, 0] / 2 # charges should be halved expected_qlj[:, 2] = expected_qlj[:, 2] / 2 # eps should be halved src_qlj_params = qlj_params[:len(qlj_params) // 2] dst_qlj_params = qlj_params[len(qlj_params) // 2:] np.testing.assert_array_equal(src_qlj_params, expected_qlj) expected_qlj = topology.standard_qlj_typer(mol_c) np.testing.assert_array_equal(dst_qlj_params, expected_qlj) combined_lambda_plane_idxs = nonbonded_potential.get_lambda_plane_idxs() combined_lambda_offset_idxs = nonbonded_potential.get_lambda_offset_idxs() A = mol_a.GetNumAtoms() B = mol_b.GetNumAtoms() C = mol_c.GetNumAtoms() np.testing.assert_array_equal(combined_lambda_plane_idxs, np.zeros(C)) np.testing.assert_array_equal(combined_lambda_offset_idxs[:A], np.zeros(A)) np.testing.assert_array_equal(combined_lambda_offset_idxs[A:], np.ones(B))
def make_peptide_bond(mol, res=None, start="N", end="C", delete="OXT"): """Performs one condesation rxn between a molecule and residue/itself default creates peptide bond Parameters ---------- mol : rdkmol Main molecule on which reaction is performed res : rdkmol None or a single residue, when it is None, self-condensation is performed on @mol start : str atom name of one of the two atoms to which connection is established end : str atom name of the other atom to which connection is established delete : str default to hydroxy oxygen thats eliminated during condensation Returns ------- mol : rdkmol modified molecule """ startIdx, endIdx, deleteIdx = -1, -1, -1 for idx, atm in enumerate(mol.GetAtoms( )): # get the last occurence of end and delete atomname if atm.GetPDBResidueInfo().GetName().strip() == end: endIdx = idx elif atm.GetPDBResidueInfo().GetName().strip() == delete: deleteIdx = idx if res is not None: #residue addition lastResNum = -1 for idx, atm in enumerate(mol.GetAtoms()): lastResNum = atm.GetPDBResidueInfo().GetResidueNumber() lastResNum += 1 for idx, atm in enumerate( res.GetAtoms()): #get the last occurence of start atomname atm.GetPDBResidueInfo().SetResidueNumber(lastResNum) if atm.GetPDBResidueInfo().GetName().strip() == start: startIdx = idx startIdx += mol.GetNumAtoms() mol = Chem.CombineMols(mol, res) else: #cyclisation for idx, atm in enumerate( mol.GetAtoms()): #get the first occurence of start atomname if atm.GetPDBResidueInfo().GetName().strip() == start: startIdx = idx break mol = Chem.RWMol(mol) mol.AddBond(startIdx, endIdx, Chem.BondType.SINGLE) mol.RemoveAtom(deleteIdx) mol.UpdatePropertyCache() Chem.GetSSSR(mol) return mol.GetMol()
def RunReactants(self, reactants): if isinstance(reactants,Chem.Mol): reactants = [reactants] elif isinstance(reactants,tuple): reactants = list(reactants) # Error test if len(reactants) != len(self.reactantquery): raise ReactionQueryError('Number of reactant mis-match') for i in xrange(0,len(reactants)): if not isinstance(reactants[i],Chem.Mol): raise ReactionQueryError("Unrecognized instance'"+type(reactants[i])+"'") reactants[i] = Chem.AddHs(reactants[i]) # make matrix of matching index self.match_indexes = list() i = 0 for reactant_name in self.reactantquery: if isinstance(self.reactantquery[reactant_name],Chem.Mol): match = reactants[i].GetSubstructMatches(self.reactantquery[reactant_name]) if not match: return tuple() else: self.match_indexes.append(match) elif isinstance(self.reactantquery[reactant_name],MolQuery): match = self.reactantquery[reactant_name].GetQueryMatches(reactants[i]) if not match: return tuple() else: self.match_indexes.append(match) i += 1 # make a index for combined reactants mol object self.combined_mol_match_index = list() for match in itpd(*self.match_indexes): row = list() modifier = 0 for i in xrange(0,len(match)): if i != 0: modifier = reactants[i-1].GetNumAtoms() row += map(add,list(match[i]),[modifier]*len(match[i])) self.combined_mol_match_index.append(row) # Combine reactants self.combined_mol = reactants[0] for i in xrange(1,len(reactants)): self.combined_mol = Chem.CombineMols(self.combined_mol,reactants[i]) self.combined_mol = Chem.RWMol(self.combined_mol) # Transform!! product_list = list() for matches in self.combined_mol_match_index: products = self.combined_mol.__copy__() for transform in self.transformations: transform(products, matches) products = Chem.GetMolFrags(products,asMols=True,sanitizeFrags=False) product_list.append(products) return tuple(product_list)
def make_conformer(mol, conf_a, conf_b): mol.RemoveAllConformers() mol = Chem.CombineMols(mol, mol) cc = Chem.Conformer(mol.GetNumAtoms()) conf = np.concatenate([conf_a, conf_b]) conf *= 10 for idx, pos in enumerate(onp.asarray(conf)): cc.SetAtomPosition(idx, (float(pos[0]), float(pos[1]), float(pos[2]))) mol.AddConformer(cc) return mol
def sub_att(mainmol, fun_mol, pair): ls_submol = [] mainmol = Chem.MolFromSmiles(mainmol) for i in pair: combo = Chem.CombineMols(mainmol, fun_mol) edcombo = Chem.EditableMol(combo) edcombo.AddBond(i[0], i[1], order=Chem.rdchem.BondType.SINGLE) back = edcombo.GetMol() back = Chem.MolToSmiles(back, isomericSmiles=True, canonical=True) ls_submol.append(back) return ls_submol
def __gen_replacements(mol1, mol2, db_name, radius, dist=None, min_size=0, max_size=8, min_rel_size=0, max_rel_size=1, min_inc=-2, max_inc=2, max_replacements=None, replace_cycles=False, protected_ids_1=None, protected_ids_2=None, min_freq=10): def func(): for env, core, *ids in f: # if link = True ids is two tuples, if link = False ids is a single tuple num_heavy_atoms = Chem.MolFromSmiles(core).GetNumHeavyAtoms() hac_ratio = num_heavy_atoms / mol_hac if (min_size <= num_heavy_atoms <= max_size and min_rel_size <= hac_ratio <= max_rel_size) \ or (replace_cycles and cycle_pattern.search(core)): frag_sma = combine_core_env_to_rxn_smarts(core, env) min_atoms = num_heavy_atoms + min_inc max_atoms = num_heavy_atoms + max_inc rep = __get_replacements(cur, env, dist, min_atoms, max_atoms, radius, min_freq) for core_smi, core_sma, freq in rep: if core_smi != core: if link: yield frag_sma, core_sma, freq, ids[0], ids[1] else: yield frag_sma, core_sma, freq, ids[0] link = False if not isinstance(mol1, Chem.Mol): raise StopIteration("The first molecule in __gen_replacement always must be specified") if isinstance(mol1, Chem.Mol) and isinstance(mol2, Chem.Mol): link = True if link: f = __fragment_mol_link(mol1=mol1, mol2=mol2, radius=radius, protected_ids_1=protected_ids_1, protected_ids_2=protected_ids_2) mol = Chem.CombineMols(mol1, mol2) else: mol = mol1 f = __fragment_mol(mol, radius, protected_ids=protected_ids_1) mol_hac = mol.GetNumHeavyAtoms() con = sqlite3.connect(db_name) cur = con.cursor() if max_replacements is not None: res = list(func()) random.shuffle(res) for items in res[:max_replacements]: yield items else: for items in func(): yield items
def __init__(self, amine, carboxy): # Construct a editable Mol from modified Amine and Carboxylic acid edMol = Chem.EditableMol( Chem.CombineMols(amine.Modify(), carboxy.Modify())) atomIdxDict = {} # Match atom list indice to atom mapping numbers for i, atm in enumerate(edMol.GetMol().GetAtoms()): atomIdxDict[atm.GetAtomMapNum()] = i # Find attaching atoms by mapping number on each constituent mol and make a single bond edMol.AddBond(atomIdxDict[amine.reactAtom], atomIdxDict[carboxy.reactAtom], order=Chem.rdchem.BondType.SINGLE) #replace all single bond in the product as an arbitrary single bond (allow aromaticity) self.sma = Chem.MolToSmarts(edMol.GetMol()).replace( "-,:", '') #.replace("-", '') # Construct the final product super().__init__(Chem.MolFromSmarts(self.sma)) hA = "{" + amine.hybridization + "}" if amine.modifArg: aReac = "{" + { 1: 'A', 2: '\\alpha', 3: '\\beta' }[amine.reactAtom] + amine.modifArg + "}" else: aReac = "{" + { 1: 'A', 2: '\\alpha', 3: '\\beta' }[amine.reactAtom] + "}" hB = "{" + carboxy.hybridization + "}" if carboxy.modifArg: bReac = "{" + { 5: 'B[O]', 6: 'B[C]', 7: '\\alpha', 8: '\\beta' }[carboxy.reactAtom] + carboxy.modifArg + "}" else: bReac = "{" + { 5: 'B[O]', 6: 'B[C]', 7: '\\alpha', 8: '\\beta' }[carboxy.reactAtom] + "}" latexModStr = '$^{}{}^{}/^{}{}^{}$'.format(hA, '{NH_2}', aReac, hB, '{COOH}', bReac) self.SetProp('Modification', latexModStr)
def merge_CB_guest(mol): """Merges the CB7 structure taken from a saved file with the structure of the guest as computed The argments are a mol object for the guest structure and two flags gen_ETKDG and gen_no_chiral that indicate how and if the guest structure was converged""" # CB_HOST = Chem.SDMolSupplier('../CB_candidate.sdf', removeHs=False)[0] CB_HOST = Chem.MolFromMolBlock(get_CB_BLOCK(), removeHs=False) complex_cb_guest = Chem.CombineMols(CB_HOST, mol) Chem.GetSSSR(complex_cb_guest) # Dirty fix to avoid an error # ff = AllChem.MMFFGetMoleculeForceField(complex_cb_guest, pyMMFFMolProperties=AllChem.MMFFGetMoleculeProperties(complex_cb_guest), ignoreInterfragInteractions=False, nonBondedThresh=100.0) # converged = ff.Minimize(n_steps, tol, tol) # E_complex = ff.CalcEnergy() # converged = converge(complex_cb_guest) return complex_cb_guest
def join_total(frags): '''joins list of multiple fragments together, returns new mol''' print len(frags) join_pts = [0, 1, 2, 3] for x in join_pts: #print x if x == 0: temp_mol = Chem.CombineMols(frags[x], frags[x + 1]) atch_mol = join_mols(temp_mol) #r = atch_mol.GetRingInfo() #print r.NumRings() continue if x == 4: break else: temp_mol = Chem.CombineMols(atch_mol, frags[x + 1]) new_atch_mol = join_mols(temp_mol) #r = new_atch_mol.GetRingInfo() #print r.NumRings() atch_mol = new_atch_mol return atch_mol
def combine(skeleton, arm): ''' combine a skeleton and an arm to form a complete molecule graph TODO: the smiles representations are different after combining, might because the node index is different TODO: unstandardized molecules fail to get features ''' mol = Chem.CombineMols(skeleton.mol, arm.mol) mol = Chem.RWMol(mol) u = skeleton.u v = skeleton.mol.GetNumAtoms() + arm.v mol.AddBond(u, v, arm.bond_type) return mol.GetMol()
def make_conformer(mol, conf_a, conf_b): """Remove all of mol's conformers, make a new mol containing two copies of mol, assign positions to each copy using conf_a and conf_b, respectively, assumed in nanometers""" mol.RemoveAllConformers() mol = Chem.CombineMols(mol, mol) cc = Chem.Conformer(mol.GetNumAtoms()) conf = np.concatenate([conf_a, conf_b]) conf *= 10 # TODO: label this unit conversion? for idx, pos in enumerate(np.asarray(conf)): cc.SetAtomPosition(idx, (float(pos[0]), float(pos[1]), float(pos[2]))) mol.AddConformer(cc) return mol
def combine_core_env_to_rxn_smarts(core, env, keep_h=True): if isinstance(env, str): m_env = Chem.MolFromSmiles(env, sanitize=False) if isinstance(core, str): m_frag = Chem.MolFromSmiles(core, sanitize=False) backup_atom_map = "backupAtomMap" # put all atom maps to atom property and remove them for a in m_env.GetAtoms(): atom_map = a.GetAtomMapNum() if atom_map: a.SetIntProp(backup_atom_map, atom_map) a.SetAtomMapNum(0) for a in m_frag.GetAtoms(): atom_map = a.GetAtomMapNum() if atom_map: a.SetIntProp(backup_atom_map, atom_map) a.SetAtomMapNum(0) # set canonical ranks for atoms in env without maps m_env.UpdatePropertyCache() for atom_id, rank in zip([a.GetIdx() for a in m_env.GetAtoms()], list(Chem.CanonicalRankAtoms(m_env))): a = m_env.GetAtomWithIdx(atom_id) if not a.HasProp(backup_atom_map): a.SetAtomMapNum(rank + 1) # because ranks start from 0 m = Chem.RWMol(Chem.CombineMols(m_frag, m_env)) links = defaultdict(list) # pairs of atom ids to create bonds att_to_remove = [] # ids of att points to remove for a in m.GetAtoms(): if a.HasProp(backup_atom_map): i = a.GetIntProp(backup_atom_map) links[i].append(a.GetNeighbors()[0].GetIdx()) att_to_remove.append(a.GetIdx()) for i, j in links.values(): m.AddBond(i, j, Chem.BondType.SINGLE) for i in sorted(att_to_remove, reverse=True): m.RemoveAtom(i) comb_sma = mol_to_smarts(m, keep_h) if not keep_h: # remove H only in mapped env part comb_sma = patt_remove_h.sub('', comb_sma) return comb_sma
def add_custom_fragment(childGenes, GeneSet, oldGene): geneSet = GeneSet.CustomFrags newGene = Chromosome(geneSet.GetEntryDescription(\ random.sample(range(geneSet.GetNumEntries()), 1)[0]),0) oldGene = oldGene + newGene.Mol.GetNumAtoms() combined = Chem.EditableMol( Chem.CombineMols(newGene.Mol, childGenes.Mol)) combined.AddBond(0, oldGene, order=Chem.rdchem.BondType.SINGLE) childGenes = combined.GetMol() try: childGenes = Chromosome(Chem.MolToSmiles(childGenes), 0) return childGenes except: return 0
def validate_dataset(self): x_complex = [] for pdb_code, ligand, pocket in zip(self.pdb_code, self.x_ligand, self.x_pocket): Chem.RemoveHs(ligand) Chem.RemoveHs(pocket) complx = Chem.CombineMols(ligand, pocket) complx.SetProp('_Name', '{}_complex'.format(pdb_code)) x_complex.append(complx) # Validate self.exclude = [] for mol in x_complex: print("Validating {}".format(mol.GetProp('_Name'))) dist = [] coordinates = np.array([ list(mol.GetConformer().GetAtomPosition(j)) for j in range(mol.GetNumAtoms()) ]) for i in range(mol.GetNumAtoms()): for j in range(i, mol.GetNumAtoms()): if i == j: continue dist.append(np.linalg.norm(coordinates[i] - coordinates[j])) dist = np.array(dist) if len(dist[dist < 1]) > 0: self.exclude.append(mol.GetProp('_Name').split('_')[0]) # Collect results code_new, ligands_new, pockets_new = [], [], [] for pdb_code, ligand, pocket in zip(self.pdb_code, self.x_ligand, self.x_pocket): if pdb_code in self.exclude: continue else: code_new.append(pdb_code) ligands_new.append(ligand) pockets_new.append(pocket) self.pdb_code, self.x_ligand, self.x_pocket = code_new, ligands_new, pockets_new # Save w = Chem.SDWriter('../data/ligand_filtered.sdf') for mol in self.x_ligand: w.write(mol) w = Chem.SDWriter('../data/pocket_filtered.sdf') for mol in self.x_pocket: w.write(mol) print("Molecules Validated")