| |
| """Unified PDB-directory inference entry point for dl_binder_design.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import subprocess |
| import sys |
| from pathlib import Path |
|
|
|
|
| ROOT = Path(__file__).resolve().parents[1] |
| CONFIG_PATH = ROOT / "conf" / "config.json" |
| MPNN_SCRIPT = ROOT / "model" / "mpnn_fr" / "dl_interface_design.py" |
| AF2_SCRIPT = ROOT / "model" / "af2_initial_guess" / "predict.py" |
|
|
|
|
| def load_config() -> dict: |
| with CONFIG_PATH.open(encoding="utf-8") as handle: |
| return json.load(handle) |
|
|
|
|
| def package_path(value: str) -> Path: |
| path = Path(value).expanduser() |
| return path if path.is_absolute() else ROOT / path |
|
|
|
|
| def require_file(path: Path, label: str) -> None: |
| if not path.is_file() or path.stat().st_size == 0: |
| raise SystemExit(f"Missing {label}: {path}") |
|
|
|
|
| def run(command: list[str]) -> None: |
| print("Running:", " ".join(command), flush=True) |
| subprocess.run(command, cwd=ROOT, check=True) |
|
|
|
|
| def run_mpnn(args: argparse.Namespace, config: dict, output_dir: Path) -> Path: |
| checkpoint = package_path(args.mpnn_checkpoint) |
| require_file(checkpoint, "ProteinMPNN checkpoint") |
| require_file( |
| ROOT / "model" / "mpnn_fr" / "ProteinMPNN" / "protein_mpnn_utils.py", |
| "ProteinMPNN source file", |
| ) |
| output_dir.mkdir(parents=True, exist_ok=True) |
| command = [ |
| sys.executable, |
| str(MPNN_SCRIPT), |
| "-pdbdir", |
| str(package_path(args.input_dir)), |
| "-outpdbdir", |
| str(output_dir), |
| "-checkpoint_name", |
| str(output_dir.parent / f"{output_dir.name}.checkpoint"), |
| "-checkpoint_path", |
| str(checkpoint), |
| "-relax_cycles", |
| str(args.relax_cycles), |
| "-seqs_per_struct", |
| str(args.seqs_per_struct), |
| ] |
| if args.runlist: |
| command.extend(["-runlist", str(package_path(args.runlist))]) |
| if args.debug: |
| command.append("-debug") |
| run(command) |
| return output_dir |
|
|
|
|
| def run_af2(args: argparse.Namespace, input_dir: Path, output_dir: Path) -> None: |
| require_file( |
| ROOT / "weight" / "AlphaFold2" / "params" / "params_model_1_ptm.npz", |
| "AlphaFold2 model_1_ptm parameters", |
| ) |
| output_dir.mkdir(parents=True, exist_ok=True) |
| command = [ |
| sys.executable, |
| str(AF2_SCRIPT), |
| "-pdbdir", |
| str(input_dir), |
| "-outpdbdir", |
| str(output_dir), |
| "-checkpoint_name", |
| str(output_dir.parent / f"{output_dir.name}.checkpoint"), |
| "-scorefilename", |
| str(output_dir.parent / f"{output_dir.name}.sc"), |
| "-recycle", |
| str(args.recycle), |
| ] |
| if args.runlist: |
| command.extend(["-runlist", str(package_path(args.runlist))]) |
| if args.debug: |
| command.append("-debug") |
| run(command) |
|
|
|
|
| def add_shared_arguments(parser: argparse.ArgumentParser, config: dict) -> None: |
| parser.add_argument("--input-dir", default=config["sample_input_dir"]) |
| parser.add_argument("--output-dir", default=config["output_dir"]) |
| parser.add_argument("--runlist", default="") |
| parser.add_argument("--debug", action="store_true") |
|
|
|
|
| def main() -> None: |
| config = load_config() |
| parser = argparse.ArgumentParser(description=__doc__) |
| subparsers = parser.add_subparsers(dest="stage", required=True) |
|
|
| mpnn = subparsers.add_parser("mpnn", help="run ProteinMPNN with optional FastRelax") |
| add_shared_arguments(mpnn, config) |
| mpnn.add_argument("--mpnn-checkpoint", default=config["proteinmpnn_checkpoint"]) |
| mpnn.add_argument("--relax-cycles", type=int, default=config["relax_cycles"]) |
| mpnn.add_argument("--seqs-per-struct", type=int, default=config["seqs_per_struct"]) |
|
|
| af2 = subparsers.add_parser("af2", help="run AlphaFold2 initial-guess prediction") |
| add_shared_arguments(af2, config) |
| af2.add_argument("--recycle", type=int, default=config["recycle"]) |
|
|
| pipeline = subparsers.add_parser("pipeline", help="run ProteinMPNN/FastRelax then AF2") |
| add_shared_arguments(pipeline, config) |
| pipeline.add_argument("--mpnn-checkpoint", default=config["proteinmpnn_checkpoint"]) |
| pipeline.add_argument("--relax-cycles", type=int, default=config["relax_cycles"]) |
| pipeline.add_argument("--seqs-per-struct", type=int, default=config["seqs_per_struct"]) |
| pipeline.add_argument("--recycle", type=int, default=config["recycle"]) |
|
|
| args = parser.parse_args() |
| base_output = package_path(args.output_dir) |
| if args.stage == "mpnn": |
| run_mpnn(args, config, base_output) |
| elif args.stage == "af2": |
| run_af2(args, package_path(args.input_dir), base_output) |
| else: |
| mpnn_output = run_mpnn(args, config, base_output / "mpnn") |
| |
| |
| args.runlist = "" |
| run_af2(args, mpnn_output, base_output / "af2") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|