DrugTargetAnalyzer / services /validator.py
ArsalanJ's picture
rwtw
a72e6a5
Raw
History Blame Contribute Delete
1.75 kB
from rdkit import Chem
from rdkit.Chem import Crippen, Descriptors, QED
def _calc_props(smiles: str) -> dict | None:
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
mw = Descriptors.MolWt(mol)
logp = Crippen.MolLogP(mol)
hbd = Descriptors.NumHDonors(mol)
hba = Descriptors.NumHAcceptors(mol)
rot = Descriptors.NumRotatableBonds(mol)
tpsa = Descriptors.TPSA(mol)
qed = float(QED.qed(mol))
return {
"mw": float(mw),
"logp": float(logp),
"hbd": int(hbd),
"hba": int(hba),
"rotatable_bonds": int(rot),
"tpsa": float(tpsa),
"qed": float(qed),
}
def filter_molecules(candidates: list[dict]) -> list[dict]:
"""Apply basic drug-likeness heuristics (Lipinski-ish + QED)."""
filtered: list[dict] = []
for c in candidates:
smiles = (c or {}).get("smiles")
if not smiles or not isinstance(smiles, str):
continue
props = _calc_props(smiles)
if props is None:
out = dict(c)
out["passes_filter"] = False
out["parse_error"] = True
filtered.append(out)
continue
passes = True
if not (150 <= props["mw"] <= 500):
passes = False
if props["logp"] > 5:
passes = False
if props["hbd"] > 5:
passes = False
if props["hba"] > 10:
passes = False
if props["qed"] < 0.3:
passes = False
out = dict(c)
out.update(props)
out["passes_filter"] = passes
filtered.append(out)
filtered.sort(key=lambda x: (x.get("score") is None, -(x.get("score") or 0), -x.get("qed", 0)))
return filtered