Клик-химия и аналоги ибупрофена¶

In [3]:
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 Lipinksi
from rdkit.Chem.Draw import SimilarityMaps

import pubchempy as pcp

import numpy as np
from IPython.display import display,Image

Вводная¶

Рассмотрим ибупрофен

In [5]:
ibu = Chem.MolFromSmiles('CC(C)CC1=CC=C(C=C1)C(C)C(=O)O')
ibu
Out[5]:

Он представляет собой бензольное кольцо с двумя заместителями в пара-положении: один полностью алифатический, другой с карбоксильной группой.
Ибупрофен связывается в активном сайте циклооксигеназы 2, ингибируя тем самым осуществляемое ею превращение арахидоновой кислоты в простогландин H2 (медиатор воспаления).

Взаимодействие выглядит следующим образом (согласно инструменту PoseView по структуре 4PH9):

In [3]:
Image(filename='4ph9_IBP_A_601.png', width=500)
Out[3]:

Вся гидрофобная часть молекулы находится в кармане, а карбоксильная группа расположена на выходе из кармана и активно взаимодейвствует с окружающими полярными и заряженными группами.

Конструирование кандидатов аналогов¶

В задании предлагается модицицировать ибупрофен введением дополнительного фрагмента по клик-реакции Хьюстена (азид-алкин циклоприсоединение)

In [172]:
Image(url='https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/CuAAC-triazole-synthesis.png/1920px-CuAAC-triazole-synthesis.png', width=500)
Out[172]:

Для этого в нём должна быть тройная связь.
Поскольку внутри кармана ряд ли найдётся место для дополнительного крупного фрагмента, введём её со стороны карбоксильной группы, например, через эфирную связь — это получится достаточно гибкое соединение, которое, к тому же, по идее достаточно несложно синтезировать. Из минусов — мы потеряем минус на карбоксигруппе, который взаимодействует с плюсом на аргинине.
Разумность такого подхода подтверждаются различными работами, применяющими его (а также вариации, например, с заменой карбоксильной группы на карбамидую) и добивающимися в результате улучшения фармакологических свойств: Lolli et al, 2001, Vasincu et al, 2021, Abbas et al, 2022.

In [140]:
click_R_before = 'C#C'  # алкильная группа
click_R_after = 'C1=CNN=N1' # кольцо после присоединения азида
click_R1, click_R2 = 'N1C=C', 'N=N1'

# acidic_R = 'C(C(=O)O)C'
aliphatic_R = 'CC(C)C'
# benzene_acidic = f'C2=CC({acidic_R})=CC=C2'
benzene_aliphatic = f'C2=CC=C({aliphatic_R})C=C2'
In [173]:
display(Draw.MolsToGridImage(
    [Chem.MolFromSmiles(x) for x in [f'C({benzene_aliphatic})(C(=O)O({click_R_before}))C',
                                     f'C({benzene_aliphatic})(C(=O)O({click_R_after}))C',
                                     
                                     # перепишем так, чтобы азоты были по краям молекулы — для корректной вставки далее
                                     f'{click_R1}(OC(=O)C(C){benzene_aliphatic}){click_R2}'
                                      ]
    ], useSVG=False, molsPerRow=3, subImgSize=(200, 200)))
In [143]:
ibu_template = f'{click_R1}(OC(=O)C(C){benzene_aliphatic}){click_R2}'

Соединение выше будет использовано как шаблон, в котором перебираемые радикалы будут присоединяться к нижнему азоту.

Получим из PubChem все молекулы, содержащие азидный фрагмент

In [32]:
compounds = []
per_page = 10**5

for smiles in ["N=N=N", "NN#N",]:
    for i in range(200):
        try:
            a = pcp.get_properties(
                      properties="CanonicalSMILES",  # свойства, которые получаем для находок
                      identifier=smiles,   # query
                      namespace="smiles",  # что представляет собой query
                      searchtype="substructure", # искать как подструктуру
                      RingsNotEmbedded=True,  # не учитывать query-фрагменты, когда они часть кольца
                      listkey_count=per_page,   # сколько молекул получить 
                      listkey_start=i*per_page  # начиная с какой получать 
                    )
            compounds.extend(a)
        except pcp.ServerError:
            print('all here')
            break
            
        print("Retrieved page {} of {} search".format(i+1, smiles))
Retrieved page 1 of N=N=N search
Retrieved page 2 of N=N=N search
Retrieved page 3 of N=N=N search
all here
Retrieved page 1 of NN#N search
all here
In [20]:
len(compounds)
Out[20]:
242269

Вставим в находки место азидной группы наш видоизменённый ибупрофен, отфильтруем получившиеся молекулы по соответсвию правилам пяти Липински

In [45]:
def pass_Lipinksi(mol):
    return \
        Lipinksi.NumHDonors(mol) <= 5 and \
        Lipinksi.NumHAcceptors(mol) <= 10 and \
        Lipinksi.rdMolDescriptors.CalcExactMolWt(mol) < 500 and \
        Lipinksi.rdMolDescriptors.CalcCrippenDescriptors(mol)[0] <= 5
In [144]:
filtered = []

for comp in compounds[:1500]: # рассмотрим только часть, потому что их и так много
    if "N=[N+]=[N-]" in comp['CanonicalSMILES']:
        newcomp=comp['CanonicalSMILES'].replace('N=[N+]=[N-]', ibu_template)
    else:
        continue
   
    # Новую молекулу лучше создавать в try из-за битых  Smiles
    try:
        newmol=Chem.MolFromSmiles(newcomp)        
        if pass_Lipinksi(newmol):
            filtered.append(newmol)            
    except:
        pass
In [145]:
len(filtered)
Out[145]:
292

Визуализируем 50 случайных из них:

In [172]:
display(Draw.MolsToGridImage(np.random.choice(filtered, 50), useSVG=False, molsPerRow=5, subImgSize=(200, 200)))

В целом, выглядит похоже на то, что мы хотели получить: ибупрофен, клик-цикл через эфир, новый фрагмент. Можно идти запускать тысячу докингов:)

Сходство молекул¶

Нарисуем карту сходства ибупрофена и одного из построенных веществ.

In [171]:
fig, maxweight = SimilarityMaps.GetSimilarityMapForFingerprint(ibu, filtered[4], SimilarityMaps.GetMorganFingerprint)

Ожидаемо, на карте сходства хорошо различима подструктура оригинального ибупрофена (зелёный цвет — высокое сходство) и добавленный новый фрагмент (красный цвет — низкое сходство).

Для сравнения посмотрим на молекулу, содержащую две подструктуры ибупрофена

In [169]:
fig, maxweight = SimilarityMaps.GetSimilarityMapForFingerprint(ibu, 
                                                               Chem.MolFromSmiles('CC(C)CC1=CC=C(C=C1)C(C)C(=O)OCC(C)CC1=CC=C(C=C1)C(C)C(=O)O'), 
                                                               SimilarityMaps.GetMorganFingerprint)

Обе подструктуры покрашены зелёным, а новосозданная эфирная связь красным — сходство оценивается именно по совпадению фингерпринтов, а не "наложением" атомов молекул друг на друга.

3D-визуализация¶

Не работает

In [6]:
m3d=Chem.AddHs(ibu)
Chem.AllChem.EmbedMolecule(m3d)
AllChem.MMFFOptimizeMolecule(m3d,maxIters=500,nonBondedThresh=200)
Out[6]:
0
In [1]:
import nglview as nv

In [37]:
widget = nv.show_rdkit(m3d)
In [40]:
widget  # пропадает при экспорте
NGLWidget()
In [43]:
widget.render_image(0)  # тоже пропадает при экспорте
Image(value=b'', width='99%')
In [44]:
widget.download_image('ibu.png')
In [45]:
Image('ibu.png')
Out[45]: