Virtual Screening with a pharmacophore

import pyunitwizard as puw
import openpharmacophore as oph
from openpharmacophore import mol_db

We want to screen a database of molecules with a pharmacophore to find potential matches. We start by defining our pharmacophore model

pharmacophore = oph.Pharmacophore([
    oph.PharmacophoricPoint(
        feat_type="hb acceptor",
        center=puw.quantity([2.35, 1.94, -0.68], "angstroms"),
        radius=puw.quantity(1.0, "angstroms"),
    ),
    oph.PharmacophoricPoint(
        feat_type="hydrophobicity",
        center=puw.quantity([1.57, -2.53, 2.15], "angstroms"),
        radius=puw.quantity(1.0, "angstroms"),
    ),
    oph.PharmacophoricPoint(
        feat_type="aromatic ring",
        center=puw.quantity([6.19, 1.34, -1.36], "angstroms"),
        radius=puw.quantity(1.0, "angstroms"),
    ),
])

We will create a database of molecules loading them from different files

file1 = "../data/screening/ligands_1.smi"
file2 = "../data/screening/ligands_2.smi"
! cat {file1}
Smiles Name
[H]/N=C(\C1CCC(CC1)CNC(=O)[C@@H]2C=C(CN3N2C(=O)N(C3=O)CC(c4ccccc4)c5ccccc5)C)/N IH2
CN[C@H](Cc1ccccc1)C(=O)N2CCC[C@H]2C(=O)NCC3CCC(CC3)N MIN
c1ccc(cc1)S(=O)(=O)CCN2C(=O)N3CC=C[C@H](N3C2=O)C(=O)NC4CCC(CC4)c5cnc([nH]5)N 00R
c1ccc(cc1)S(=O)(=O)CCN2C(=O)N3CC=C[C@H](N3C2=O)C(=O)NCC4CCC(CC4)N 00P
[H]/N=C(/c1ccc(cc1)C[C@H](C(=O)N2CCCCC2)NC(=O)CNS(=O)(=O)c3ccc4ccccc4c3)\N MID
! cat {file2}
Smiles Name
[H]/N=C(\c1ccc2c(c1)cc([nH]2)C(=O)N3CCC(CC3)Cc4ccccc4)/N BPP
CCC1CCN(CC1)C(=O)[C@H](CCCNC(=[NH2+])N)NS(=O)(=O)c2cccc3c2cccc3N(C)C 0ZI
C[C@H]1CN2c3c(cc(cc3NC2=S)Cl)CN1CC=C(C)C TB9
CC(C)c1c(n(c(n1)COC(=O)N)Cc2ccncc2)Sc3cc(cc(c3)Cl)Cl S11
CC(C)OC(=O)N1c2cc(ccc2NC(=S)[C@@H]1CSC)OC HBY
db = mol_db.MolDB()
db.from_file_list([file1, file2], header=True)

We can now create a virtual screening object to which will pass our pharmacophore and our molecule db

screener = oph.VirtualScreening([pharmacophore])
screener.screen(db)

print(f"{len(screener.matches[0])} molecule matched the pharmacophore")
print(f"{screener.fails[0]} molecule failed to match the pharmacophore")
4 molecule matched the pharmacophore
6 molecule failed to match the pharmacophore

We inspect the molecules that matched the pharmachore along with their alignment scores (RMSD)

ligands = [m.ligand for m in screener.matches[0]]
legends = [
    m.ligand.to_rdkit().GetProp("_Name") for m in screener.matches[0]
]
scores = [m.rmsd for m in screener.matches[0]]

print("RMSDs", scores)
oph.draw_ligands(
    ligands=ligands, 
    n_per_row=4,
    legends=legends
)
RMSDs [0.8177257515854292, 0.8517769586370709, 0.7687604258063847, 0.9831765173894478]
../../../_images/9585ceda605a355d0a77eae961ae3b5949df3ac1b687712d1a65e455c23180d2.png

We visualize the aligned ligands and the pharmacophore

idx = 0
viewer = oph.Viewer()
viewer.add_components([ligands[idx], pharmacophore])
viewer.show()