-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding medicinal chemistry calculators and associated tests.
- Loading branch information
1 parent
5736c28
commit be69fc2
Showing
5 changed files
with
264 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
"""Script containing tools to calculate Medicinal Chemistry properties.""" | ||
|
||
import os | ||
import sys | ||
from typing import Union | ||
|
||
from rdkit import Chem | ||
from rdkit.Chem import RDConfig | ||
from rdkit.Chem.FilterCatalog import FilterCatalog, FilterCatalogParams | ||
|
||
from adme_py.lipophilicity import calculate_logp_crippen | ||
from adme_py.physiochemical import calculate_molecular_weight, calculate_number_rotatable_bonds | ||
|
||
sys.path.append(os.path.join(RDConfig.RDContribDir, "SA_Score")) | ||
import sascorer | ||
|
||
|
||
def calculate_all_medicinal(mol: Chem.Mol) -> dict[str, Union[bool, str, dict[str, str], float]]: | ||
"""Calculate all properties in the medicinal chemistry script. | ||
Parameters | ||
---------- | ||
mol : Chem.Mol | ||
The input rdkit Mol object | ||
Returns | ||
------- | ||
properties : dict[str, Union[str,dict[str,str]]] | ||
Dictionary of properties calculated | ||
""" | ||
pains: bool = calculate_pains(mol) | ||
brenk: bool = calculate_brenk(mol) | ||
zinc: bool = calculate_zinc(mol) | ||
leadlikeness: Union[str, dict[str, str]] = calculate_leadlikeness(mol) | ||
synthetic_accessibility: float = calculate_synthetic_accessiblity(mol) | ||
|
||
properties: dict[str, Union[bool, str, dict[str, str], float]] = { | ||
"pains": pains, | ||
"brenk": brenk, | ||
"zinc": zinc, | ||
"leadlikeness": leadlikeness, | ||
"synthetic_accessibility": synthetic_accessibility, | ||
} | ||
|
||
return properties | ||
|
||
|
||
def calculate_pains(mol: Chem.Mol) -> bool: | ||
"""Calculate whether the molecule triggers the PAINS filter. | ||
Parameters | ||
---------- | ||
mol : Chem.Mol | ||
The input rdkit Mol object | ||
Returns | ||
------- | ||
bool | ||
Whether the molecule triggers the PAINS filter. | ||
""" | ||
params_pains = FilterCatalogParams() | ||
params_pains.AddCatalog(FilterCatalogParams.FilterCatalogs.PAINS_A) | ||
params_pains.AddCatalog(FilterCatalogParams.FilterCatalogs.PAINS_B) | ||
params_pains.AddCatalog(FilterCatalogParams.FilterCatalogs.PAINS_C) | ||
|
||
catalog_pains = FilterCatalog(params_pains) | ||
return catalog_pains.HasMatch(mol) | ||
|
||
|
||
def calculate_brenk(mol: Chem.Mol) -> bool: | ||
"""Calculate whether the molecule triggers the Brenk filter. | ||
Parameters | ||
---------- | ||
mol : Chem.Mol | ||
The input rdkit Mol object | ||
Returns | ||
------- | ||
bool | ||
Whether the molecule triggers the Brenk filter. | ||
""" | ||
params_brenk = FilterCatalogParams() | ||
params_brenk.AddCatalog(FilterCatalogParams.FilterCatalogs.BRENK) | ||
|
||
catalog_brenk = FilterCatalog(params_brenk) | ||
return catalog_brenk.HasMatch(mol) | ||
|
||
|
||
def calculate_zinc(mol: Chem.Mol) -> bool: | ||
"""Calculate whether the molecule triggers the Zinc filter. | ||
Parameters | ||
---------- | ||
mol : Chem.Mol | ||
The input rdkit Mol object | ||
Returns | ||
------- | ||
bool | ||
Whether the molecule triggers the ZINC filter. | ||
""" | ||
params_zinc = FilterCatalogParams() | ||
params_zinc.AddCatalog(FilterCatalogParams.FilterCatalogs.ZINC) | ||
|
||
catalog_zinc = FilterCatalog(params_zinc) | ||
return catalog_zinc.HasMatch(mol) | ||
|
||
|
||
def calculate_leadlikeness(mol: Chem.Mol) -> Union[str, dict[str, str]]: | ||
"""Calculate if the molecule exhibits leadlikeness. | ||
Parameters | ||
---------- | ||
mol : Chem.Mol | ||
The input rdkit Mol object | ||
Returns | ||
------- | ||
Union[str,dict[str,str]] | ||
The violations to the leadlikeness filter | ||
""" | ||
violation = {} | ||
|
||
logp = calculate_logp_crippen(mol) | ||
if logp > 3.5: | ||
violation["LogP"] = f"LogP: {logp} > 3.5" | ||
|
||
molecular_weight = calculate_molecular_weight(mol) | ||
if molecular_weight < 250 or molecular_weight > 350: | ||
violation["MW"] = f"MW: {molecular_weight} is outside the acceptable range (250-350)" | ||
|
||
number_rotatable_bonds = calculate_number_rotatable_bonds(mol) | ||
if number_rotatable_bonds > 7: | ||
violation["num_rot_bonds"] = f"Number of Rotatable Bonds: {number_rotatable_bonds} > 7" | ||
|
||
if violation: | ||
return violation | ||
else: | ||
return "Yes" | ||
|
||
|
||
def calculate_synthetic_accessiblity(mol: Chem.Mol) -> float: | ||
"""Calculate the synthetic accessibility of the molecule. | ||
Parameters | ||
---------- | ||
mol : Chem.Mol | ||
The input rdkit Mol object | ||
Returns | ||
------- | ||
float | ||
The Synthetic Accessibility score of the molecule | ||
""" | ||
return sascorer.calculateScore(mol) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""Tests for methods in medicinal.py file.""" | ||
|
||
from adme_py.medicinal import ( | ||
calculate_brenk, | ||
calculate_leadlikeness, | ||
calculate_pains, | ||
calculate_synthetic_accessiblity, | ||
calculate_zinc, | ||
) | ||
from rdkit import Chem | ||
|
||
|
||
def test_calculate_pains_pass(rdkit_mol): | ||
"""Test a passing case of calculate_pains().""" | ||
assert not calculate_pains(rdkit_mol) | ||
|
||
|
||
def test_calculate_pains_fail(): | ||
"""Test a failing case of calculate_pains().""" | ||
pains_mol = Chem.MolFromSmiles("CC(=O)NCC1CN(C(=O)O1)C2=CC(=C(C=C2)N3CCOCC3)F") | ||
assert calculate_pains(pains_mol) | ||
|
||
|
||
def test_calculate_brenk_pass(rdkit_mol): | ||
"""Test a passing case of calculate_brenk().""" | ||
assert not calculate_brenk(rdkit_mol) | ||
|
||
|
||
def test_calculate_brenk_fail(): | ||
"""Test a failing case of calculate_brenk().""" | ||
brenk_mol = Chem.MolFromSmiles("OCOCC(COc1ccc(c(c1C(=O)Oc1ccc(cc1N)N1CCNCC1)N)OC)O") | ||
assert calculate_brenk(brenk_mol) | ||
|
||
|
||
def test_calculate_zinc_pass(rdkit_mol): | ||
"""Test a passing case of calculate_zinc().""" | ||
assert not calculate_zinc(rdkit_mol) | ||
|
||
|
||
def test_calculate_zinc_fail(): | ||
"""Test a failing case of calculate_zinc().""" | ||
zinc_mol = Chem.MolFromSmiles( | ||
"CC1=C2C(C(=O)C3(C(CC4C(C3C(C(C2(C)C)(CC1OC(=O)C(C(C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C" | ||
) | ||
assert calculate_zinc(zinc_mol) | ||
|
||
|
||
def test_calculate_leadlikeness_pass(rdkit_mol): | ||
"""Test a passing case of calculate_leadlikeness().""" | ||
mol = Chem.MolFromSmiles("COc1ccc2c(c1)nc([nH]2)S(=O)Cc1ncc(c(c1C)OC)C") | ||
result = calculate_leadlikeness(mol) | ||
expected_result = "Yes" | ||
assert result == expected_result | ||
|
||
|
||
def test_calculate_leadlikeness_fail(rdkit_mol): | ||
"""Test a failing case of calculate_leadlikeness().""" | ||
result = calculate_leadlikeness(rdkit_mol) | ||
expected_violations = { | ||
"MW": "MW: 92.14099999999999 is outside the acceptable range (250-350)", | ||
} | ||
|
||
assert isinstance(result, dict) | ||
assert result == expected_violations | ||
|
||
|
||
def test_calculate_synthetic_accessibility(rdkit_mol): | ||
"""Test the result of calculate_synthetic_accessibility().""" | ||
result = calculate_synthetic_accessiblity(rdkit_mol) | ||
expected_result = 1.0 | ||
|
||
assert result == expected_result |