import argparse import os import numpy as np import pandas as pd import torch as th from joblib import Parallel, delayed from onescience.datapipes.genscore.feats.mol2graph_rdmda_res import mol_to_graph2 def parse_args(): parser = argparse.ArgumentParser(description="Preprocess PDBbind complexes for GenScore training.") parser.add_argument( "-d", "--dir", default=".", help="Directory containing PDBbind-style protein-ligand complex folders.", ) parser.add_argument( "-c", "--cutoff", default=10.0, type=float, help="Pocket cutoff used in pocket file names and graph construction.", ) parser.add_argument( "-o", "--outprefix", default="out", help="Output prefix for generated _ids.npy, _prot.pt, and _lig.pt files.", ) parser.add_argument( "-r", "--ref", default="pdbbind_2020_general.csv", help="CSV containing labels indexed by PDB id with a labels column.", ) parser.add_argument( "-usH", "--useH", default=False, action="store_true", help="Use explicit hydrogen atoms.", ) parser.add_argument( "-uschi", "--use_chirality", default=False, action="store_true", help="Use chirality features.", ) parser.add_argument( "-p", "--parallel", default=False, action="store_true", help="Build graphs in parallel.", ) return parser.parse_args() def _label_query(pdbid, labels): return labels.loc[pdbid, "labels"] def _pdbbind_paths(root_dir, pdbid, cutoff): complex_dir = os.path.join(root_dir, pdbid, f"{pdbid}_prot") prot_path = os.path.join(complex_dir, f"{pdbid}_p_pocket_{cutoff}.pdb") lig_path = os.path.join(complex_dir, f"{pdbid}_l.sdf") return prot_path, lig_path def _pdbbind_handle(pdbid, args, labels): prot_path, lig_path = _pdbbind_paths(args.dir, pdbid, args.cutoff) try: graph_prot, graph_lig = mol_to_graph2( prot_path, lig_path, cutoff=args.cutoff, explicit_H=args.useH, use_chirality=args.use_chirality, ) except Exception as exc: print(f"{pdbid} failed to generate graph: {exc}") return None return pdbid, graph_prot, graph_lig, _label_query(pdbid, labels) def main(): args = parse_args() labels = pd.read_csv(args.ref, index_col=0, header=0) pdbids = [ name for name in os.listdir(args.dir) if os.path.isdir(os.path.join(args.dir, name)) ] if args.parallel: results = Parallel(n_jobs=-1)( delayed(_pdbbind_handle)(pdbid, args, labels) for pdbid in pdbids ) else: results = [_pdbbind_handle(pdbid, args, labels) for pdbid in pdbids] results = [item for item in results if item is not None] if not results: raise RuntimeError("No valid PDBbind complexes were converted.") ids, graphs_p, graphs_l, label_values = list(zip(*results)) np.save(f"{args.outprefix}_ids", (ids, label_values)) th.save(graphs_p, f"{args.outprefix}_prot.pt") th.save(graphs_l, f"{args.outprefix}_lig.pt") if __name__ == "__main__": main()