def add_terminal_atom(mol, condition, newAtomicNumber, newAtomInfo=lambda atm: Chem.AtomMonomerInfo(), aromatic=lambda atm: False, bondType=1): #TODO make bondType also a function? """create new atom(s) based on expression Parameters: ---------- mol : rdkmol Main moelcule one which addition is perforemd condition : function outputs how many atoms to add at each atom site of @mol newAtomicNumber : function outputs element types to add at each atom site of @mol newAtomInfo : function outputs the rdkit AtomInfo block information add at each atom site of @mol aromatic : function True/False value for atom aromaticity bondType : float Returns ------- mol : rdkmol modified molecule Example: -------- residue = Chem.MolFromSequence("KK", flavor = 0) residue = add_terminal_atom(mol = residue, condition = lambda atm: atm.GetPDBResidueInfo().GetName().strip() == "N", newAtomName = lambda atm : "CN", newAtomicNumber = lambda atm: 6) print(Chem.MolToPDBBlock(residue)) """ def mapper(condition, mol): for idx, repeats in enumerate(map(condition, mol.GetAtoms())): for j in range(repeats): yield mol.GetAtomWithIdx(idx) bondType = _bondtypes[bondType] mol = Chem.RWMol(mol) for atom in mapper(condition, copy.deepcopy(mol)): newatom = Chem.Atom(newAtomicNumber(atom)) newatom.SetIsAromatic(aromatic(atom)) newatom.SetMonomerInfo(newAtomInfo(atom)) # newatom.SetMonomerInfo(Chem.AtomPDBResidueInfo(atomName = " {: <3s}".format(newAtomName(atom)), # residueName = atom.GetPDBResidueInfo().GetResidueName(), # residueNumber = atom.GetPDBResidueInfo().GetResidueNumber(), # chainId = atom.GetPDBResidueInfo().GetChainId(), # )) mol.AddAtom(newatom) mol.AddBond(atom.GetIdx(), mol.GetNumAtoms() - 1, bondType) # mol.UpdatePropertyCache(strict = False) mol.UpdatePropertyCache() Chem.GetSSSR(mol) return mol.GetMol()