From 7b836ed4d5bedbc478b6fd91f880791ff488bfc0 Mon Sep 17 00:00:00 2001 From: Kohulan Date: Tue, 7 Mar 2023 19:17:28 +0100 Subject: [PATCH] feat: descriptor calculations using RDKit --- app/modules/descriptor_calculator.py | 64 ++++++++++++++++++++++++++++ app/routers/chem.py | 4 +- 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 app/modules/descriptor_calculator.py diff --git a/app/modules/descriptor_calculator.py b/app/modules/descriptor_calculator.py new file mode 100644 index 0000000..e5cda3c --- /dev/null +++ b/app/modules/descriptor_calculator.py @@ -0,0 +1,64 @@ +from rdkit import Chem +from rdkit.Chem import Descriptors, QED, Lipinski, rdMolDescriptors, rdmolops + + +def checkRo5Violations(mol): + """Takes a molecules and checks whether the molecule violates + the Lipinski's Rule of Five. + Args : molecules rdkit.Chem.rdmol.Mol: rdkit_mol Objects + Returns (int): A number of violations on Lipinski Rules. + """ + num_of_violations = 0 + if Descriptors.MolLogP(mol) > 5: + rule_break += 1 + if Descriptors.MolWt(mol) > 500: + rule_break += 1 + if Lipinski.NumHAcceptors(mol) > 10: + rule_break += 1 + if Lipinski.NumHDonors(mol) > 5: + rule_break += 1 + return num_of_violations + + +def GetBasicDescriptors(smiles): + """Take an input SMILES and generates a selected set of molecular + descriptors as a dictionary + Args (str): SMILES string + Returns (dict): a dictionary of calculated descriptors + """ + mol = Chem.MolFromSmiles(smiles) + AtomC = rdMolDescriptors.CalcNumAtoms(mol) + HeavyAtomsC = rdMolDescriptors.CalcNumHeavyAtoms(mol) + MolWt = "%.2f" % Descriptors.MolWt(mol) + ExactMolWt = "%.2f" % Descriptors.ExactMolWt(mol) + ALogP = "%.2f" % QED.properties(mol).ALOGP + NumRotatableBonds = rdMolDescriptors.CalcNumRotatableBonds(mol) + PSA = "%.2f" % rdMolDescriptors.CalcTPSA(mol) + HBA = Descriptors.NumHAcceptors(mol) + HBD = Descriptors.NumHDonors(mol) + Lipinski_HBA = Lipinski.NumHAcceptors(mol) + Lipinski_HBD = Lipinski.NumHDonors(mol) + Ro5Violations = checkRo5Violations(mol) + AromaticRings = rdMolDescriptors.CalcNumAromaticRings(mol) + QEDWeighted = "%.2f" % QED.qed(mol) + FormalCharge = "%.2f" % rdmolops.GetFormalCharge(mol) + + AllDescriptors = { + "Atom count": AtomC, + "Heavy atom count": HeavyAtomsC, + "Molecular weight": MolWt, + "Exact molecular weight": ExactMolWt, + "ALogP": ALogP, + "Rotatable bond count": NumRotatableBonds, + "Topological polar surface area": PSA, + "Hydrogen bond acceptors": HBA, + "Hydrogen bond donors": HBD, + "Hydrogen bond acceptors(Lipinski)": Lipinski_HBA, + "Hydrogen bond donors(Lipinski)": Lipinski_HBD, + "Lipinski's rule of five violations": Ro5Violations, + "Aromatic rings count": AromaticRings, + "QED drug likeliness": QEDWeighted, + "Formal Charge": FormalCharge, + } + + return AllDescriptors diff --git a/app/routers/chem.py b/app/routers/chem.py index 22c005d..19c350b 100644 --- a/app/routers/chem.py +++ b/app/routers/chem.py @@ -15,6 +15,7 @@ from rdkit.Chem.rdMolDescriptors import Properties from STOUT import translate_forward, translate_reverse from app.modules.npscorer import getnp_score +from app.modules.descriptor_calculator import GetBasicDescriptors router = APIRouter( prefix="/chem", @@ -96,8 +97,7 @@ async def standardise_mol(request: Request): @router.get("/{smiles}/descriptors") async def smiles_descriptors(smiles: Optional[str]): if smiles: - m = Chem.MolFromSmiles(smiles) - return properties(m) + return GetBasicDescriptors(smiles) @router.get("/{smiles}/iupac")