Commit aeaffd30 authored by Hervé  MENAGER's avatar Hervé MENAGER
Browse files

move physico-chemical tests to Compound annotations

this to allow their use in filters on the compounds list


Former-commit-id: 19c7f05a27c028a9578991b596fa8d43c7b2b75e
parent 19aa824d
......@@ -7,9 +7,9 @@ import operator
from django.db import models
from django.conf import settings
from django.db.models import Max, Min, Count, F, Q
from django.db.models import Max, Min, Count, F, Q, Case, When, Sum
from django.db.models.functions import Cast
from django.db.models import FloatField
from django.db.models import FloatField, IntegerField, BooleanField
from .utils import FingerPrinter, smi2inchi, smi2inchikey
......@@ -275,14 +275,41 @@ class CompoundManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
# with number of publications
# with number of publications
qs = qs.annotate(pubs=Count('refcompoundbiblio', distinct=True))
# with best activity
# with best activity
qs = qs.annotate(best_activity=Max('compoundactivityresult__activity'))
# with LE
qs = qs.annotate(le=Cast(1.37 * Max('compoundactivityresult__activity') / F('nb_atom_non_h'),FloatField()))
# with LLE
qs = qs.annotate(lle=Cast(Max('compoundactivityresult__activity') - F('a_log_p'),FloatField()))
# with LE
qs = qs.annotate(le=Cast(1.37 * Max('compoundactivityresult__activity') / F('nb_atom_non_h'), FloatField()))
# with LLE
qs = qs.annotate(lle=Cast(Max('compoundactivityresult__activity') - F('a_log_p'), FloatField()))
# Lipinsky MW (<=500)
qs = qs.annotate(lipinsky_mw=Case(When(molecular_weight__lte=500, then=True), default=False, output_field=BooleanField()))
# Lipinsky hba (<=10)
qs = qs.annotate(lipinsky_hba=Case(When(nb_acceptor_h__lte=10, then=True), default=False, output_field=BooleanField()))
# Lipinsky hbd (<5)
qs = qs.annotate(lipinsky_hbd=Case(When(nb_donor_h__lte=5, then=True), default=False, output_field=BooleanField()))
# Lipinsky a_log_p (<5)
qs = qs.annotate(lipinsky_a_log_p=Case(When(a_log_p__lte=5, then=True), default=False, output_field=BooleanField()))
# Lipinsky global
qs = qs.annotate(lipinsky_score=Cast(F('lipinsky_mw'), IntegerField())+Cast(F('lipinsky_hba'), IntegerField())+ \
Cast(F('lipinsky_hbd'), IntegerField()) + Cast(F('lipinsky_a_log_p'), IntegerField()))
qs = qs.annotate(lipinsky=Case(When(lipinsky_score__gte=3, then=True), default=False, output_field=BooleanField()))
# Veber hba_hbd (<=12)
qs = qs.annotate(hba_hbd=F('nb_acceptor_h')+F('nb_donor_h'))
qs = qs.annotate(veber_hba_hbd=Case(When(hba_hbd__lte=12, then=True), default=False, output_field=BooleanField()))
# Veber TPSA (<=140)
qs = qs.annotate(veber_tpsa=Case(When(tpsa__lte=140, then=True), default=False, output_field=BooleanField()))
# Veber Rotatable Bonds (<=10)
qs = qs.annotate(veber_rb=Case(When(nb_rotatable_bonds__lte=10, then=True), default=False, output_field=BooleanField()))
# Veber global (Rotatable bonds and (hba_hbd or tpsa))
qs = qs.annotate(veber=F('veber_rb').bitand(F('veber_hba_hbd').bitor(F('veber_tpsa'))))
# Pfizer AlogP (<=3)
qs = qs.annotate(pfizer_a_log_p=Case(When(a_log_p__lte=3, then=True), default=False, output_field=BooleanField()))
# Pfizer TPSA (>=75)
qs = qs.annotate(pfizer_tpsa=Case(When(tpsa__gte=75, then=True), default=False, output_field=BooleanField()))
# Pfizer global (AlogP and TPSA)
qs = qs.annotate(pfizer=F('pfizer_a_log_p').bitand(F('pfizer_tpsa')))
return qs
class Compound(AutoFillableModel):
......@@ -408,59 +435,6 @@ class Compound(AutoFillableModel):
ligand_ids.add(ca.ligand_id)
return ligand_ids
@property
def hba_hbd(self):
return self.nb_acceptor_h + self.nb_donor_h
@property
def lipinsky_mw(self):
return self.molecular_weight <= 500
@property
def lipinsky_hba(self):
return self.nb_acceptor_h <= 10
@property
def lipinsky_hbd(self):
return self.nb_donor_h <= 5
@property
def lipinsky_a_log_p(self):
return self.a_log_p <= 5
@property
def lipinsky_global(self):
return int(self.lipinsky_mw) + int(self.lipinsky_hba) + \
int(self.lipinsky_hbd) + int(self.lipinsky_a_log_p) >= 3
@property
def veber_hba_hbd(self):
return self.nb_acceptor_h + self.nb_donor_h <= 12
@property
def veber_tpsa(self):
return self.tpsa <= 140
@property
def veber_rb(self):
return self.nb_rotatable_bonds <= 10
@property
def veber_global(self):
return self.veber_rb and (self.veber_hba_hbd or self.veber_tpsa)
@property
def pfizer_a_log_p(self):
return self.a_log_p <= 3
@property
def pfizer_tpsa(self):
return self.tpsa >= 75
@property
def pfizer_global(self):
return self.pfizer_a_log_p and self.pfizer_tpsa
@property
def best_pXC50_activity(self):
return self.compoundactivityresult_set.aggregate(Max('activity'))['activity__max']
......
......@@ -58,9 +58,9 @@
<tbody>
<tr>
<th scope="row">Global</th>
<td class="{% if compound.lipinsky_global %}table-success{% else %}table-danger{% endif %}" title="at least 3 criteria ok"></td>
<td class="{% if compound.veber_global %}table-success{% else %}table-danger{% endif %}" title="RB and HBA+HBD or TPSA ok"></td>
<td class="{% if compound.pfizer_global %}table-success{% else %}table-danger{% endif %}" title="AlogP and TPSA ok"></td>
<td class="{% if compound.lipinsky %}table-success{% else %}table-danger{% endif %}" title="at least 3 criteria ok"></td>
<td class="{% if compound.veber %}table-success{% else %}table-danger{% endif %}" title="RB and HBA+HBD or TPSA ok"></td>
<td class="{% if compound.pfizer %}table-success{% else %}table-danger{% endif %}" title="AlogP and TPSA ok"></td>
</tr>
<tr>
<th scope="row">MW</th>
......
......@@ -140,7 +140,8 @@ def create_dummy_compound(id_, smiles):
c.tpsa = 0
c.ui = 0
c.wiener_index = 0
c.save(autofill=True)
c.save(autofill=True)
return c
def create_dummy_drugbank_compound(id_, smiles):
......@@ -180,3 +181,103 @@ class CompoundTanimotoTestCaseCompound1ECFP4(TestCase):
ct2 = CompoundTanimoto.objects.get(id=2,canonical_smiles=self.smiles_query)
self.assertEqual(ct.tanimoto, 1.0)
self.assertEqual(float(ct2.tanimoto),0.0971)
class CompoundAnnotationsTestCase(TestCase):
def test_lipinsky_ok(self):
# c is ok for Lipinsky
c = create_dummy_compound(1,"CC")
# MW <= 500
c.molecular_weight = 300
# HBA <= 10
c.nb_acceptor_h = 9
# HBD <= 5
c.nb_donor_h = 4
# AlogP <= 5
c.a_log_p = 4
c.save()
c = Compound.objects.get(id=1)
self.assertTrue(c.lipinsky_mw)
self.assertTrue(c.lipinsky_hba)
self.assertTrue(c.lipinsky_hbd)
self.assertTrue(c.lipinsky_a_log_p)
self.assertTrue(c.lipinsky)
def test_lipinsky_ko(self):
# c is ko for Lipinsky
c = create_dummy_compound(1,"CC")
# MW > 500
c.molecular_weight = 3000
# HBA > 10
c.nb_acceptor_h = 11
# HBD > 5
c.nb_donor_h = 6
# AlogP > 5
c.a_log_p = 7
c.save()
c = Compound.objects.get(id=1)
self.assertFalse(c.lipinsky_mw)
self.assertFalse(c.lipinsky_hba)
self.assertFalse(c.lipinsky_hbd)
self.assertFalse(c.lipinsky_a_log_p)
self.assertFalse(c.lipinsky)
def test_veber_ok(self):
# c is ok for Veber
c = create_dummy_compound(1,"CC")
# HBA + HBD <=12
c.nb_acceptor_h = 10
c.nb_donor_h = 1
# TPSA <= 140
c.tpsa = 130
# RB <= 10
c.nb_rotatable_bonds = 9
c.save()
c = Compound.objects.get(id=1)
self.assertTrue(c.veber_hba_hbd)
self.assertTrue(c.veber_tpsa)
self.assertTrue(c.veber_rb)
self.assertTrue(c.veber)
def test_veber_ko(self):
# c is ko for Veber
c = create_dummy_compound(1,"CC")
# HBA + HBD > 12
c.nb_acceptor_h = 10
c.nb_donor_h = 3
# TPSA > 140
c.tpsa = 141
# RB > 10
c.nb_rotatable_bonds = 11
c.save()
c = Compound.objects.get(id=1)
self.assertFalse(c.veber_hba_hbd)
self.assertFalse(c.veber_tpsa)
self.assertFalse(c.veber_rb)
self.assertFalse(c.veber)
def test_pfizer_ok(self):
# c is ok for Pfizer
c = create_dummy_compound(1,"CC")
# AlogP <=3
c.a_log_p = 2
# TPSA >=75
c.tpsa = 80
c.save()
c = Compound.objects.get(id=1)
self.assertTrue(c.pfizer_a_log_p)
self.assertTrue(c.pfizer_tpsa)
self.assertTrue(c.pfizer)
def test_pfizer_ko(self):
# c is ko for Pfizer
c = create_dummy_compound(1,"CC")
# AlogP >3
c.a_log_p = 4
# TPSA <75
c.tpsa = 8
c.save()
c = Compound.objects.get(id=1)
self.assertFalse(c.pfizer_a_log_p)
self.assertFalse(c.pfizer_tpsa)
self.assertFalse(c.pfizer)
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment