def test_02_getMissingValence(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) PT = PeriodicTable() atom_formalcharge = sm.formalcharge[BENZAMIDINE_N_CHARGED_IDX] omv = PT.getMissingValence(sm, BENZAMIDINE_N_CHARGED_IDX, formalcharge=atom_formalcharge) self.assertEqual(omv, BENZAMIDINE_N_CHARGED_MISSING_VALENCE, msg="The missing valence for the N charged is not " "as expected") sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=False, fixHs=False) n_idx = np.where(sm.element == 'N')[0][0] n_formalcharge = sm.formalcharge[n_idx] omv = PT.getMissingValence(sm, n_idx, formalcharge=n_formalcharge) self.assertEqual(omv, ETANOLAMMINE_N_MISSING_VALENCE, msg="The missing valence for the N is not " "as expected")
def test_06_isChiral(self): smi = CHIRAL_SMI sm = SmallMol(smi) ischiral, details = sm.isChiral(returnDetails=True) self.assertListEqual( details, CHIRAL_DETAILS, 'chiral atom does not match.' 'Expected: {}; Now: {}'.format(CHIRAL_DETAILS, details))
def test_08_removeHydrogens(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) sm_c = sm.copy() b = Builder(sm_c) b.removeHydrogens() sm_b = b.getSmallMol() sm_b_element = sm_b.element.tolist() self.assertListEqual(sm_b_element, BENZAMIDINE_ELEMENTS_NOHS) sm_c = sm.copy() b = Builder(sm_c) b.removeHydrogens(removeNonPolars=False) sm_b = b.getSmallMol() sm_b_element = sm_b.element.tolist() self.assertListEqual(sm_b_element, BENZAMIDINE_ELEMENTS_NO_POLARHS) sm_c = sm.copy() b = Builder(sm_c) b.removeHydrogens(removePolars=False) sm_b = b.getSmallMol() sm_b_element = sm_b.element.tolist() self.assertListEqual(sm_b_element, BENZAMIDINE_ELEMENTS_NO_NONPOLARHS)
def test_08_removeHydrogens(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) sm_c = sm.copy() b = Builder(sm_c) b.removeHydrogens() sm_b = b.getSmallMol() sm_b_element = sm_b.element.tolist() self.assertListEqual(sm_b_element, BENZAMIDINE_ELEMENTS_NOHS) sm_c = sm.copy() b = Builder(sm_c) b.removeHydrogens(removeNonPolars=False) sm_b = b.getSmallMol() sm_b_element = sm_b.element.tolist() self.assertListEqual(sm_b_element, BENZAMIDINE_ELEMENTS_NO_POLARHS) sm_c = sm.copy() b = Builder(sm_c) b.removeHydrogens(removePolars=False) sm_b = b.getSmallMol() sm_b_element = sm_b.element.tolist() self.assertListEqual(sm_b_element, BENZAMIDINE_ELEMENTS_NO_NONPOLARHS)
def test_06_getSmallMol(self): sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=True, fixHs=False) sm_c = sm.copy() b = Builder(sm_c) sm_b = b.getSmallMol() self.assertIsInstance(sm_b, SmallMol, msg="The molecule was not loaded correctly")
def test_14_getBonds(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) bonds, bondstype = sm.getBonds() self.assertListEqual(bonds.tolist(), BENZAMIDINE_BOND_ATOMS, msg="The atoms in bonds are not the same of the reference") self.assertListEqual(bondstype.tolist(), BENZAMIDINE_BONDTYPES, msg="The bonds type are not the same of the reference")
def test_08_generateConformers(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) current_conformer = sm.numConformers sm.generateConformers(num_confs=10, append=False) n_conformers = sm.numConformers self.assertGreater(n_conformers, current_conformer, 'The generation of conforemr should provide at least the ' 'same amount of conformer')
def test_06_getSmallMol(self): sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=True, fixHs=False) sm_c = sm.copy() b = Builder(sm_c) sm_b = b.getSmallMol() self.assertIsInstance(sm_b, SmallMol, msg="The molecule was not loaded correctly")
def test_09_writeGenerateAndWriteConformers(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) sm.generateConformers(num_confs=10, append=False) tmpdir = NamedTemporaryFile().name sm.writeConformers(savefolder=tmpdir) direxists = os.path.isdir(tmpdir) n_files = len(glob(os.path.join(tmpdir, '*.sdf'))) self.assertTrue(direxists, 'The directory where to store the conformations where not created') self.assertGreater(n_files, 1, 'None conformations were written. At least one should be present')
def test_07_foundBond(self): smi = FOUNDBOND_SMI sm = SmallMol(smi) isbond_0_N = sm.foundBondBetween('idx 0', 'element N') isbond_0_1_single = sm.foundBondBetween('idx 0', 'idx 1', bondtype=1) isbond_0_1_double, _ = sm.foundBondBetween('idx 0', 'idx 1', bondtype=2) self.assertFalse(isbond_0_N, 'Bond between atom 0 and any nitrogens should not be present') self.assertFalse(isbond_0_1_single, 'Bond between atom 0 1 should not be single') self.assertTrue(isbond_0_1_double, 'Bond between atom 0 1 should be double')
def test_08_generateConformers(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) current_conformer = sm.numConformers sm.generateConformers(num_confs=10, append=False) n_conformers = sm.numConformers self.assertGreater( n_conformers, current_conformer, 'The generation of conforemr should provide at least the ' 'same amount of conformer')
def test_13_convertToMolecule(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) mol = Molecule(mol2file) mol_elements = mol.element.tolist() sm_htmd = sm.toMolecule() sm_htmd_element = sm_htmd.element.tolist() self.assertListEqual(sm_htmd_element, mol_elements, msg="The elements found are different. The handle and convertion" "of the SmallMol object into the htmd.Molecule one, probably " "get wrong")
def test_05_Builder_load(self): sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=True, fixHs=False) sm_c = sm.copy() b = Builder() b.loadMol(sm_c) sm_b = b.getSmallMol() expectedFalse = np.array_equal(sm_b.coords, sm.coords) self.assertIsInstance(b, Builder, msg="The molecule was not creted in the Builder") self.assertFalse(expectedFalse, msg="A initial conformation was not created")
def test_12_convertToRdkit(self): smimol = SMILE_SMI sm = SmallMol(smimol, removeHs=True, fixHs=False) mrd = MolFromSmiles(smimol) mrd_natom = mrd.GetNumAtoms() sm_rd = sm.toRdkitMol(includeConformer=True) sm_rd_natoms = sm_rd.GetNumAtoms() self.assertIsInstance(sm_rd, rdkit.Chem.rdchem.Mol, msg="The conversion of the SmallMol object into the rdkit" "Mol one get wrong") self.assertEqual(sm_rd_natoms, mrd_natom, msg="NUmber of atoms different. The handle and convertion of the " "SmallMol object into the rdkit Mol one probably get wrong")
def test_05_getAtoms(self): smi = SMILE_SMI sm = SmallMol(smi) element_idx_1 = sm.get('element', 'idx 1')[0] neighbors_element_O = sm.get('neighbors', 'element O')[0] btypes_element_O = sm.get('bondtypes', 'element O', convertType=False)[0] self.assertEqual(element_idx_1, PHENOL_ELEMENT_IDX_1, 'Element of the first atom does not correspond' 'Expect: {}; Now: {}'.format(element_idx_1, PHENOL_ELEMENT_IDX_1)) self.assertListEqual(neighbors_element_O, PHENOL_ELEMENT_NEIGHBORS_OX, 'Neighbors atoms of the oxygen atom do not correspond' 'Expected: {}; Now: {}'.format(PHENOL_ELEMENT_NEIGHBORS_OX, neighbors_element_O)) self.assertListEqual(btypes_element_O, PHENOL_BTYPES_OX, 'Bondtypes of the oxygen atom do not correspond:' 'Expeected: {}; Now: {}'.format(btypes_element_O, PHENOL_BTYPES_OX))
def test_14_getBonds(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) bonds, bondstype = sm.getBonds() self.assertListEqual( bonds.tolist(), BENZAMIDINE_BOND_ATOMS, msg="The atoms in bonds are not the same of the reference") self.assertListEqual( bondstype.tolist(), BENZAMIDINE_BONDTYPES, msg="The bonds type are not the same of the reference")
def test_13_convertToMolecule(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) mol = Molecule(mol2file) mol_elements = mol.element.tolist() sm_htmd = sm.toMolecule() sm_htmd_element = sm_htmd.element.tolist() self.assertListEqual( sm_htmd_element, mol_elements, msg="The elements found are different. The handle and convertion" "of the SmallMol object into the htmd.Molecule one, probably " "get wrong")
def test_05_Builder_load(self): sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=True, fixHs=False) sm_c = sm.copy() b = Builder() b.loadMol(sm_c) sm_b = b.getSmallMol() expectedFalse = np.array_equal(sm_b.coords, sm.coords) self.assertIsInstance(b, Builder, msg="The molecule was not creted in the Builder") self.assertFalse(expectedFalse, msg="A initial conformation was not created")
def test_02_loadPdbfile(self): pdbfile = os.path.join(self.dataDir, 'ligand.pdb') sm = SmallMol(pdbfile) n_atoms = sm.numAtoms self.assertEqual( n_atoms, LIGAND_N_ATOMS, 'Atoms not correctly loaded. ' 'Expected: {}; Now: {}'.format(LIGAND_N_ATOMS, n_atoms))
def filter_tautomers(tautomers, scores, threshold=2): """ The function returns the tautomers as rdkit molecule objects based on the scores and the threshold Parameters ---------- tautomers: list - List of rdkit.Chem.Molecule of the tautomers identified scores: list - List of the scores for each tatutomer threshold: int - The threshold value to be used as difference from the highest one Returns ------- t_filtered: list - List of rdkit.Chem.Molecule of the tautomers filtered """ tautomers = [ mol._mol if isinstance(mol, SmallMol) else mol for mol in tautomers ] tautomers_sorted = [ x for _, x in sorted( zip(scores, tautomers), key=lambda pair: pair[0], reverse=True) ] scores.sort(reverse=True) t_filterd = [ t for t, s in zip(tautomers_sorted, scores) if s >= max(scores) - threshold ] return [SmallMol(rdmol) for rdmol in t_filterd]
def test_07_foundBond(self): smi = FOUNDBOND_SMI sm = SmallMol(smi) isbond_0_N = sm.foundBondBetween('idx 0', 'element N') isbond_0_1_single = sm.foundBondBetween('idx 0', 'idx 1', bondtype=1) isbond_0_1_double, _ = sm.foundBondBetween('idx 0', 'idx 1', bondtype=2) self.assertFalse( isbond_0_N, 'Bond between atom 0 and any nitrogens should not be present') self.assertFalse(isbond_0_1_single, 'Bond between atom 0 1 should not be single') self.assertTrue(isbond_0_1_double, 'Bond between atom 0 1 should be double')
def test_15_depict(self): import IPython refimg = os.path.join(self.dataDir, 'benzamidine.svg') mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) img_name = NamedTemporaryFile().name + '.svg' sm.depict(sketch=True, filename=img_name) _img = sm.depict(sketch=True, ipython=True) refimg_size = os.path.getsize(refimg) sm_img_size = os.path.getsize(img_name) self.assertIsInstance(_img, IPython.core.display.SVG, msg="The object is not an IPython image as expected") self.assertEqual(sm_img_size, refimg_size, msg="The svg image does not have the same size of the reference")
def getChemblSimilarLigandsBySmile(smi, threshold=85, returnSmiles=False): """ Returns a SmallMolLib object of the ligands having a similarity with a smile of at least the specified threshold.. This molecules are retrieve from Chembl. It is possible to return also the list smiles. Parameters ---------- smi: str The smile threshold: int The threshold value to apply for the similarity search returnSmiles: bool If True, the list smiles is returned Returns ------- sm: htmd.smallmol.smallmol.SmallMol The SmallMol object smiles: str The list of smiles Example ------- >>> _, smile = getChemblLigandByDrugName('ibuprofen', returnSmile=True) # doctest: +SKIP >>> lib = getChemblSimilarLigandsBySmile(smile) # doctest: +SKIP >>> lib.numMols # doctest: +SKIP 4 >>> lib, smiles = getChemblSimilarLigandsBySmile(smile, returnSmiles=True) # doctest: +SKIP >>> len(smiles) # doctest: +SKIP 4 """ from htmd.smallmol.smallmol import SmallMolLib, SmallMol try: from chembl_webresource_client.new_client import new_client except ImportError as e: raise ImportError( 'You need to install the chembl_webresource package to use this function. Try using `conda install ' '-c chembl chembl_webresource_client`.') smi_list = [] similarity = new_client.similarity results = similarity.filter(smiles=smi, similarity=threshold).only(['molecule_structures']) results = results.all() for r in range(len(results)): tmp_smi = results[r]['molecule_structures']['canonical_smiles'] fragments = tmp_smi.split('.') fragments_len = [ len(fr) for fr in fragments ] fragment = fragments[fragments_len.index(max(fragments_len))] if fragment not in smi_list: smi_list.append(fragment) lib = SmallMolLib() for smi in smi_list: lib.appendSmallMol(SmallMol(smi)) if returnSmiles: return lib, smi_list return lib
def test_03_loadSmile(self): smi = SMILE_SMI sm = SmallMol(smi) n_atoms = sm.numAtoms self.assertEqual( n_atoms, SMILE_N_ATOMS, 'Atoms not correctly loaded. ' 'Expected: {}; Now: {}'.format(SMILE_N_ATOMS, n_atoms))
def test_01_loadMol2file(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) n_atoms = sm.numAtoms self.assertEqual( n_atoms, BENZAMIDINE_N_ATOMS, 'Atoms not correctly loaded. ' 'Expected: {}; Now: {}'.format(BENZAMIDINE_N_ATOMS, n_atoms))
def test_09_anglesMETHANE(self): sm = SmallMol(METHANE_SMILE, fixHs=False, removeHs=False) b = Builder(sm) b.addHydrogens() centercoords = sm.coords[0] setone = [sm.coords[1], sm.coords[2]] settwo = [sm.coords[2], sm.coords[3]] setthree = [sm.coords[3], sm.coords[4]] setfour = [sm.coords[4], sm.coords[1]] sets = [setone, settwo, setthree, setfour] angles = [] for s in sets: a1coords = s[0] a2coords = s[1] angle = calculateAngle(centercoords, a1coords, a2coords, deg=True) angles.append(angle) angle_sample = angles[0] equal_angles = Counter(angles)[METHANE_ANGLE] self.assertEqual( angle_sample, METHANE_ANGLE, msg="The computed angle is not the expected one. Probably atoms " "coords not correctly predict") self.assertEqual(equal_angles, 4, msg="Not all the angle have the same value.")
def test_10_angleETHENE(self): sm = SmallMol(ETHENE_SMILE, fixHs=False, removeHs=False) b = Builder(sm) b.addHydrogens() centercoords1 = sm.coords[0] centercoords2 = sm.coords[1] set1one = [sm.coords[1], sm.coords[2]] set1two = [sm.coords[2], sm.coords[3]] set1three = [sm.coords[3], sm.coords[1]] set2one = [sm.coords[0], sm.coords[4]] set2two = [sm.coords[4], sm.coords[5]] set2three = [sm.coords[5], sm.coords[0]] sets1 = [set1two, set1two, set1three] sets2 = [set2two, set2two, set2three] angles1 = [] for s in sets1: a1coords = s[0] a2coords = s[1] angle = calculateAngle(centercoords1, a1coords, a2coords, deg=True) angles1.append(angle) angles2 = [] for s in sets2: a1coords = s[0] a2coords = s[1] angle = calculateAngle(centercoords2, a1coords, a2coords, deg=True) angles2.append(angle) angle1_sample = angles1[0] equal1_angles = Counter(angles1)[ETHENE_ANGLE] angle2_sample = angles2[0] equal2_angles = Counter(angles2)[ETHENE_ANGLE] self.assertEqual( angle1_sample, ETHENE_ANGLE, msg="The computed angle is not the expected one. Probably atoms " "coords not correctly predict") self.assertEqual(equal1_angles, 3, msg="Not all the angle have the same value.") self.assertEqual( angle2_sample, ETHENE_ANGLE, msg="The computed angle is not the expected one. Probably atoms " "coords not correctly predict") self.assertEqual(equal2_angles, 3, msg="Not all the angle have the same value.")
def test_12_convertToRdkit(self): smimol = SMILE_SMI sm = SmallMol(smimol, removeHs=True, fixHs=False) mrd = MolFromSmiles(smimol) mrd_natom = mrd.GetNumAtoms() sm_rd = sm.toRdkitMol(includeConformer=True) sm_rd_natoms = sm_rd.GetNumAtoms() self.assertIsInstance( sm_rd, rdkit.Chem.rdchem.Mol, msg="The conversion of the SmallMol object into the rdkit" "Mol one get wrong") self.assertEqual( sm_rd_natoms, mrd_natom, msg="NUmber of atoms different. The handle and convertion of the " "SmallMol object into the rdkit Mol one probably get wrong")
def test_07_addHydrogens(self): sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=True, fixHs=False) sm_c = sm.copy() b = Builder(sm_c) b.addHydrogens() sm_b = b.getSmallMol() sm_b_elements = sm_b.element.tolist() self.assertListEqual(sm_b_elements, ETANOLAMMINE_ELEMENTS_ALL) sm_c = sm.copy() b = Builder(sm_c) b.addHydrogens(onlyExplicit=True) sm_b = b.getSmallMol() sm_b_elements = sm_b.element.tolist() self.assertListEqual(sm_b_elements, ETANOLAMMINE_ELEMENTS_POLARHS)
def test_07_addHydrogens(self): sm = SmallMol(ETANOLAMMINE_SMILE, removeHs=True, fixHs=False) sm_c = sm.copy() b = Builder(sm_c) b.addHydrogens() sm_b = b.getSmallMol() sm_b_elements = sm_b.element.tolist() self.assertListEqual(sm_b_elements, ETANOLAMMINE_ELEMENTS_ALL) sm_c = sm.copy() b = Builder(sm_c) b.addHydrogens(onlyExplicit=True) sm_b = b.getSmallMol() sm_b_elements = sm_b.element.tolist() self.assertListEqual(sm_b_elements, ETANOLAMMINE_ELEMENTS_POLARHS)
def test_11_invertChirality(self): molsmile = CHIRAL_SMI sm = SmallMol(molsmile) aname = CHIRAL_DETAILS[0][0] chiral = CHIRAL_DETAILS[0][1] aidx = sm.get('idx', 'atomname {}'.format(aname))[0] sm.invertChirality(aidx) newchiral = sm.isChiral(returnDetails=True)[1][0][-1] self.assertNotEqual(chiral, newchiral, msg="The chirality was not formally changed") sm.generateConformers(num_confs=1, append=False) m = sm.toMolecule() fname = NamedTemporaryFile().name + '.mol2' m.write(fname) sm2 = SmallMol(fname) newchiral_confirm = sm2.isChiral(returnDetails=True)[1][0][-1] self.assertEqual(newchiral, newchiral_confirm, msg="The chirality was not structurally changed")
def test_04_appendSmallMol(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sdffile = os.path.join(self.dataDir, 'fda_drugs_light.sdf') lib = SmallMolLib(sdffile) sm = SmallMol(mol2file) lib.appendSmallMol(sm) n_mol2_append = lib.numMols self.assertEqual(n_mol2_append, SDF_N_MOLS+1, msg="The number of molecules in the SmallMolLib is not as expected." "The mol2 were not correctly append. ")
def test_15_depict(self): import IPython refimg = os.path.join(self.dataDir, 'benzamidine.svg') mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) img_name = NamedTemporaryFile().name + '.svg' sm.depict(sketch=True, filename=img_name) _img = sm.depict(sketch=True, ipython=True) refimg_size = os.path.getsize(refimg) sm_img_size = os.path.getsize(img_name) self.assertIsInstance( _img, IPython.core.display.SVG, msg="The object is not an IPython image as expected") self.assertEqual( sm_img_size, refimg_size, msg="The svg image does not have the same size of the reference")
def test_05_getAtoms(self): smi = SMILE_SMI sm = SmallMol(smi) element_idx_1 = sm.get('element', 'idx 1')[0] neighbors_element_O = sm.get('neighbors', 'element O')[0] btypes_element_O = sm.get('bondtypes', 'element O', convertType=False)[0] self.assertEqual( element_idx_1, PHENOL_ELEMENT_IDX_1, 'Element of the first atom does not correspond' 'Expect: {}; Now: {}'.format(element_idx_1, PHENOL_ELEMENT_IDX_1)) self.assertListEqual( neighbors_element_O, PHENOL_ELEMENT_NEIGHBORS_OX, 'Neighbors atoms of the oxygen atom do not correspond' 'Expected: {}; Now: {}'.format(PHENOL_ELEMENT_NEIGHBORS_OX, neighbors_element_O)) self.assertListEqual( btypes_element_O, PHENOL_BTYPES_OX, 'Bondtypes of the oxygen atom do not correspond:' 'Expeected: {}; Now: {}'.format(btypes_element_O, PHENOL_BTYPES_OX))
def generate_representation(in_smile): """ Makes embeddings of Molecule. """ try: m = Chem.MolFromSmiles(in_smile) mh = Chem.AddHs(m) AllChem.EmbedMolecule(mh) Chem.AllChem.MMFFOptimizeMolecule(mh) m = Chem.RemoveHs(mh) mol = SmallMol(m) return mol except: # Rarely the conformer generation fails return None
def alignMol(smallmol, refmol): """ Return a new SmallMol object aligned to a refmol that can be a htmd.smallmol.smallmol.SmallMol or rdkit.Chem.rdchem.Mol. It removes all the conformers stored in the original object. Parameters ---------- smallmol: htmd.smallmol.smallmol.SmallMol The SmallMol object to align refmol: htmd.smallmol.smallmol.SmallMol or rdkit.Chem.rdchem.Mol The molecule to align to Return ------ newsmallmol: htmd.smallmol.smallmol.SmallMol a new SmallMol aligned to reference molecule """ from htmd.smallmol.smallmol import SmallMol from rdkit.Chem.rdMolAlign import GetO3A if isinstance(refmol, SmallMol): refmol = refmol.toRdkitMol(includeConformer=True) sm_rdkit = smallmol.toRdkitMol(includeConformer=True) pyO3A = GetO3A(sm_rdkit, refmol) rmsd = pyO3A.Align() print('Alignment with a RMSD of {}'.format(rmsd)) coords_new = sm_rdkit.GetConformer().GetPositions() sm_new = SmallMol(smallmol, fixHs=False) sm_new.removeConformers() sm_new.coords = coords_new[:, :, np.newaxis] return sm_new
def alignMol(smallmol, refmol): """ Return a new SmallMol object aligned to a refmol that can be a htmd.smallmol.smallmol.SmallMol or rdkit.Chem.rdchem.Mol. It removes all the conformers stored in the original object. Parameters ---------- smallmol: htmd.smallmol.smallmol.SmallMol The SmallMol object to align refmol: htmd.smallmol.smallmol.SmallMol or rdkit.Chem.rdchem.Mol The molecule to align to Return ------ newsmallmol: htmd.smallmol.smallmol.SmallMol a new SmallMol aligned to reference molecule """ from htmd.smallmol.smallmol import SmallMol from rdkit.Chem.rdMolAlign import GetO3A if isinstance(refmol, SmallMol): refmol = refmol.toRdkitMol(includeConformer=True) sm_rdkit = smallmol.toRdkitMol(includeConformer=True) pyO3A = GetO3A(sm_rdkit, refmol) rmsd = pyO3A.Align() print('Alignment with a RMSD of {}'.format(rmsd)) coords_new = sm_rdkit.GetConformer().GetPositions() sm_new = SmallMol(smallmol, fixHs=False) sm_new.removeConformers() sm_new.coords = coords_new[:, :, np.newaxis] return sm_new
def test_10_removeGenerateConformer(self): molsmile = SMILE_SMI sm = SmallMol(molsmile) sm.generateConformers(num_confs=10, append=False) n_confs = sm.numConformers sm.removeConformers([0]) n_confs_del = sm.numConformers sm.removeConformers() n_confs_zero = sm.numConformers self.assertEqual(n_confs_del, n_confs - 1, "The number of conformations after the deletion was not reduced of " "exactly one unit") self.assertEqual(n_confs_zero, 0, "The number of conformations after the deletion was not reduced to 0")
def getRCSBLigandByLigname(ligname, returnMol2=False): """ Returns a SmallMol object of a ligand by its three letter lignane. This molecule is retrieve from RCSB and a mol2 written. It is possible to return also the mol2 filename. Parameters ---------- ligname: str The three letter ligand name returnMol2: bool If True, the mol2 filename is returned Returns ------- sm: htmd.smallmol.smallmol.SmallMol The SmallMol object mol2filename: str The mol2 filename Example ------- >>> from htmd.molecule.molecule import Molecule >>> mol = Molecule('4eiy') >>> np.unique(mol.get('resname', 'not protein and not water')) array(['CLR', 'NA', 'OLA', 'OLB', 'OLC', 'PEG', 'ZMA'], dtype=object) >>> sm = getRCSBLigandByLigname('ZMA') # doctest: +ELLIPSIS SmallMol module... >>> sm.numAtoms 40 >>> sm, mol2filename = getRCSBLigandByLigname('ZMA', returnMol2=True) >>> mol2filename # doctest: +ELLIPSIS '/tmp/tmp....mol2' """ import requests from htmd.molecule.support import string_to_tempfile from htmd.smallmol.smallmol import SmallMol r = requests.get( "https://files.rcsb.org/ligands/view/{}_ideal.sdf".format(ligname)) sdf_text = r.content.decode('ascii') tempfile = string_to_tempfile(sdf_text, "sdf") mol2 = openbabelConvert(tempfile, 'sdf', 'mol2') sm = SmallMol(mol2) if returnMol2: return sm, mol2 return sm
def test_10_removeGenerateConformer(self): molsmile = SMILE_SMI sm = SmallMol(molsmile) sm.generateConformers(num_confs=10, append=False) n_confs = sm.numConformers sm.removeConformers([0]) n_confs_del = sm.numConformers sm.removeConformers() n_confs_zero = sm.numConformers self.assertEqual( n_confs_del, n_confs - 1, "The number of conformations after the deletion was not reduced of " "exactly one unit") self.assertEqual( n_confs_zero, 0, "The number of conformations after the deletion was not reduced to 0" )
def test_09_writeGenerateAndWriteConformers(self): mol2file = os.path.join(self.dataDir, 'benzamidine.mol2') sm = SmallMol(mol2file) sm.generateConformers(num_confs=10, append=False) tmpdir = NamedTemporaryFile().name sm.writeConformers(savefolder=tmpdir) direxists = os.path.isdir(tmpdir) n_files = len(glob(os.path.join(tmpdir, '*.sdf'))) self.assertTrue( direxists, 'The directory where to store the conformations where not created') self.assertGreater( n_files, 1, 'None conformations were written. At least one should be present')
def test_06_isChiral(self): smi = CHIRAL_SMI sm = SmallMol(smi) ischiral, details = sm.isChiral(returnDetails=True) self.assertListEqual(details, CHIRAL_DETAILS, 'chiral atom does not match.' 'Expected: {}; Now: {}'.format(CHIRAL_DETAILS, details))
def compute_score(self, mol, returndetails=False, log=False): """ Return a canonical tautomer by enumerating and scoring all possible tautomers. :param mol: The input molecule. :type mol: :rdkit:`Mol <Chem.rdchem.Mol-class.html>` :return: The canonical tautomer. :rtype: :rdkit:`Mol <Chem.rdchem.Mol-class.html>` """ t_scores = [] scores_detail = [] t_depict = [] if isinstance(mol, SmallMol): mol = mol._mol # TODO: Overload the mol parameter to pass a list of pre-enumerated tautomers tautomers = self._enumerate_tautomers(mol) for t in tautomers: tmp_score_details = { 'ArRing': 0, 'CarbArRing': 0, 'MatchFeature': [0, []], 'Penalty': [0, []], 'Conjugate': 0 } smiles = Chem.MolToSmiles(t, isomericSmiles=True) if log: print('Tautomer: %s', smiles) score = 0 # Add aromatic ring scores ssr = Chem.GetSymmSSSR(t) for ring in ssr: btypes = { t.GetBondBetweenAtoms(*pair).GetBondType() for pair in pairwise(ring) } elements = { t.GetAtomWithIdx(idx).GetAtomicNum() for idx in ring } if btypes == {BondType.AROMATIC}: if log: print('Score +100 (aromatic ring)') score += 100 tmp_score_details['ArRing'] += 1 if elements == {6}: if log: print('Score +150 (carbocyclic aromatic ring)') score += 150 tmp_score_details['CarbArRing'] += 1 # Add SMARTS scores, Chem.MolToSmiles(t)) for tscore in self.scores: for match in t.GetSubstructMatches(tscore.smarts): if log: print('Score %+d (%s)' % (tscore.score, tscore.name)) score += tscore.score tmp_score_details['MatchFeature'][0] += 1 tmp_score_details['MatchFeature'][1].append(tscore.name) # Add (P,S,Se,Te)-H scores for atom in t.GetAtoms(): if atom.GetAtomicNum() in {15, 16, 34, 52}: hs = atom.GetTotalNumHs() if hs: if log: print('Score %+d (%s-H bonds)' % (-hs, atom.GetSymbol())) score -= hs tmp_score_details['Penalty'][0] += 1 tmp_score_details['Penalty'][1].append( atom.GetSymbol()) # compute the conjuggate system n_conjugate, depictionatoms = self.get_conjugate(t) t_depict.append(depictionatoms) tmp_score_details['Conjugate'] = n_conjugate score += n_conjugate * 2 scores_detail.append(tmp_score_details) t_scores.append(score) if returndetails: return [SmallMol(tautomer) for tautomer in tautomers ], t_scores, t_depict, scores_detail return tautomers, t_scores
def test_11_invertChirality(self): molsmile = CHIRAL_SMI sm = SmallMol(molsmile) aname = CHIRAL_DETAILS[0][0] chiral = CHIRAL_DETAILS[0][1] aidx = sm.get('idx', 'atomname {}'.format(aname))[0] sm.invertChirality(aidx) newchiral = sm.isChiral(returnDetails=True)[1][0][-1] self.assertNotEqual(chiral, newchiral, msg="The chirality was not formally changed") sm.generateConformers(num_confs=1, append=False) m = sm.toMolecule() fname = NamedTemporaryFile().name + '.mol2' m.write(fname) sm2 = SmallMol(fname) newchiral_confirm = sm2.isChiral(returnDetails=True)[1][0][-1] self.assertEqual(newchiral, newchiral_confirm, msg="The chirality was not structurally changed")
def getChemblLigandByDrugName(drugname, returnSmile=False): """ Returns a SmallMol object of a ligand by its drug name. This molecule is retrieve from Chembl. It is possible to return also the smile of the ligand. Parameters ---------- drugname: str The drug name returnSmile: bool If True, the smile is returned Returns ------- sm: htmd.smallmol.smallmol.SmallMol The SmallMol object smile: str The smile Example ------- >>> sm = getChemblLigandByDrugName('paracetamol') # doctest: +SKIP >>> sm.numAtoms # doctest: +SKIP 20 >>> sm, smile = getChemblLigandByDrugName('paracetamol', returnSmile=True) # doctest: +SKIP >>> smile # doctest: +SKIP 'CC(=O)Nc1ccc(O)cc1' """ from htmd.smallmol.smallmol import SmallMol try: from chembl_webresource_client.new_client import new_client except ImportError as e: raise ImportError( 'You need to install the chembl_webresource package to use this function. Try using `conda install ' '-c chembl chembl_webresource_client`.') drug = new_client.drug results = drug.filter(synonyms__icontains=drugname) chembl_id = None if len(results) == 0: return None found = False for drug_chembl in results: for name in drug_chembl['synonyms']: matched = [ True for na in name.split() if na.lower() == drugname.lower() ] if sum(matched) != 0: found = True chembl_id = drug_chembl['molecule_chembl_id'] break if found: break molecule = new_client.molecule molecule_chembl = molecule.get(chembl_id) smi = molecule_chembl['molecule_structures']['canonical_smiles'] sm = SmallMol(smi) if returnSmile: return sm, smi return sm