from warnings import filterwarnings
filterwarnings(action='ignore')
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 Lipinksy
import numpy as np
from IPython.display import display, Image, HTML
Отрисуем молекулу ибупрофена
ibu = Chem.MolFromSmiles('CC(C)CC1=CC=C(C=C1)C(C)C(=O)O')
AllChem.Compute2DCoords(ibu)
display(ibu)
Посмотрим на показатели, необходимые для оценки молекулы ибупрофена по правилу пяти Липински (RO5).
print('Число доноров водородной связи (должно быть ≤ 5): ',
Lipinksy.NumHDonors(ibu))
print('Число акцепторов водородной связи (должно быть ≤ 10): ',
Lipinksy.NumHAcceptors(ibu))
print('Молекулярная масса (должна быть < 500 Da): ',
Lipinksy.rdMolDescriptors.CalcExactMolWt(ibu))
print('Коэффициент распределения октанол-вода, log P (должен быть ≤ 5): ',
Lipinksy.rdMolDescriptors.CalcCrippenDescriptors(ibu)[0])
Как мы видим, RO5 выполняется по всем пунктам, что означает доступность ибупрофена при пероральном приёме.
Напишем специальную функцию для проверки RO5:
def test_lipinski_ro5(mol):
if (Lipinksy.NumHDonors(mol) <= 5) & \
(Lipinksy.NumHAcceptors(mol) <= 10) & \
(Lipinksy.rdMolDescriptors.CalcExactMolWt(mol) < 500) &\
(Lipinksy.rdMolDescriptors.CalcCrippenDescriptors(mol)[0] <= 5):
return True
else:
return False
test_lipinski_ro5(ibu)
Модифицируем ибупрофен так, как если бы он являлся продуктом реакции click-химии.
ibu_mod_smiles = 'N1N=NC=C(CC(C(=O)O)C2=CC=C(CC(C)C)C=C2)1'
ibu_mod = Chem.MolFromSmiles(ibu_mod_smiles)
AllChem.Compute2DCoords(ibu_mod)
display(ibu_mod)
Lipinksy.rdMolDescriptors.CalcExactMolWt(ibu_mod)
Когда мы будем внедрять этот фрагмент вместо азидной группы, мы будем добавлять примерно 273 - 42 = 231 Да. Тогда для прохождения всех критериев RO5 азид-содержащее соединение должно облалать молекулярной массой не более 269 Да.
test_lipinski_ro5(ibu_mod)
Выгрузим из PubChem 10000 находок с азидной группой "N=[N+]=[N-]" в качестве Substructure.
import pandas as pd
df = pd.read_csv('files/pubchem_azide_substructures_1kk.csv', nrows=10000)
Отфильтруем находки с несколькими соединениями и сделаем отсечку по массе.
df = df[~(df['isosmiles'].str.contains('\.'))]
df_candidate = df[df['mw']<=269]
print(f'До: {df.shape[0]} молекул, после фильтрации — {df_candidate.shape[0]}.')
df_azides = df_candidate[df_candidate['isosmiles'].apply(lambda x: 'N=[N+]=[N-]' in x)]
print(f'Замену азидной группы проведем в {df_azides.shape[0]} структурах.')
candidate_smiles = df_azides['isosmiles'].apply(lambda x: x.replace('N=[N+]=[N-]', f'({ibu_mod_smiles})')).values
from tqdm.notebook import tqdm
import multiprocessing as mp
def testing_pipeline(smiles):
try:
mol = Chem.MolFromSmiles(smiles)
AllChem.Compute2DCoords(mol)
if test_lipinski_ro5(mol):
return mol
except:
return None
pool = mp.Pool(processes=4)
result = pool.map(testing_pipeline, candidate_smiles)
candidate_molecules = [mol for mol in result if mol]
print(f'Получилось {len(candidate_molecules)} кандидатных молекул.')
from random import sample, seed
seed(23)
Отрисуем 9 кандидатов
candidate_sample = sample(candidate_molecules, 9)
Draw.MolsToGridImage(candidate_sample, useSVG=True, molsPerRow=3, subImgSize=(200, 200))
Построим Similiraty Map ибупрофена с пятым соединением.
from rdkit.Chem.Draw import SimilarityMaps
candidate = candidate_sample[4]
fig, maxweight = SimilarityMaps.GetSimilarityMapForFingerprint(ibu,
candidate,
SimilarityMaps.GetMorganFingerprint)
Получим 3D конформацию нашего кандидата
candidate_3d = Chem.AddHs(candidate)
Chem.AllChem.EmbedMolecule(candidate_3d)
AllChem.MMFFOptimizeMolecule(candidate_3d, maxIters=500, nonBondedThresh=200);
candidate_3d
Визуализировать с помощью как nglviewer, так и py3Dmol не удалось, так что воспользуемся демонстрацией из PyMOL.
w = Chem.PDBWriter('files/candidate_3d.pdb')
w.write(candidate_3d, confId=0)
import __main__
__main__.pymol_argv = ['pymol', '-x']
import pymol
pymol.finish_launching()
from pymol import cmd
cmd.do('''reinitialize
bg_color white
load files/candidate_3d.pdb, candidate
select candidate
orient
zoom
deselect
mset 1x90
mview store, 1
mview store, 90
turn y, 120
mview store, 30
turn y, 120
mview store, 60
''')
HTML('''
<div align="middle">
<video width="80%" controls>
<source src="img/candidate.mp4" type="video/mp4">
</video></div>''')