| import argparse |
| import os |
| import pickle |
|
|
| import pandas as pd |
| from joblib import Parallel, delayed |
|
|
| from _common import add_model_args, formatter, runtime_kwargs, score_ligand_file |
|
|
|
|
| def parse_args(): |
| parser = argparse.ArgumentParser( |
| description="Run GenScore CASF-2016 screening benchmark.", |
| formatter_class=formatter(), |
| ) |
| add_model_args(parser) |
| parser.add_argument("--casf-dir", required=True, help="CASF-2016 root directory.") |
| parser.add_argument("--pdbbind-dir", required=True, help="PDBbind root directory.") |
| parser.add_argument("--outdir", required=True, help="Directory for CASF screening score .dat files.") |
| parser.add_argument("--decoys-subdir", default="decoys_screening") |
| parser.add_argument("--coreset-subdir", default="coreset") |
| parser.add_argument("--refined-subdir", default="v2020-refined") |
| parser.add_argument("--other-pl-subdir", default="v2020-other-PL") |
| parser.add_argument("--parallel", action="store_true", default=False) |
| return parser.parse_args() |
|
|
|
|
| def _complex_ids(path): |
| return [name for name in os.listdir(path) if os.path.isdir(os.path.join(path, name))] |
|
|
|
|
| def _pocket_path(pdbbind_dir, subset, pdbid, cutoff): |
| return os.path.join( |
| pdbbind_dir, |
| subset, |
| pdbid, |
| f"{pdbid}_prot", |
| f"{pdbid}_p_pocket_{cutoff}.pdb", |
| ) |
|
|
|
|
| def _ligand_path(root, stem): |
| candidates = [os.path.join(root, f"{stem}.{extension}") for extension in ("mol2", "sdf")] |
| for path in candidates: |
| if os.path.isfile(path): |
| return path |
| raise FileNotFoundError( |
| f"No ligand file found for {stem}. Checked: {', '.join(candidates)}" |
| ) |
|
|
|
|
| def score_compound(pdbid, ligid, subset, args): |
| prot = _pocket_path(args.pdbbind_dir, subset, pdbid, args.cutoff) |
| root = os.path.join(args.casf_dir, args.decoys_subdir, pdbid) |
| lig = _ligand_path(root, f"{pdbid}_{ligid}") |
| return score_ligand_file(prot, lig, args, parallel=True) |
|
|
|
|
| def score_target(pdbid, subset, ligids, args): |
| print(f"{pdbid} started.....") |
| ids_list = [] |
| scores_list = [] |
| for ligid in ligids: |
| ids, scores = score_compound(pdbid, ligid, subset, args) |
| if ids is not None and scores is not None: |
| ids_list.extend(ids) |
| scores_list.extend(scores) |
| print(f"{pdbid} finished.....") |
| return pdbid, [ids_list, scores_list] |
|
|
|
|
| def run_for_subset(pdbids, subset, ligids, args): |
| if args.parallel and runtime_kwargs(args)["device"] == "cpu": |
| return Parallel(n_jobs=-1, backend="threading")( |
| delayed(score_target)(pdbid, subset, ligids, args) for pdbid in pdbids |
| ) |
| return [score_target(pdbid, subset, ligids, args) for pdbid in pdbids] |
|
|
|
|
| def main(): |
| args = parse_args() |
| ligids = _complex_ids(os.path.join(args.casf_dir, args.coreset_subdir)) |
| pdbids = _complex_ids(os.path.join(args.casf_dir, args.decoys_subdir)) |
| refined_ids = set(_complex_ids(os.path.join(args.pdbbind_dir, args.refined_subdir))) |
| other_ids = set(_complex_ids(os.path.join(args.pdbbind_dir, args.other_pl_subdir))) |
|
|
| ids_refined = [pdbid for pdbid in pdbids if pdbid in refined_ids] |
| ids_other = [pdbid for pdbid in pdbids if pdbid in other_ids] |
|
|
| results = run_for_subset(ids_refined, args.refined_subdir, ligids, args) |
| results += run_for_subset(ids_other, args.other_pl_subdir, ligids, args) |
|
|
| os.makedirs(args.outdir, exist_ok=True) |
| for pdbid, payload in results: |
| df = pd.DataFrame(zip(*payload), columns=["#code_ligand_num", "score"]) |
| df["#code_ligand_num"] = df["#code_ligand_num"].str.split("-").apply(lambda item: item[0]) |
| df.to_csv(os.path.join(args.outdir, f"{pdbid}_score.dat"), index=False, sep="\t") |
|
|
| with open(f"{args.outprefix}_screening.pkl", "wb") as handle: |
| pickle.dump(results, handle) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|