Что мы делаем здесь:
import pubchempy as pcp
Вытаскиваем из PubChem'а все соединения с азидной группой.
С какими проблемами мы столкнулись и как их решали.
azides
),not_azides
),nope
). .
, точка, обозначающая в SMILES не-ковалентную связь,Здесь происходит выгрузка результатов поиска:
compounds = []
per_page = 10**5
for smiles in ["N=N=N", "NN#N"]:
for i in range(20):
try:
a = pcp.get_properties(
properties="CanonicalSMILES",
identifier=smiles,
namespace="smiles",
searchtype="substructure",
RingsNotEmbedded=True,
listkey_count=per_page,
listkey_start=i*per_page
)
except KeyboardInterrupt:
print("Interrupted")
raise
except:
print("Page {} returns 500, which is "
"our signal to stop.".format(i+1))
break
print("Retrieved page {} of {} search".format(i+1, smiles))
compounds.extend(a)
# Remove duplicates
compounds = {c["CID"]:c for c in compounds}.values()
print("Retrieved {} SMILES of (supposedly) "
"azide-containing compounds".format(len(compounds)))
Здесь происходит проверка фильтра на адекватность:
azides = ["N=[N+]=[N-]", "N[NH+]=[N-]",
"[N-]=[N+]=N", "[N-]=[NH+]N",
"[N-][N+]#N", "N[N+]#N", "[N][N+]#N",
"N#[N+][N-]", "N#[N+]N", "N#[N+][N]",
]
not_azides = ["=N[N+]#N", "=N[N+]=[N-]",
"([N+]#N)", ")[N+]#N", "(=[N-])", ")[NH+]=[N-]", "NN(N"
] + ["N{}[N+]#N".format(i) for i in range(1, 4+1)] \
+ ["N{}NN{}".format(i, i) for i in range(1, 4+1)]
nope = [".", "=N[N+]#N", "N=[N+]=N"]
nonmatched = sum(1 for compound in compounds if
all(substr not in compound["CanonicalSMILES"]
for substr in azides+not_azides+nope))
print(nonmatched)
for compound in compounds:
if all((substr not in compound["CanonicalSMILES"]
for substr in azides+not_azides+nope)):
# print(compound)
pass
Just for fun: здесь можно посмотреть, какие представления азидов и не-азидов наиболее популярны в результатах нашего поиска:
azidelike_counts = {y:0 for y in azides+not_azides+nope}
for x in compounds:
for y in azides+not_azides+nope:
if y in x["CanonicalSMILES"]:
azidelike_counts[y] += 1
print(sum(azidelike_counts.itervalues()) - len(compounds))
for key, value in azidelike_counts.iteritems():
print(key, value)
Здесь, наконец, происходит фильтрация.
compounds = [compound for compound in compounds if
any(substr in compound["CanonicalSMILES"]
for substr in azides) and
all(substr not in compound["CanonicalSMILES"]
for substr in nope)]
print(len(compounds))
Теперь мы можем добавлять ибупрофен.
Для начала подключим rdkit.
# Those imports are copy-pasted;
# I have not verified that they're all necessary.
from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit import RDConfig
from rdkit.Chem.Draw import IPythonConsole
from rdkit.Chem import Draw
import rdkit.Chem.Lipinski as Lipinski
from IPython.display import display,Image
Извлечём из того же PubChem'а SMILES ибупрофена и для наглядности нарисуем его.
ibuprofen = Chem.MolFromSmiles("CC(C)CC1=CC=C(C=C1)C(C)C(=O)O")
display(ibuprofen)
Для CuAAC нам нужна ацетиленовая группа. Объявляем, что заменить в ибупрофене изопропил на неё легко и просто, и это и будет делаться в живых реакциях.
ibuprofen_2 = Chem.MolFromSmiles("C#CCC1=CC=C(C=C1)C(C)C(=O)O")
display(ibuprofen_2)
ibu = "C(=C9)(N=NN9CC8=CC=C(C=C8)C(C)C(=O)O)"
compounds2 = {}
for i, compound in enumerate(compounds):
s = compound["CanonicalSMILES"]
for azide in azides:
s = s.replace(azide, ibu)
mol = Chem.MolFromSmiles(s)
if i%10000 == 0:
print(i)
#display(mol)
if mol is None:
continue
if (Lipinski.NumHDonors(mol) <= 5 and
Lipinski.NumHAcceptors(mol) <= 10 and
Lipinski.rdMolDescriptors.CalcExactMolWt(mol) < 500 and
Lipinski.rdMolDescriptors.CalcCrippenDescriptors(mol)[0] <= 5):
compounds2[compound['CID']] = mol
print("Done: {} molecules Lipinski-approved".format(len(compounds2)))
ibuprofen_3 = Chem.MolFromSmiles(ibu)
AllChem.Compute2DCoords(ibuprofen_3)
to_draw = {key:compounds2[key] for key in compounds2.keys()[::5000]}
for mol in to_draw.values():
AllChem.GenerateDepictionMatching2DStructure(mol, ibuprofen_3)
AllChem.Compute2DCoords(mol)
#display(mol)
img = Draw.MolsToGridImage(to_draw.values(),
molsPerRow=2,
subImgSize=(400,200),
#legends=[str(k) for k in to_draw.keys()],
)
display(img)
#for mol in compounds2.values()[::10000]:
# display(mol)
#nv.show_rdkit(mol3d)
import nglview as nv
m3d=Chem.AddHs(to_draw.values()[7])
Chem.AllChem.EmbedMolecule(m3d)
AllChem.MMFFOptimizeMolecule(m3d,maxIters=500,nonBondedThresh=200 )
nv.show_rdkit(m3d)