diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 914cb6a..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -recursive-include abcfold *.js *.css *.html *.svg *.png *.jinja2 -recursive-include abcfold/plots/pae-viewer-main/src/templates *.tpl diff --git a/abcfold/abcfold.py b/abcfold/abcfold.py deleted file mode 100644 index 19ab535..0000000 --- a/abcfold/abcfold.py +++ /dev/null @@ -1,673 +0,0 @@ -import configparser -import json -import os -import shutil -import socketserver -import sys -import tempfile -import webbrowser -from pathlib import Path -from typing import Any, Dict, List, Union - -from abcfold.alphafold3.run_alphafold3 import run_alphafold3 -from abcfold.argparse_utils import (alphafold_argparse_util, - boltz_argparse_util, chai_argparse_util, - custom_template_argpase_util, - main_argpase_util, mmseqs2_argparse_util, - openfold_argparse_util, - prediction_argparse_util, - protenix_argparse_util, - raise_argument_errors, - rosettafold_argparse_util, - visuals_argparse_util) -from abcfold.html.html_utils import (PORT, NoCacheHTTPRequestHandler, - get_all_cif_files, get_model_data, - get_model_sequence_data, - output_open_html_script, plots, - render_template) -from abcfold.output.alphafold3 import AlphafoldOutput -from abcfold.output.boltz import BoltzOutput -from abcfold.output.chai import ChaiOutput -from abcfold.output.file_handlers import superpose_models -from abcfold.output.openfold3 import OpenfoldOutput -from abcfold.output.protenix import ProtenixOutput -from abcfold.output.rosettafold3 import RosettafoldOutput -from abcfold.output.utils import (get_gap_indicies, insert_none_by_minus_one, - make_dummy_m8_file, verify_config_file) -from abcfold.scripts.abc_script_utils import (check_input_json, make_dir, - make_dummy_af3_db, setup_logger) -from abcfold.scripts.add_custom_template import add_custom_template -from abcfold.scripts.add_mmseqs_msa import add_msa_to_json - -logger = setup_logger() - -HTML_DIR = Path(__file__).parent / "html" -HTML_TEMPLATE = HTML_DIR.joinpath("abcfold.html.jinja2") -PLOTS_DIR = ".plots" - -ModelOutput = Union[ - AlphafoldOutput, - BoltzOutput, - ChaiOutput, - ProtenixOutput, - OpenfoldOutput, - RosettafoldOutput, -] - - -def run(args, config, defaults, config_file): - """Run ABCFold - - Args: - args (argparse.Namespace): Arguments from the command line - config (configparser.ConfigParser): Config parser object - defaults (dict): Default values from the config file - config_file (Path): Path to the config file - - - Raises: - SystemExit: If the database directory or model parameters directory is not found - - - """ - outputs: List[ModelOutput] = [] - - args.output_dir = Path(args.output_dir) - - if args.mmseqs2: - logger.info("MMSeqs2 Selected, all other MSAs will be ignored") - - make_dir(args.output_dir, overwrite=args.override) - make_dir(args.output_dir.joinpath(PLOTS_DIR)) - - updated_config = False - if args.model_params is not None and args.model_params != defaults["model_params"]: - config.set("Weights", "model_params", args.model_params) - updated_config = True - if args.database_dir is not None and args.database_dir != defaults["database_dir"]: - config.set("Databases", "database_dir", args.database_dir) - updated_config = True - af3_sif = args.af3_sif_path - if af3_sif is not None and af3_sif != defaults.get("af3_sif_path"): - config.set("Sif_paths", "af3_sif_path", af3_sif) - updated_config = True - if updated_config: - with open(config_file, "w") as f: - config.write(f) - - rt_config = {} - for section in config.sections(): - rt_config.update(dict(config.items(section))) - - args = raise_argument_errors(args) - # Ensure that the input json file is valid - args.input_json = check_input_json( - args.input_json, - output_dir=args.output_dir, - use_af3_templates=args.use_af3_template_search, - ) - - with open(args.input_json, "r") as f: - input_params = json.load(f) - - name = input_params.get("name") - if name is None: - logger.error("Input JSON must contain a 'name' field") - sys.exit(1) - - with tempfile.TemporaryDirectory() as temp_dir_str: - temp_dir = Path(temp_dir_str) - if args.mmseqs2: - if not args.output_json: - input_json = Path(args.input_json) - run_json = temp_dir.joinpath( - input_json.name.replace(".json", "_mmseqs.json") - ) - else: - input_json = Path(args.input_json) - run_json = Path(args.output_json) - - input_params = add_msa_to_json( - input_json=input_json, - mmseqs_db=args.mmseqs_database, - templates=args.templates, - num_templates=args.num_templates, - chai_template_output=temp_dir.joinpath("all_chains.m8"), - input_params=input_params, - output_json=run_json, - to_file=True, - ) - else: - run_json = Path(args.input_json) - - if args.custom_template is not None: - add_custom_template( - run_json, - args.target_id, - args.custom_template, - args.custom_template_chain, - output_json=run_json, - to_file=True, - ) - - successful_runs = [] - if args.alphafold3: - af3_database = args.database_dir - use_precomputed_msas = args.mmseqs2 or any( - seq.get("protein", {}).get("unpairedMsa") - or seq.get("protein", {}).get("unpairedMsaPath") - for seq in input_params["sequences"] - ) - if use_precomputed_msas: - af3_database = make_dummy_af3_db(temp_dir) - - af3_output_dir = run_alphafold3( - input_json=run_json, - output_dir=args.output_dir, - model_params=args.model_params, - database_dir=af3_database, - number_of_models=args.number_of_models, - num_recycles=args.num_recycles, - sif_path=af3_sif, - save_distogram=args.save_distogram, - gpus=args.gpus, - config=rt_config, - use_precomputed_msas=use_precomputed_msas, - ) - af3_success = af3_output_dir is not None - - if af3_success: - assert af3_output_dir is not None - ao = AlphafoldOutput(af3_output_dir, input_params, name) - outputs.append(ao) - run_json = ao.input_json - successful_runs.append(af3_success) - - if args.boltz: - from abcfold.boltz.run_boltz import run_boltz - - boltz_success = run_boltz( - input_json=run_json, - output_dir=args.output_dir, - save_input=args.save_input, - number_of_models=args.number_of_models, - num_recycles=args.num_recycles, - gpus=args.gpus, - config=rt_config, - boltz_mode=args.boltz_mode, - boltz_crystal_structure=args.boltz_crystal_structure, - boltz_ligand_chain=args.boltz_ligand_chain, - boltz_template_chain_id=args.boltz_template_chain_id, - boltz_template_id=args.boltz_template_id, - boltz_template_force=args.boltz_template_force, - boltz_template_threshold=args.boltz_template_threshold, - boltz_pocket_radius=args.boltz_pocket_radius, - boltz_pocket_max_distance=args.boltz_pocket_max_distance, - boltz_pocket_force=args.boltz_pocket_force, - preprocessing_threads=args.boltz_preprocessing_threads, - num_workers=args.boltz_num_workers, - max_parallel_samples=args.boltz_max_parallel_samples, - ) - - if boltz_success: - bolt_out_dirs = list(args.output_dir.glob("boltz_results*")) - bo = BoltzOutput(bolt_out_dirs, input_params, name, args.save_input) - outputs.append(bo) - successful_runs.append(boltz_success) - - if args.chai1: - from abcfold.chai1.run_chai1_fast import run_chai_fast as run_chai - - template_hits_path = None - if args.templates and args.mmseqs2: - template_hits_path = temp_dir.joinpath("all_chains.m8") - elif args.templates: - template_hits_path = make_dummy_m8_file(run_json, temp_dir) - - chai_success = run_chai( - input_json=run_json, - output_dir=args.output_dir, - save_input=args.save_input, - number_of_models=args.number_of_models, - num_recycles=args.num_recycles, - template_hits_path=template_hits_path, - device=args.gpus, - config=rt_config, - ) - - if chai_success: - chai_output_dirs = list(args.output_dir.glob("chai_output*")) - co = ChaiOutput( - chai_output_dirs, input_params, name, rt_config, args.save_input - ) - outputs.append(co) - successful_runs.append(chai_success) - - if args.protenix: - from abcfold.protenix.run_protenix import run_protenix - - protenix_success = run_protenix( - input_json=run_json, - output_dir=args.output_dir, - save_input=args.save_input, - number_of_models=args.number_of_models, - num_recycles=args.num_recycles, - config=rt_config, - ) - - if protenix_success: - protenix_output_dirs = list(args.output_dir.glob("protenix_results*")) - po = ProtenixOutput( - protenix_output_dirs, input_params, name, args.save_input - ) - outputs.append(po) - successful_runs.append(protenix_success) - - if args.openfold3: - from abcfold.openfold3.run_openfold3 import run_openfold - - template_hits_path = None - if args.templates and args.mmseqs2: - template_hits_path = temp_dir.joinpath("all_chains.m8") - - openfold_success = run_openfold( - input_json=run_json, - output_dir=args.output_dir, - save_input=args.save_input, - number_of_models=args.number_of_models, - template_hits_path=template_hits_path, - input_ckpt=args.inference_ckpt_path, - config=rt_config, - ) - - if openfold_success: - openfold_output_dirs = list(args.output_dir.glob("openfold_results*")) - oo = OpenfoldOutput( - openfold_output_dirs, input_params, name, args.save_input - ) - outputs.append(oo) - successful_runs.append(openfold_success) - - if args.rosettafold3: - from abcfold.rosettafold3.run_rosettafold3 import run_rosettafold - - rosettafold_success = run_rosettafold( - input_json=run_json, - output_dir=args.output_dir, - save_input=args.save_input, - number_of_models=args.number_of_models, - config=rt_config, - ) - - if rosettafold_success: - rosettafold_output_dirs = list( - args.output_dir.glob("rosettafold_results*") - ) - ro = RosettafoldOutput( - rosettafold_output_dirs, input_params, name, args.save_input - ) - outputs.append(ro) - successful_runs.append(rosettafold_success) - - if args.no_visuals: - logger.info("Visuals disabled") - return - - if not any(successful_runs): - logger.error("No models were generated") - return - - plot_dict = plots(outputs, args.output_dir.joinpath(PLOTS_DIR)) - - # Compile data to make output page - programs_run = [] - cif_models = [ - cif_file - for cif_list in get_all_cif_files(outputs).values() - for cif_file in cif_list - ] - indicies = get_gap_indicies(*cif_models) - index_counter = 0 - - alphafold_models: Dict[str, List[Dict[str, Any]]] = {"models": []} - - if args.alphafold3: - if af3_success: - programs_run.append("AlphaFold3") - for seed in ao.output.keys(): - for idx in ao.output[seed].keys(): - model = ao.output[seed][idx]["cif"] - model.check_clashes() - score_file = ao.output[seed][idx]["summary"] - plddt = model.residue_plddts - pae = ao.output[seed][idx]["af3_pae"] - if len(indicies) > 0: - plddt = insert_none_by_minus_one( - indicies[index_counter], plddt - ) - index_counter += 1 - model_data = get_model_data( - model, - plot_dict, - "AlphaFold3", - plddt, - pae, - score_file, - args.output_dir, - ) - alphafold_models["models"].append(model_data) - - boltz_models: Dict[str, List[Dict[str, Any]]] = {"models": []} - if args.boltz: - if boltz_success: - programs_run.append("Boltz") - for seed in bo.output.keys(): - for idx in bo.output[seed].keys(): - model = bo.output[seed][idx]["cif"] - model.check_clashes() - score_file = bo.output[seed][idx]["json"] - plddt = model.residue_plddts - pae = bo.output[seed][idx]["af3_pae"] - if len(indicies) > 0: - plddt = insert_none_by_minus_one( - indicies[index_counter], plddt - ) - index_counter += 1 - model_data = get_model_data( - model, - plot_dict, - "Boltz", - plddt, - pae, - score_file, - args.output_dir, - ) - boltz_models["models"].append(model_data) - - chai_models: Dict[str, List[Dict[str, Any]]] = {"models": []} - if args.chai1: - if chai_success: - programs_run.append("Chai-1") - for seed in co.output.keys(): - for idx in co.output[seed].keys(): - if idx >= 0: - model = co.output[seed][idx]["cif"] - model.check_clashes() - score_file = co.output[seed][idx]["scores"] - plddt = model.residue_plddts - pae = co.output[seed][idx]["af3_pae"] - if len(indicies) > 0: - plddt = insert_none_by_minus_one( - indicies[index_counter], plddt - ) - index_counter += 1 - model_data = get_model_data( - model, - plot_dict, - "Chai-1", - plddt, - pae, - score_file, - args.output_dir, - ) - chai_models["models"].append(model_data) - - openfold_models: Dict[str, List[Dict[str, Any]]] = {"models": []} - if args.openfold3: - if openfold_success: - programs_run.append("OpenFold3") - for seed in oo.output.keys(): - for idx in oo.output[seed].keys(): - if idx >= 0: - model = oo.output[seed][idx]["cif"] - model.check_clashes() - score_file = oo.output[seed][idx]["scores"] - plddt = model.residue_plddts - pae = oo.output[seed][idx]["af3_pae"] - if len(indicies) > 0: - plddt = insert_none_by_minus_one( - indicies[index_counter], plddt - ) - index_counter += 1 - model_data = get_model_data( - model, - plot_dict, - "OpenFold3", - plddt, - pae, - score_file, - args.output_dir, - ) - openfold_models["models"].append(model_data) - - protenix_models: Dict[str, List[Dict[str, Any]]] = {"models": []} - if args.protenix: - if protenix_success: - programs_run.append("Protenix") - for seed in po.output.keys(): - for idx in po.output[seed].keys(): - if idx >= 0: - model = po.output[seed][idx]["cif"] - model.check_clashes() - score_file = po.output[seed][idx]["scores"] - plddt = model.residue_plddts - pae = po.output[seed][idx]["af3_pae"] - if len(indicies) > 0: - plddt = insert_none_by_minus_one( - indicies[index_counter], plddt - ) - index_counter += 1 - model_data = get_model_data( - model, - plot_dict, - "Protenix", - plddt, - pae, - score_file, - args.output_dir, - ) - protenix_models["models"].append(model_data) - - rosettafold_models: Dict[str, List[Dict[str, Any]]] = {"models": []} - if args.rosettafold3: - if rosettafold_success: - programs_run.append("RosettaFold3") - for seed in ro.output.keys(): - for idx in ro.output[seed].keys(): - if idx >= 0: - model = ro.output[seed][idx]["cif"] - model.check_clashes() - score_file = ro.output[seed][idx]["scores"] - plddt = model.residue_plddts - pae = ro.output[seed][idx]["af3_pae"] - if len(indicies) > 0: - plddt = insert_none_by_minus_one( - indicies[index_counter], plddt - ) - index_counter += 1 - model_data = get_model_data( - model, - plot_dict, - "RosettaFold3", - plddt, - pae, - score_file, - args.output_dir, - ) - rosettafold_models["models"].append(model_data) - - combined_models = ( - alphafold_models["models"] - + boltz_models["models"] - + chai_models["models"] - + openfold_models["models"] - + protenix_models["models"] - + rosettafold_models["models"] - ) - - # Make the output directory for the models - os.makedirs(args.output_dir.joinpath("output_models"), exist_ok=True) - output_models = [] - for model in combined_models: - cif_file = args.output_dir.joinpath(model["model_path"]) - if model["model_source"] == "AlphaFold3": - output_name = "af3_model_" + model["model_id"][-1] + ".cif" - elif model["model_source"] == "Boltz": - output_name = "boltz_model_" + model["model_id"][-1] + ".cif" - elif model["model_source"] == "Chai-1": - output_name = "chai_model_" + model["model_id"][-1] + ".cif" - elif model["model_source"] == "OpenFold3": - output_name = "openfold_model_" + model["model_id"][-1] + ".cif" - elif model["model_source"] == "Protenix": - output_name = "protenix_model_" + model["model_id"][-1] + ".cif" - elif model["model_source"] == "RosettaFold3": - output_name = "rosettafold_model_" + model["model_id"][-1] + ".cif" - shutil.copy( - cif_file, - args.output_dir.joinpath("output_models").joinpath(output_name), - ) - output_models.append( - args.output_dir.joinpath("output_models").joinpath(output_name) - ) - # Superpose the models - if len(output_models) > 1: - superpose_models(output_models) - - sequence_data = get_model_sequence_data(cif_models) - sequence = "" - for key in sequence_data.keys(): - sequence += sequence_data[key] - chain_data = {} - ref = 0 - for key in sequence_data.keys(): - chain_data["Chain " + key] = (ref, len(sequence_data[key]) + ref - 1) - ref += len(sequence_data[key]) - results_dict = { - "sequence": sequence, - "models": combined_models, - "plotly_path": Path(plot_dict["plddt"]) - .relative_to(args.output_dir.resolve()) - .as_posix(), - "chain_data": chain_data, - } - results_json = json.dumps(results_dict) - - if not args.output_dir.joinpath(".feature_viewer").exists(): - shutil.copytree(HTML_DIR, args.output_dir / ".feature_viewer") - - if len(programs_run) > 1: - programs = ( - "Structure predictions for: " - + ", ".join(programs_run[:-1]) - + " and " - + programs_run[-1] - ) - else: - programs = "Structure predictions for: " + programs_run[0] - - # Create the index page - HTML_OUT = args.output_dir.joinpath("index.html") - html_out = Path(HTML_OUT).resolve() - render_template( - HTML_TEMPLATE, - html_out, - # kwargs appear as variables in the template - abcfold_html_dir=".feature_viewer", - programs=programs, - results_json=results_json, - version=0.1, - ) - logger.info(f"Output page written to {HTML_OUT}") - - # Change to the output directory to run the server - os.chdir(args.output_dir) - - # Make a script to open the output HTML file in the default web browser - output_open_html_script("open_output.py", port=PORT) - - if args.no_server: - logger.info("Server disabled") - logger.info("Run 'python open_output.py' in the output directory to \ -view the output pages") - return - - try: - # Start the server - with socketserver.TCPServer(("", PORT), NoCacheHTTPRequestHandler) as httpd: - logger.info( - f"Serving at port {PORT}: http://localhost:{PORT}/index.html" - ) - logger.info("Press Ctrl+C to stop the server") - # Open the main HTML page in the default web browser - webbrowser.open(f"http://localhost:{PORT}/index.html") - # Keep the server running - httpd.serve_forever() - except KeyboardInterrupt: - logger.info("Server stopped") - httpd.server_close() - sys.exit(0) - - -def main(): - """ - Run AlphaFold3 / Boltz / Chai-1 / OpenFold3 / Protenix / RosettaFold3 - """ - import argparse - - config_parser = argparse.ArgumentParser(add_help=False) - config_parser.add_argument( - "--config-file", - type=str, - default=str(Path.home() / ".abcfold_config.ini"), - help="Path to the config file. " - "If not provided, a config file will be created " - "at ~/.abcfold_config.ini with default values. " - "If a config file already exists at that location, it will be used.", - ) - config_args, remaining = config_parser.parse_known_args() - - defaults = {} - config_file = Path(config_args.config_file) - default_config_file = Path(__file__).parent.joinpath("data", "config.ini") - if not config_file.exists(): - shutil.copy(default_config_file, config_file) - else: - verify_config_file(config_file, default_config_file) - - config = configparser.ConfigParser() - config.read(str(config_file)) - for section in config.sections(): - defaults.update(dict(config.items(section))) - - parser = argparse.ArgumentParser( - description=( - "Run AlphaFold3 / Boltz / Chai-1 / OpenFold3 / Protenix / RosettaFold3" - ), - parents=[config_parser], - ) - - parser = main_argpase_util(parser) - parser = alphafold_argparse_util(parser) - parser = boltz_argparse_util(parser) - parser = chai_argparse_util(parser) - parser = openfold_argparse_util(parser) - parser = protenix_argparse_util(parser) - parser = rosettafold_argparse_util(parser) - parser = mmseqs2_argparse_util(parser) - parser = custom_template_argpase_util(parser) - parser = prediction_argparse_util(parser) - parser = visuals_argparse_util(parser) - - parser.set_defaults(**defaults) - args = parser.parse_args(remaining) - - run( - args, - config, - defaults, - config_file, - ) - - -if __name__ == "__main__": - main() diff --git a/abcfold/backend_envs.py b/abcfold/backend_envs.py deleted file mode 100644 index 903f60e..0000000 --- a/abcfold/backend_envs.py +++ /dev/null @@ -1,180 +0,0 @@ -import os -import shutil -import subprocess -import sys -from typing import Optional - - -def supports_cuda_wheels() -> bool: - return sys.platform.startswith("linux") - - -class MicromambaEnv: - def __init__(self, env_name: str): - self.env_name = env_name - self.micromamba = self._find_micromamba() - - @staticmethod - def _find_micromamba() -> str: - for candidate in [ - shutil.which("micromamba"), - os.path.expanduser("~/micromamba/bin/micromamba"), - os.path.expanduser("~/.local/bin/micromamba"), - ]: - if candidate and os.path.exists(candidate): - return candidate - raise RuntimeError( - "micromamba binary not found. " - "Ensure micromamba is installed and on PATH." - ) - - def get_installed_version(self, package: str) -> Optional[str]: - """ - Return installed version of `package` inside the env, - or None if the package is not installed. - """ - code = ( - "from importlib.metadata import version, PackageNotFoundError\n" - "import sys\n" - f"pkg='{package}'\n" - "try:\n" - " print(version(pkg))\n" - "except PackageNotFoundError:\n" - " sys.exit(1)" - ) - - try: - out = subprocess.check_output( - [ - self.micromamba, - "run", - "-n", self.env_name, - "python", - "-c", code, - ], - text=True, - ) - return out.strip() - except subprocess.CalledProcessError: - return None - - def ensure_package(self, package: str, version: Optional[str] = None): - """ - Ensure a package (optionally pinned to a version) is installed. - """ - installed = self.get_installed_version(package) - - if installed is not None: - if version is None or installed == version: - return - raise RuntimeError( - f"{package}=={installed} is installed in {self.env_name}, " - f"but {version} is required" - ) - - spec = f"{package}=={version}" if version else package - self.pip_install([spec]) - - def _run(self, args: list[str]): - return subprocess.check_call([self.micromamba, *args]) - - def env_exists(self) -> bool: - out = subprocess.check_output( - [self.micromamba, "env", "list"], - text=True, - ) - return any( - line.split()[0] == self.env_name - for line in out.splitlines() - if line.strip() - ) - - def create(self, *, python_version: str): - if self.env_exists(): - return - self._run([ - "create", - "-y", - "-n", self.env_name, - f"python={python_version}", - ]) - - def pip_install(self, packages: list[str]): - self._run([ - "run", - "-n", self.env_name, - "python", "-m", "pip", "install", - "--break-system-packages", - *packages, - ]) - - def conda_install( - self, - packages: list[str], - *, - channels: Optional[list[str]] = None, - ): - cmd = [ - "install", - "-y", - "-n", self.env_name, - ] - - if channels: - for ch in channels: - cmd.extend(["-c", ch]) - - cmd.extend(packages) - - self._run(cmd) - - def run(self, - command: list[str], - capture_output: bool = False, - quiet: bool = False) -> Optional[str]: - cmd = [self.micromamba, "run", "-n", self.env_name, *command] - - if capture_output or quiet: - stdout_lines = [] - with subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - ) as proc: - if proc.stdout is None: - return None - - for line in proc.stdout: - if not quiet: - sys.stdout.write(line) - sys.stdout.flush() - stdout_lines.append(line) - - _, stderr = proc.communicate() - - if proc.returncode != 0: - if stderr and not quiet: - sys.stderr.write(stderr) - sys.stderr.flush() - raise subprocess.CalledProcessError( - proc.returncode, - cmd, - output="".join(stdout_lines), - stderr=stderr - ) - - return "".join(stdout_lines) if capture_output else None - - else: - # Quiet is False and capture_output is False → just run - subprocess.check_call(cmd) - return None - - def remove(self): - self._run([ - "remove", - "-n", self.env_name, - "--all", - "-y", - ]) diff --git a/abcfold/boltz/check_install.py b/abcfold/boltz/check_install.py deleted file mode 100644 index 1c10799..0000000 --- a/abcfold/boltz/check_install.py +++ /dev/null @@ -1,47 +0,0 @@ -import logging - -from abcfold.backend_envs import MicromambaEnv, supports_cuda_wheels - -logger = logging.getLogger("logger") - - -def ensure_boltz_env(config: dict) -> MicromambaEnv: - BOLTZ_ENV = config['boltz_env'] - BOLTZ_VERSION = config['boltz_version'] - - env = MicromambaEnv(BOLTZ_ENV) - - # 1. Ensure env exists - env.create(python_version="3.11") - - # 2. Check installed boltz version - installed = env.get_installed_version("boltz") - - if installed != BOLTZ_VERSION: - if installed is None: - logger.info("boltz not found. Installing version: %s", BOLTZ_ENV) - else: - logger.info( - "boltz version mismatch (found %s). Installing correct version: %s", - installed, - BOLTZ_ENV, - ) - packages = [f"boltz=={BOLTZ_VERSION}"] - if supports_cuda_wheels(): - packages.extend([ - "cuequivariance_torch", - "cuequivariance_ops_torch-cu12", - ]) - else: - logger.info("Skipping CUDA-only Boltz dependencies on non-Linux platform") - - env.pip_install([*packages, "--no-cache-dir"]) - else: - logger.info("boltz is already up-to-date (%s)", BOLTZ_ENV) - - # 3. Ensure runtime deps you *actually* need - env.ensure_package("numpy") - env.ensure_package("typer") - env.ensure_package("matplotlib") - - return env diff --git a/abcfold/chai1/check_install.py b/abcfold/chai1/check_install.py deleted file mode 100644 index 56821c4..0000000 --- a/abcfold/chai1/check_install.py +++ /dev/null @@ -1,48 +0,0 @@ -import logging - -from abcfold.backend_envs import MicromambaEnv - -logger = logging.getLogger("logger") - - -# Set requirment versions for chai dependencies -PANDERA_VERSION = "0.24.0" - - -def ensure_chai_env(config: dict) -> MicromambaEnv: - CHAI_ENV = config['chai_env'] - CHAI_VERSION = config['chai_version'] - - env = MicromambaEnv(CHAI_ENV) - - # 1. Ensure env exists - env.create(python_version="3.11") - - # 2. Check installed chai version - installed = env.get_installed_version("chai_lab") - - if installed != CHAI_VERSION: - if installed is None: - logger.info("chai_lab not found. Installing version: %s", CHAI_VERSION) - else: - logger.info( - "chai_lab version mismatch (found %s). Installing correct version: %s", - installed, - CHAI_VERSION, - ) - env.conda_install(["kalign2"], channels=["conda-forge", "bioconda"]) - env.pip_install([f"chai_lab=={CHAI_VERSION}"]) - else: - logger.info("chai_lab is already up-to-date (%s)", CHAI_VERSION) - - installed_pandera = env.get_installed_version("pandera") - if installed_pandera != PANDERA_VERSION: - logger.info("Installing pandera==%s for Chai compatibility", PANDERA_VERSION) - env.pip_install([f"pandera=={PANDERA_VERSION}"]) - - # 3. Ensure runtime deps you *actually* need - env.ensure_package("numpy") - env.ensure_package("typer") - env.ensure_package("matplotlib") - - return env diff --git a/abcfold/data/config.ini b/abcfold/data/config.ini deleted file mode 100644 index fb84a4e..0000000 --- a/abcfold/data/config.ini +++ /dev/null @@ -1,35 +0,0 @@ -[Databases] -database_dir = None - -[Sif_paths] -af3_sif_path = None - -[Weights] -model_params = /mnt/ligandpro/soft/protein/alphafold3/models -boltz_weights = None -openfold_weights = None -rosettafold_weights = None - -[Environments] -af3_docker_env = romerolabduke/alphafast:latest -boltz_env = abcfold-boltz-py311 -chai_env = abcfold-chai-py311 -openfold_env = abcfold-openfold-py311 -protenix_env = abcfold-protenix-py311 -rosettafold_env = abcfold-rosetta-py312 - -[Versions] -af3_version = 3.0.0 -boltz_version = 2.2.1 -chai_version = 0.6.1 -openfold_version = 0.4.1 -protenix_version = 2.0.0 -rosetta_version = 0.1.12 - -[Models] -protenix_model = protenix-v2 - -[Boltz] -boltz_preprocessing_threads = 2 -boltz_num_workers = 2 -boltz_max_parallel_samples = None diff --git a/abcfold/openfold3/check_install.py b/abcfold/openfold3/check_install.py deleted file mode 100644 index 478272b..0000000 --- a/abcfold/openfold3/check_install.py +++ /dev/null @@ -1,90 +0,0 @@ -import logging -import urllib.request -from pathlib import Path - -from abcfold.backend_envs import MicromambaEnv, supports_cuda_wheels - -logger = logging.getLogger("logger") - -OPENFOLD_BUCKET = "openfold3-data" -CHECKPOINT_NAME = "of3-p2-155k.pt" -S3_KEY = f"openfold3-parameters/{CHECKPOINT_NAME}" -HTTPS_URL = ( - f"https://{OPENFOLD_BUCKET}.s3.amazonaws.com/{S3_KEY}" -) - - -def ensure_openfold_checkpoint(target_path: Path) -> Path: - """ - Ensure OpenFold3 checkpoint exists at target_path. - Non-interactive, automation-safe. - """ - if target_path.exists(): - return target_path - - target_path.parent.mkdir(parents=True, exist_ok=True) - - try: - logger.info( - "Downloading OpenFold3 checkpoint via HTTPS " - "(~2.1 GB, this may take a while)..." - ) - urllib.request.urlretrieve(HTTPS_URL, target_path) - except Exception as e: - raise RuntimeError( - "Failed to download OpenFold3 checkpoint.\n" - f"Target: {target_path}\n" - f"Error: {e}" - ) - - if not target_path.exists(): - raise RuntimeError("Checkpoint download completed but file not found") - - return target_path - - -def ensure_openfold_env(config: dict) -> MicromambaEnv: - OPENFOLD_ENV = config['openfold_env'] - OPENFOLD_VERSION = config['openfold_version'] - - env = MicromambaEnv(OPENFOLD_ENV) - - # 1. Ensure env exists - env.create(python_version="3.11") - - # 2. Check installed openfold version - installed = env.get_installed_version("openfold3") - - if installed != OPENFOLD_VERSION: - if installed is None: - logger.info("openfold3 not found. Installing version: %s", OPENFOLD_VERSION) - else: - logger.info( - "openfold3 version mismatch (found %s). Installing correct version: %s", - installed, - OPENFOLD_VERSION, - ) - # 3. Install Kalign2 - env.conda_install(["kalign2"], channels=["conda-forge", "bioconda"]) - - packages = [f"openfold3=={OPENFOLD_VERSION}"] - if supports_cuda_wheels(): - packages.extend([ - "cuequivariance_torch", - "cuequivariance_ops_torch-cu12", - ]) - else: - logger.info( - "Skipping CUDA-only OpenFold3 dependencies on non-Linux platform" - ) - - env.pip_install([*packages, "--no-cache-dir"]) - else: - logger.info("openfold3 is already up-to-date (%s)", OPENFOLD_ENV) - - # 4. Ensure runtime deps you *actually* need - env.ensure_package("numpy") - env.ensure_package("typer") - env.ensure_package("matplotlib") - - return env diff --git a/abcfold/openfold3/run_openfold3.py b/abcfold/openfold3/run_openfold3.py deleted file mode 100644 index 12cbaec..0000000 --- a/abcfold/openfold3/run_openfold3.py +++ /dev/null @@ -1,180 +0,0 @@ -import logging -import subprocess -import tempfile -from pathlib import Path -from typing import Optional, Union - -from abcfold.openfold3.af3_to_openfold3 import OpenfoldJson -from abcfold.openfold3.check_install import (CHECKPOINT_NAME, - ensure_openfold_checkpoint, - ensure_openfold_env) - -logger = logging.getLogger("logger") - - -def run_openfold( - input_json: Union[str, Path], - output_dir: Union[str, Path], - config: dict, - save_input: bool = False, - test: bool = False, - number_of_models: int = 5, - template_hits_path: Path | None = None, - input_ckpt: Optional[Union[str, Path]] = None, -) -> bool: - """ - Run OpenFold 3 using the input JSON file - - Args: - input_json (Union[str, Path]): Path to the input JSON file - output_dir (Union[str, Path]): Path to the output directory - config (dict): Configuration dictionary - save_input (bool): If True, save the input JSON file and MSA to the output - directory - test (bool): If True, run the test command - number_of_models (int): Number of models to generate - template_hits_path (Path): Path to the template hits m8 file - input_ckpt (Union[str, Path]): Path to user input checkpoint file - - Returns: - Bool: True if the OpenFold 3 run was successful, False otherwise - - Raises: - subprocess.CalledProcessError: If the OpenFold 3 command returns an error - - - """ - input_json = Path(input_json) - output_dir = Path(output_dir) - - logger.debug("Checking if openfold is installed") - env = ensure_openfold_env(config=config) - - openfold_weight_dir = config['openfold_weights'] - if openfold_weight_dir is not None and openfold_weight_dir != "None": - cache_path = Path(openfold_weight_dir) - else: - cache_path = Path.home().joinpath(".openfold3") - - default_ckpt = cache_path.joinpath(CHECKPOINT_NAME) - if input_ckpt is None: - if not default_ckpt.exists(): - logger.info( - "No Checkpoint file found. " - f"Downloading OpenFold3 checkpoint to {default_ckpt}" - ) - openfold_ckpt = ensure_openfold_checkpoint(default_ckpt) - else: - openfold_ckpt = default_ckpt - elif Path(input_ckpt).exists(): - logger.info(f"Using user provided OpenFold3 checkpoint: {input_ckpt}") - openfold_ckpt = Path(input_ckpt) - - elif Path(input_ckpt).exists(): - logger.info(f"Using user provided OpenFold3 checkpoint: {input_ckpt}") - openfold_ckpt = Path(input_ckpt) - else: - logger.error( - "No valid OpenFold3 checkpoint path provided." - ) - return False - - with tempfile.TemporaryDirectory() as temp_dir: - working_dir = Path(temp_dir) - if save_input: - logger.info("Saving input yaml file and msa to the output directory") - working_dir = output_dir - - openfold_json = OpenfoldJson(working_dir, templates=template_hits_path) - openfold_json.json_to_json(input_json) - runner_yaml = working_dir / "openfold3_runner.yml" - openfold_json.write_yaml(runner_yaml) - - for seed in openfold_json.seeds: - out_file = working_dir.joinpath(f"{input_json.stem}_seed-{seed}.json") - - openfold_json.write_json(out_file) - logger.info("Running OpenFold 3 using seed: %s", seed) - openfold_out_dir = output_dir / f"openfold_results_seed-{seed}" - cmd = ( - generate_openfold_command( - out_file, - openfold_out_dir, - runner_yaml, - openfold_ckpt, - number_of_models - ) - if not test - else generate_openfold_test_command() - ) - - try: - env.run(cmd) - except subprocess.CalledProcessError as e: - stderr = e.stderr or "" - if stderr: - if working_dir.exists(): - output_err_file = working_dir / "openfold_error.log" - else: - output_err_file = working_dir.parent / "openfold_error.log" - output_err_file.write_text(stderr) - logger.error( - "OpenFold 3 run failed. Error log is in %s", output_err_file - ) - else: - logger.error("OpenFold 3 run failed") - return False - - logger.info("OpenFold 3 run complete") - logger.info("Output files are in %s", output_dir) - return True - - -def generate_openfold_command( - input_json: Union[str, Path], - output_dir: Union[str, Path], - runner_yaml: Union[str, Path], - ckpt_path: Union[str, Path], - number_of_models: int = 5, -) -> list: - """ - Generate the OpenFold 3 command - - Args: - input_json (Union[str, Path]): Path to the input JSON file - output_dir (Union[str, Path]): Path to the output directory - runner_yaml (Union[str, Path]): Path to the runner YAML file - ckpt_path (Union[str, Path]): Path to the inference CheckPoint - number_of_models (int): Number of models to generate - - Returns: - list: The OpenFold 3 command - """ - return [ - "run_openfold", - "predict", - "--query_json", str(input_json), - "--runner_yaml", str(runner_yaml), - "--num_diffusion_samples", str(number_of_models), - "--output_dir", str(output_dir), - "--inference_ckpt_path", str(ckpt_path), - "--use_msa_server", "false" - ] - - -def generate_openfold_test_command() -> list: - """ - Generate the test command for OpenFold 3 - - Args: - None - - Returns: - list: The OpenFold 3 test command - """ - - return [ - "run_openfold", - "predict", - "--help", - ] diff --git a/abcfold/protenix/check_install.py b/abcfold/protenix/check_install.py deleted file mode 100644 index 4ce4935..0000000 --- a/abcfold/protenix/check_install.py +++ /dev/null @@ -1,38 +0,0 @@ -import logging - -from abcfold.backend_envs import MicromambaEnv - -logger = logging.getLogger("logger") - - -def ensure_protenix_env(config: dict) -> MicromambaEnv: - PROTENIX_ENV = config['protenix_env'] - PROTENIX_VERSION = config['protenix_version'] - - env = MicromambaEnv(PROTENIX_ENV) - - # 1. Ensure env exists - env.create(python_version="3.11") - - # 2. Check installed protenix version - installed = env.get_installed_version("protenix") - - if installed != PROTENIX_VERSION: - if installed is None: - logger.info("Protenix not found. Installing version: %s", PROTENIX_ENV) - else: - logger.info( - "Protenix version mismatch (found %s). Installing correct version: %s", - installed, - PROTENIX_ENV, - ) - env.pip_install([f"protenix=={PROTENIX_VERSION}"]) - else: - logger.info("Protenix is already up-to-date (%s)", PROTENIX_ENV) - - # 3. Ensure runtime deps you *actually* need - env.ensure_package("numpy") - env.ensure_package("typer") - env.ensure_package("matplotlib") - - return env diff --git a/abcfold/protenix/run_protenix.py b/abcfold/protenix/run_protenix.py deleted file mode 100644 index 6a009aa..0000000 --- a/abcfold/protenix/run_protenix.py +++ /dev/null @@ -1,180 +0,0 @@ -import json -import logging -import subprocess -import tempfile -from pathlib import Path -from typing import Union - -from abcfold.protenix.af3_to_protenix import ProtenixJson -from abcfold.protenix.check_install import ensure_protenix_env - -logger = logging.getLogger("logger") - - -def run_protenix( - input_json: Union[str, Path], - output_dir: Union[str, Path], - config: dict, - save_input: bool = False, - test: bool = False, - number_of_models: int = 5, - num_recycles: int = 10, -) -> bool: - """ - Run Protenix using the input JSON file - - Args: - input_json (Union[str, Path]): Path to the input JSON file - output_dir (Union[str, Path]): Path to the output directory - config (dict): Configuration dictionary - save_input (bool): If True, save the input yaml file and MSA to the output - directory - test (bool): If True, run the test command - number_of_models (int): Number of models to generate - num_recycles (int): Number of recycles - - Returns: - Bool: True if the Protenix run was successful, False otherwise - - Raises: - subprocess.CalledProcessError: If the Protenix command returns an error - - - """ - input_json = Path(input_json) - output_dir = Path(output_dir) - - env = None - if not test: - logger.debug("Checking if protenix is installed") - env = ensure_protenix_env(config=config) - - with tempfile.TemporaryDirectory() as temp_dir: - working_dir = Path(temp_dir) - if save_input: - logger.info("Saving input json file and msa to the output directory") - working_dir = output_dir - - protenix_json = ProtenixJson(working_dir) - protenix_json.json_to_json(input_json) - - for seed in protenix_json.seeds: - out_file = working_dir.joinpath(f"{input_json.stem}_seed-{seed}.json") - - protenix_json.write_json(out_file) - protenix_out_dir = output_dir / f"protenix_results_seed-{seed}" - logger.info("Running Protenix using seed: %s", seed) - cmd = ( - generate_protenix_command( - out_file, - protenix_out_dir, - config, - number_of_models, - num_recycles, - seed=seed, - ) - if not test - else generate_protenix_test_command() - ) - - try: - if test: - logger.info("Skipping Protenix backend execution in test mode") - continue - assert env is not None - env.run(cmd) - except subprocess.CalledProcessError as e: - stderr = e.stderr or "" - if stderr: - if working_dir.exists(): - output_err_file = working_dir / "protenix_error.log" - else: - output_err_file = working_dir.parent / "protenix_error.log" - output_err_file.write_text(stderr) - logger.error( - "Protenix run failed. Error log is in %s", output_err_file - ) - else: - logger.error("Protenix run failed") - return False - - logger.info("Protenix run complete") - logger.info("Output files are in %s", output_dir) - return True - - -def generate_protenix_command( - input_json: Union[str, Path], - output_dir: Union[str, Path], - config: dict, - number_of_models: int, - num_recycles: int, - seed: int, -) -> list: - """ - Generate the Protenix command - - Args: - input_json (Union[str, Path]): Path to the input JSON file - output_dir (Union[str, Path]): Path to the output directory - config (dict): Configuration dictionary - number_of_models (int): Number of models to generate - num_recycles (int): Number of recycles - seed (int): Random seed - config (dict): Configuration dictionary - - Returns: - list: The Protenix command - """ - - # Determine if MSA is present in the input JSON - use_msa = False - with open(str(input_json), "r") as f: - data = json.load(f) - for key, value in data[0].items(): - if key == "sequences": - for entry in value: - if "proteinChain" in entry: - if "msa" in entry["proteinChain"]: - use_msa = True - break - - return [ - "python", - "-m", - "runner.inference", - "--model_name", - str(config["protenix_model"]), - "--input_json_path", - str(input_json), - "--dump_dir", - str(output_dir), - "--sample_diffusion.N_sample", - str(number_of_models), - "--model.N_cycle", - str(num_recycles), - "--seeds", - str(seed), - "--use_msa", - str(use_msa), - "--need_atom_confidence", - "True", - ] - - -def generate_protenix_test_command() -> list: - """ - Generate the test command for Protenix - - Args: - None - - Returns: - list: The Protenix test command - """ - - return [ - "protenix", - "predict", - "--help", - ] diff --git a/abcfold/rosettafold3/check_install.py b/abcfold/rosettafold3/check_install.py deleted file mode 100644 index a0b8efc..0000000 --- a/abcfold/rosettafold3/check_install.py +++ /dev/null @@ -1,73 +0,0 @@ -import logging -import urllib.request -from pathlib import Path - -from abcfold.backend_envs import MicromambaEnv - -logger = logging.getLogger("logger") - -RF3_BASE_URL = "http://files.ipd.uw.edu/pub/rf3" -CHECKPOINT_NAME = "rf3_foundry_01_24_latest_remapped.ckpt" -RF3_URL = f"{RF3_BASE_URL}/{CHECKPOINT_NAME}" - - -def ensure_rosettafold_checkpoint(target_path: Path) -> Path: - if target_path.exists(): - return target_path - - target_path.parent.mkdir(parents=True, exist_ok=True) - - try: - logger.info( - "Downloading RoseTTAFold3 checkpoint via HTTPS " - "(this may take a while)..." - ) - urllib.request.urlretrieve(RF3_URL, target_path) - except Exception as e: - raise RuntimeError( - "Failed to download RoseTTAFold3 checkpoint.\n" - f"Target: {target_path}\n" - f"Error: {e}" - ) - - if not target_path.exists(): - raise RuntimeError("Checkpoint download completed but file not found") - - return target_path - - -def ensure_rosettafold_env(config: dict) -> MicromambaEnv: - ROSETTAFOLD_ENV = config['rosettafold_env'] - ROSETTAFOLD_VERSION = config['rosetta_version'] - - env = MicromambaEnv(ROSETTAFOLD_ENV) - # 1. Ensure env exists - env.create(python_version="3.12") - - # 2. Check installed rosettafold version - installed = env.get_installed_version("rc-foundry") - - if installed != ROSETTAFOLD_VERSION: - if installed is None: - logger.info("RosettaFold3 not found. Installing rc-foundry version: %s", - ROSETTAFOLD_VERSION) - else: - logger.info( - "RosettaFold3 version mismatch (found %s). " - "Installing correct version: %s", - installed, - ROSETTAFOLD_VERSION, - ) - - env.pip_install([ - f"rc-foundry[rf3]=={ROSETTAFOLD_VERSION}", - ]) - else: - logger.info("RosettaFold3 is already up-to-date (%s)", ROSETTAFOLD_ENV) - - # 3. Ensure runtime deps you *actually* need - env.ensure_package("numpy") - env.ensure_package("typer") - env.ensure_package("matplotlib") - - return env diff --git a/lefthook.yml b/lefthook.yml index 0af690a..0507877 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -5,14 +5,14 @@ pre-commit: commands: ruff-format-staged: glob: "*.{py,pyi}" - run: uv run --extra lint ruff format --check {staged_files} + run: uv run ruff format --check {staged_files} ruff-check-staged: glob: "*.{py,pyi}" - run: uv run --extra lint ruff check {staged_files} + run: uv run ruff check {staged_files} af3-fast-unit-smoke: - run: uv run --extra test pytest tests/test_run_alphafold3.py tests/test_argparse.py -q + run: uv run pytest tests/test_run_alphafold3.py tests/test_argparse.py -q git-diff-check: run: git diff --check --cached @@ -36,8 +36,8 @@ pre-push: echo "[python-quality] skipped: no Python files in push range (${range})" exit 0 fi - uv run --extra lint ruff format --check ${python_files} - uv run --extra lint ruff check ${python_files} + uv run ruff format --check ${python_files} + uv run ruff check ${python_files} pytest: - run: uv run --extra test pytest tests/test_run_alphafold3.py tests/test_run_boltz.py tests/test_run_protenix.py tests/test_af3_to_boltz.py tests/test_af3_to_openfold.py tests/test_argparse.py tests/test_run_scripts.py tests/test_utilities.py tests/test_abcfold.py -q + run: uv run pytest tests/test_run_alphafold3.py tests/test_run_boltz.py tests/test_run_protenix.py tests/test_af3_to_boltz.py tests/test_af3_to_openfold.py tests/test_argparse.py tests/test_run_scripts.py tests/test_utilities.py tests/test_abcfold.py -q diff --git a/pyproject.toml b/pyproject.toml index 7482e64..10e8ecb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,17 +1,18 @@ [build-system] -requires = ["setuptools>=42", "wheel"] +requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] name = "abcfold" -version = "1.1.3" -description = "Tool to run & compare AlphaFold3, Boltz, Chai-1, OpenFold3 and Protenix" +version = "2.0.0" +description = "Run and compare AlphaFold3, Boltz, Chai-1, OpenFold3, Protenix and RosettaFold3 on one input" readme = "README.md" requires-python = ">=3.10" license = { text = "BSD License" } authors = [ { name = "Adam Simpkin", email = "hlasimpk@liverpool.ac.uk" }, - { name = "Luc Elliott", email = "hllelli2@liverpool.ac.uk" } + { name = "Luc Elliott", email = "hllelli2@liverpool.ac.uk" }, + { name = "LigandPro" }, ] classifiers = [ "Development Status :: 4 - Beta", @@ -25,82 +26,59 @@ classifiers = [ "Topic :: Scientific/Engineering :: Bio-Informatics", ] dependencies = [ - "numpy==1.26.4", + "numpy>=1.26,<3", "colorama", "tqdm", - "biopython==1.84", + "biopython>=1.84", "requests", - "types-requests", - "pandas==2.2.3", + "pandas>=2.2", "plotly", "jinja2", - "pyarrow==19.0.1", - + "pyarrow>=19", + "packaging", + "tomli>=2; python_version < '3.11'", ] [project.optional-dependencies] -lint = [ - "ruff", -] -test = [ - "pytest", - "pytest-cov", -] -dev = [ - "ruff", - "pytest", - "pytest-cov", - "pre-commit", - "flake8", - "black", - "mypy", - "coverage-badge", - "coverage", -] +lint = ["ruff"] +test = ["pytest", "pytest-cov"] +dev = ["ruff", "pytest", "pytest-cov", "pre-commit", "mypy", "types-requests"] -[project.urls] -homepage = "https://github.com/rigdenlab/ABCFold" - -[tool.setuptools] -packages = [ - "abcfold", - "abcfold.alphafold3", - "abcfold.boltz", - "abcfold.chai1", - "abcfold.protenix", - "abcfold.openfold3", - "abcfold.rosettafold3", - "abcfold.html", - "abcfold.output", - "abcfold.plots", - "abcfold.plots.pae-viewer-main", - "abcfold.plots.pae-viewer-main.src", - "abcfold.plots.pae-viewer-main.src.css", - "abcfold.plots.pae-viewer-main.src.modules", - "abcfold.plots.pae-viewer-main.src.templates", - "abcfold.plots.pae-viewer-main.standalone", - "abcfold.plots.pae-viewer-main.standalone.css", - "abcfold.plots.pae-viewer-main.standalone.js", - "abcfold.plots.pae-viewer-main.standalone.libs", - "abcfold.scripts", - -] -include-package-data = true +[dependency-groups] +dev = ["pytest", "pytest-cov", "ruff"] -[tool.setuptools.package-data] -abcfold = ["data/config.ini"] +[project.urls] +homepage = "https://github.com/LigandPro/ABCFold" +upstream = "https://github.com/rigdenlab/ABCFold" [project.scripts] -abcfold = "abcfold.abcfold:main" +abcfold = "abcfold.cli:main" boltz-affinity = "abcfold.boltz.score_existing:main" boltz-dock = "abcfold.boltz.dock_crystal:main" mmseqs2msa = "abcfold.scripts.add_mmseqs_msa:main" custom_templates = "abcfold.scripts.add_custom_template:main" ipsae = "abcfold.scripts.ipsae:main" -[tool.flake8] -max-line-length = 88 -extend-ignore = ["E203"] +[tool.setuptools.packages.find] +where = ["src"] +include = ["abcfold*"] + +[tool.setuptools.package-data] +abcfold = [ + "backends.toml", + "data/*", + "LICENCE", + "html/*", + "html/**/*", + "plots/pae-viewer-main/**/*", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +markers = [ + "gpu: needs a GPU and the backend environments (deselected by default)", +] +addopts = "-m 'not gpu'" [tool.ruff] line-length = 88 @@ -115,5 +93,5 @@ ignore_missing_imports = true check_untyped_defs = true [[tool.mypy.overrides]] -module = ["abcfold.scripts.ipsae", "abcfold.scripts.add_mmseqs2_msa", "abcfold.tests.conftest"] +module = ["abcfold.scripts.ipsae", "abcfold.scripts.add_mmseqs_msa", "tests.conftest"] ignore_errors = true diff --git a/scripts/AF3_json_prepare.ipynb b/scripts/AF3_json_prepare.ipynb deleted file mode 100755 index 3cab391..0000000 --- a/scripts/AF3_json_prepare.ipynb +++ /dev/null @@ -1,1649 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Processing 6qqw, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqw/6qqw_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqw/6qqw_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: NC1CC(c2ccc3ccn(Cc4ccccc4)c3c2)NN1\n", - "JSON saved: json_inputs/6qqw.json\n", - "Processing 6d08, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d08/6d08_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d08/6d08_ligand.sdf\n", - "Found 1 chains: {'A': 'GEFVVEKVLDRRVVKGKVEYLLKWKGGSDEDNTWEPEENLDCPDLIAEFLQSQK'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](C)NC(=O)[C@@H](NC(=O)[C@H](CCC(N)=O)NC(=O)[C@H](CCCC[NH3+])NC(=O)[C@H](C)[NH3+])[C@@H](C)O)C(=O)N[C@@H](CCCC[NH2+]Cc1ccccc1)C(=O)N[C@@H](CO)C(=O)O\n", - "JSON saved: json_inputs/6d08.json\n", - "Processing 6jap, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jap/6jap_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jap/6jap_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSAPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@@](CO)(O[C@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jap.json\n", - "Processing 6np2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np2/6np2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np2/6np2_ligand.sdf\n", - "Found 1 chains: {'A': 'TPWSKSELVRQLRDLGVRSGDMVMPHVSLRAVGPLADGPQTLVDALIEAVGPTGNILAFVSWRDSPYEQTLGHDAPPAAIAQSWPAFDPDHAPAYPGFGAINEFIRTYPGCRRSAHPDASMAAIGPDAAWLVAPHEMGAAYGPRSPIARFLAHAGKILSIGAGPDAVTALHYAEAVARIEGKRRVTYSMPLLREGKRVWVTTSDWDSNGILDEYAAPDGPDAVERIARDYLARTRVAQGPVGGAQSRLIDAADIVSFGIEWLEARHAA'}\n", - "Ligand SMILES: C[NH2+][C@@H]1[C@@H](O)[C@@H](O[C@@H]2[C@@H](O)[C@H](O[C@H]3OC(C[NH3+])=CC[C@H]3[NH3+])[C@@H]([NH3+])C[C@H]2[NH3+])OC[C@]1(C)O\n", - "JSON saved: json_inputs/6np2.json\n", - "Processing 6uvp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uvp/6uvp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uvp/6uvp_ligand.sdf\n", - "Found 1 chains: {'A': 'RRGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGFPLNQSEVLASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1/N[C@@]2([C@H]3C[C@@H]3NC(=O)c3ccc(F)cn3)COC[C@H]2CS1\n", - "JSON saved: json_inputs/6uvp.json\n", - "Processing 6oxq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxq/6oxq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxq/6oxq_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CCC(CC)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc(CO)cc1\n", - "JSON saved: json_inputs/6oxq.json\n", - "Processing 6jsn, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsn/6jsn_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsn/6jsn_ligand.sdf\n", - "Found 1 chains: {'A': 'RGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYNI'}\n", - "Ligand SMILES: [H]/N=C1/N[C@](C)(c2cc(NC(=O)c3cnc(OCF)cn3)ccc2F)C2(CCS(=O)(=O)CC2)CS1\n", - "JSON saved: json_inputs/6jsn.json\n", - "Processing 6hzb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hzb/6hzb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hzb/6hzb_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTASGSLVPR'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)CCCC(=O)NCCCC[C@@H](C(=O)N[C@@H](CCCC[NH3+])C(=O)NCc2ccc(/C(N)=N\\[H])cc2)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC1=O\n", - "JSON saved: json_inputs/6hzb.json\n", - "Processing 6qrc, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrc/6qrc_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrc/6qrc_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSPT'}\n", - "Ligand SMILES: COc1cccc(Cn2ccc3ccc(C4CC(N)NN4)cc32)c1\n", - "JSON saved: json_inputs/6qrc.json\n", - "Processing 6oio, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oio/6oio_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oio/6oio_ligand.sdf\n", - "Found 1 chains: {'A': 'VKYVDKIHIGNYEIDAWYFSPFPEDYGKQPKLWLCEYCLKYMKYEKSYRFHLGQCQWRQPPGKEIYRKSNISVHEVDGKDHKIYCQNLCLLAKLFLDHTLYFDVEPFVFYILTEVDRQGAHIVGYFSKEKESPDGNNVSCIMILPPYQRRGYGRFLIAFSYELSKLESTVGSPEKPLSDLGKLSYRSYWSWVLLENLRDFRGTLSIKDLSQMTSITQNDIISTLQSLNMVKYWKGQHVICVTPKLVEEHLKSAQYKKPPITVDSVCLKWAPP'}\n", - "Ligand SMILES: O=C(NNS(=O)(=O)c1ccccc1)c1cccc(-c2ccccc2)c1\n", - "JSON saved: json_inputs/6oio.json\n", - "Processing 6jag, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jag/6jag_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jag/6jag_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@@](CO)(O[C@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jag.json\n", - "Processing 6moa, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6moa/6moa_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6moa/6moa_ligand.sdf\n", - "Found 1 chains: {'A': 'LSEQLKHCNGILKELLSKKHAAYAWPFYKPVDASALGLHDYHDIIKHPMDLSTVKRKMENRDYRDAQEFAADVRLMFSNCYKYNPPDHDVVAMARKLQDVFEFRYAKMP'}\n", - "Ligand SMILES: Cc1ccc2ncccc2c1C1CC(c2c(C)noc2C)CC2NC(C3CC3)NC21\n", - "JSON saved: json_inputs/6moa.json\n", - "Processing 6hld, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hld/6hld_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hld/6hld_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTASGSLVP'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@@H]([NH3+])Cc1cccc2ccccc12)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CCCC[NH3+])C(=O)NCc1ccc(/C(N)=N\\[H])cc1\n", - "JSON saved: json_inputs/6hld.json\n", - "Processing 6i9a, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i9a/6i9a_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i9a/6i9a_ligand.sdf\n", - "Found 1 chains: {'A': 'DVYTDHGDLYNTPVRMLVVAGAKFKEALKPWLTWKAQKGFYLDVHYTDEAEVGTTNASIKAFIHKKYNDGLAASAAPVFLALVGDTDVISGEKGKKTKKVTDLYYSAVDGDYFPEMYTFRMSASSPEELTNIIDKVLMYEKATMPDKSYLEKVLLIAGADYSWNSQVGQPTIKYGMQYYYNQEHGYTDVYNYLKAPYTGCYSHLNTGVSFANYTAHGSETAWADPLLTTSQLKALTNKDKYFLAIGNCCITAQFDYVQPCFGEVITRVKEKGAYAYIGSSPNSYWGEDYYWSVGANAVFGVQPTFEGTSMGSYDATFLEDSYNTVNSIMWAGNLAATHAGNIGNITHIGAHYYWEAYHVLGDGSVMPYRAMPKTNTYTLPASLPQNQASYSIQASAGSYVAISKDGVLYGTGVANASGVATVSMTKQITENGNYDVVITRSNYLPVIKQIQVG'}\n", - "Ligand SMILES: CN(NC(=O)CC[C@H](NC(=O)OCc1ccccc1)C(=O)N[C@@H](CCCC[NH3+])[C@H](O)C(=O)NCc1ccccc1)c1ccccc1\n", - "JSON saved: json_inputs/6i9a.json\n", - "Processing 6e4c, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e4c/6e4c_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e4c/6e4c_ligand.sdf\n", - "Found 1 chains: {'A': 'MAMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIKEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSER'}\n", - "Ligand SMILES: Cc1cc(-c2noc(=O)[nH]2)ccc1C1=CC(=O)[C@@H](O)C(C(=O)O)=N1\n", - "JSON saved: json_inputs/6e4c.json\n", - "Processing 6g24, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g24/6g24_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g24/6g24_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEATKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYID'}\n", - "Ligand SMILES: O=C(O)c1ccccc1/C=C/c1cccs1\n", - "JSON saved: json_inputs/6g24.json\n", - "Processing 6jb4, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jb4/6jb4_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jb4/6jb4_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGAQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O[C@H]2[C@H](O)[C@@H](O)[C@@H](O)O[C@@H]2CO)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jb4.json\n", - "Processing 6s55, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s55/6s55_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s55/6s55_ligand.sdf\n", - "Found 1 chains: {'A': 'SMQEEDTFRELRIFLRNVTHRLAIDKRFRVFTKPVDPDEVPDYVTVIKQPMDLSSVISKIDLHKYLTVKDYLRDIDLICSNALEYNPDRDPGDRLIRHRACALRDTAYAIIKEELDEDFEQLCEEIQESR'}\n", - "Ligand SMILES: C[C@H]1CCCN(S(=O)(=O)c2cc(NC(=O)CN3C(=O)CNC3=O)ccc2Br)C1\n", - "JSON saved: json_inputs/6s55.json\n", - "Processing 6seo, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6seo/6seo_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6seo/6seo_ligand.sdf\n", - "Found 1 chains: {'A': 'PRSVASSKLWMLEFSAFLEQQQDPDTYNKHLFVHIGPYLEAVDIRQIYDKFPEKKGGLKDLFERGPSNAFFLVKFWADLNTNSSFYGVSSQYESPENMIITCSTKVCSFGKQVVEVETEYARYENGHYSYRIHRSPLCEYMINFIHKLKHLPEKYMMNSVLENFTILQVVTNRDTQETLLCIAYVFEVSASEHGAQHHIYRLVK'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](C)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CC(C)C)NC(=O)[C@@H]1CCCN1C(=O)[C@@H](NC(C)=O)C(C)C)C(=O)N[C@@H](CC(N)=O)C(=O)N[C@@H](CC(C)C)C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H](CO)C(=O)N[C@@H](Cc1ccccc1)C(=O)N[C@@H](Cc1ccccc1)C(=O)N[C@H](C(=O)N[C@@H](CCC(=O)O)C(=O)N1CCC[C@H]1C(N)=O)[C@@H](C)O\n", - "JSON saved: json_inputs/6seo.json\n", - "Processing 6dyz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dyz/6dyz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dyz/6dyz_ligand.sdf\n", - "Found 2 chains: {'A': 'AVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGRQHTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLLP', 'C': 'AVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGRQHTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLLP'}\n", - "Ligand SMILES: C#CCSC[C@H]1C[N@@H+](CC2CNC3C(N)NCNC23)C[C@@H]1O\n", - "JSON saved: json_inputs/6dyz.json\n", - "Processing 5zk5, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zk5/5zk5_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zk5/5zk5_ligand.sdf\n", - "Found 1 chains: {'A': 'PEHYIKHPLQNRWALWFFKNDKSKTWQANLRLISKFDTVEDFWALYNHIQLSSNLMPGCDYSLFKDGIEPMWEDEKNKRGGRWLITLNKQQRRSDLDRFWLETLLCLIGESFDDYSDDVCGAVVNVRAKGDKIAIWTTECENREAVTHIGRVYKERLGLPPKIVIGYQSHADTATTKNRFVV'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H](C=O)NC(=O)[C@H](CCC(N)=O)NC(=O)[C@H](Cc1ccccc1)NC(=O)[C@](C)(CCCC)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CCC(N)=O)NC(=O)[C@H](CCC(=O)O)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CO)NC(=O)[C@H](Cc1ccc(O)cc1)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](C)[NH3+]\n", - "JSON saved: json_inputs/5zk5.json\n", - "Processing 6jid, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jid/6jid_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jid/6jid_ligand.sdf\n", - "Found 1 chains: {'A': 'EAVVISGRKLAQQIKQEVRQEVEEWVASGNKRPHLSVILVGENPASHSYVLNKTRAAAVVGINSETIMKPASISEEELLNLINKLNNDDNVDGLLVQLPLPEHIDERRICNAVSPDKDVDGFHVINVGRMCLDQYSMLPATPWGVWEIIKRTGIPTLGKNVVVAGRSKNVGMPIAMLLHTDGAHERPGGDATVTISHRYTPKEQLKKHTILADIVISAAGIPNLITADMIKEGAAVIDVGINRVHDKPKLVGDVDFEGVRQKAGYITPVPGGVGPMTVAMLMKNTIIAAKKVLR'}\n", - "Ligand SMILES: O=C(c1ccc2c(c1)CS(=O)(=O)N2)N1CCc2[nH]c(-c3ccccc3)nc(=O)c2C1\n", - "JSON saved: json_inputs/6jid.json\n", - "Processing 5ze6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5ze6/5ze6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5ze6/5ze6_ligand.sdf\n", - "Found 2 chains: {'A': 'MNLEKINELTAQDMAGVNAAILEQLNSDVQLINQLGYYIVSGGGKRIRPMIAVLAARAVGYEGNAHVTIAALIEFIHTATLLHDDVVDESDMRRGKATANAAFGNAASVLVGDFIYTRAFQMMTSLGSLKVLEVMSEAVNVIAEGEVLQLMNVNDPDITEENYMRVIYSKTARLFEAAAQCSGILAGCTPEEEKGLQDYGRYLGTAFQLIDDLLDYNADGNVGDDLNEGKPTLPLLHAMHHGTPEQAQMIRTAIEQGNGRHLLEPVLEAMNACGSLEWTRQRAEEEADKAIAALQVLPDTPWREALIGLAHIAVQ', 'C': 'MNLEKINELTAQDMAGVNAAILEQLNSDVQLINQLGYYIVSGGGKRIRPMIAVLAARAVGYEGNAHVTIAALIEFIHTATLLHDDVVDESFGNAASVLVGDFIYTRAFQMMTSLGSLKVLEVMSEAVNVIAEGEVLQLMNVNDPDITEMRVIYSKTARLFEAAAQCSGILAGCTPEEEKGLQDYGRYLGTAFQLIDDLLDYNVGDDLNEGKPTLPLLHAMHHGTPEQAQMIRTAIEQGNGRHLLEPVLEAMNACGSLEWTRQRAEEEADKAIAALQVLPDTPWREALIGLAHIAVQR'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCOc1cccc(O)c1C(=O)O\n", - "JSON saved: json_inputs/5ze6.json\n", - "Processing 6qlu, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlu/6qlu_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlu/6qlu_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4ccc(F)c(C)c4)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qlu.json\n", - "Processing 6a6k, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a6k/6a6k_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a6k/6a6k_ligand.sdf\n", - "Found 1 chains: {'A': 'NKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLE'}\n", - "Ligand SMILES: CC(C)[NH+]1CCN(c2ccc(/C(=C(/CCCO)c3ccccc3)c3cccc(O)c3)cc2)CC1\n", - "JSON saved: json_inputs/6a6k.json\n", - "Processing 6qgf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qgf/6qgf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qgf/6qgf_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: OC[C@H]1O[C@@H](SC[C@H](O)Cn2cc(-c3cccc(F)c3)nn2)[C@H](O)[C@@H](n2cc(-c3cccc(F)c3)nn2)[C@H]1O\n", - "JSON saved: json_inputs/6qgf.json\n", - "Processing 6e3z, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3z/6e3z_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3z/6e3z_ligand.sdf\n", - "Found 1 chains: {'A': 'TGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1\\CO[C@@H](C(F)(F)F)[C@@](C)(c2cc(NC(=O)c3ncc(Cl)cc3Cl)ccc2F)N1\n", - "JSON saved: json_inputs/6e3z.json\n", - "Processing 6te6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6te6/6te6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6te6/6te6_ligand.sdf\n", - "Found 1 chains: {'A': 'LELRLKSPVGAEPAVYPWPLPVYDKHHDAAHEIIETIRWVCEEIPDLKLAMENYVLIDYDTKSFESMQRLCDKYNRAIDSIHQLWKGTNTRPSTGLLRHILQQVYNHSVTDPEKLNNYEPFSPEVYGETSFDLVAQMIDEIKMTDDDLFVDLGSGVGQVVLQVAAATNCKHHYGVEKADIPAKYAETMDREFRKWMKWYGKKHAEYTLERGDFLSEEWRERIANTSVIFVNNFAFGPEVDHQLKERFANMKEGGRIVSSKPFAPLNFRINSRNLSDIGTIMRVVELSPLKSWTGKPVSYYLHTIDRTILENYFSSLKNP'}\n", - "Ligand SMILES: CS(=O)(=O)c1ccc(N[C@@H](c2cccc(Cl)c2)c2ccccn2)c(Nc2ncccn2)c1\n", - "JSON saved: json_inputs/6te6.json\n", - "Processing 6pka, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pka/6pka_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pka/6pka_ligand.sdf\n", - "Found 2 chains: {'A': 'IPTVYDIYSRLLKDRIIMLGSQIDDNVANSIVSQLLFLQAQDSEKDIYLYINSPGGSVTAGFAIYDTIQHIKPDVQTICIGMAASMGSFLLAAGAKGKRFALPNAEVMIHQPLGGAQGQATEIEIAANHILKTREKLNRILSERTGQSIEKIQKDTDRDNFLTAEEAKEYGLIDEVMVP', 'B': 'IPTVIYDIYSRLLKDRIIMLGSQIDDNVANSIVSQLLFLQAQDSEKDIYLYINSPGGSVTAGFAIYDTIQHIKPDVQTICIGMAASMGSFLLAAGAKGKRFALPNAEVMIHQPLGGAQGQATEIEIAANHILKTREKLNRILSERTGQSIEKIQKDTDRDNFLTAEEAKEYGLIDEVMVP'}\n", - "Ligand SMILES: Cc1ccc(NC(=O)N[C@@H](Cc2cc(F)cc(F)c2)C(=O)N[C@@H]2C(=O)N3C=CC[C@H]3C(=O)N3CCCC[C@H]3C(=O)N[C@@H](C)C(=O)N3C[C@H](C)C[C@H]3C3(O)OC2O3)cc1\n", - "JSON saved: json_inputs/6pka.json\n", - "Processing 6g2o, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2o/6g2o_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2o/6g2o_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEQKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYID'}\n", - "Ligand SMILES: Cc1cc(C[NH3+])cc(C)c1-c1ncn(C)c1-c1ccnc2cc(F)ccc12\n", - "JSON saved: json_inputs/6g2o.json\n", - "Processing 6jsf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsf/6jsf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsf/6jsf_ligand.sdf\n", - "Found 1 chains: {'A': 'RGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYNIP'}\n", - "Ligand SMILES: [H]/N=C1\\N[C@](C)(c2cc(NC(=O)c3cnc(OCF)cn3)ccc2F)[C@H](c2ccccc2)CS1\n", - "JSON saved: json_inputs/6jsf.json\n", - "Processing 5zxk, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zxk/5zxk_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zxk/5zxk_ligand.sdf\n", - "Found 1 chains: {'A': 'GAYNEWKKALFKPADVILDPKTANPILLVSEDQRSVQRAKEPQDLPDNPERFNWHYCVLGCESFISGRHYWEVEVGDRKEWHIGVCSKNVQRKGWVKMTPENGFWTMGLTDGNKYRTLTEPRTNLKLPKPPKKVGVFLDYETGDISFYNAVDGSHIHTFLDVSFSEALYPVFRILTLEPTALTICP'}\n", - "Ligand SMILES: C/C(=C\\CO[P@@](=O)(O)OP(=O)(O)O)CO\n", - "JSON saved: json_inputs/5zxk.json\n", - "Processing 6qxd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qxd/6qxd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qxd/6qxd_ligand.sdf\n", - "Found 1 chains: {'A': 'KYRVRKNVLHLTDTEKRDFVRTVLILKEKGIYDRYIAWHGAAGKFHTPPGSDRNAAHMSSAFLPWHREYLLRFERDLQSINPEVTLPYWEWETDAQMQDPSQSQIWSADFMGGNGNPIKDFIVDTGPFAAGRWTTIDEQGNPSGGLKRNFGATKEAPTLPTRDDVLNALKITQYDTPPWDMTSQNSFRNQLEGFINGPQLHNRVHRWVGGQMGVVPTAPNDPVFFLHHANVDRIWAVWQIIHRNQNYQPMKNGPFGQNFRDPMYPWNTTPEDVMNHRKLGYVYDIEL'}\n", - "Ligand SMILES: O=C(c1ccc([N+](=O)[O-])cc1[N+](=O)[O-])N1CC[NH+](Cc2ccc(F)cc2)CC1\n", - "JSON saved: json_inputs/6qxd.json\n", - "Processing 6n97, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n97/6n97_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n97/6n97_ligand.sdf\n", - "Found 2 chains: {'A': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH', 'C': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH'}\n", - "Ligand SMILES: C[C@H](C(=O)NCCNC(=O)CCNC(=O)[C@H](O)C(C)(C)CO[P@@](=O)(O)O[P@@](=O)(O)OC[C@H]1O[C@@H](n2cnc3c(N)ncnc32)[C@H](O)[C@@H]1OP(=O)(O)O)S(=O)(=O)O\n", - "JSON saved: json_inputs/6n97.json\n", - "Processing 6jt3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jt3/6jt3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jt3/6jt3_ligand.sdf\n", - "Found 1 chains: {'A': 'RGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1/N[C@](C)(c2cc(NC(=O)c3cnc(OCF)cn3)ccc2F)[C@@H](F)[C@@H](C)S1\n", - "JSON saved: json_inputs/6jt3.json\n", - "Processing 6qtr, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtr/6qtr_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtr/6qtr_ligand.sdf\n", - "Found 1 chains: {'A': 'AMTFTRYSRLRVIAEIRNIVSSIEFDRDDELFATAGVSRIKVFDFSSVVNEQCPIVEMSTRSKLSLSWNKHEKNHIASSDYEGIVTVWDVTTRQSLMEYEEHEKRAWSVDFSRTEPSMLVSGSDDCKVKVWTRQEASVINIDMKANICVKYNPGSSNYIAVGSADHHIHYYDLRNISQPLHVFSGHKKAVSYVKFLSNNELASASTDSTLRLWDVKDNLPVRTFRGHTNEKNFVGLTVNSEYLACGSETNEVYVYHKEITRPVTSHRFGAGSYFISAVCWKSDSPTMLTANSQGTIKVLVLAA'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@@H](NC(=O)[C@@H]([NH3+])CCC(=O)O)[C@@H](C)CC)C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)N[C@@H](CCC(=O)O)C(=O)N[C@@H](Cc1ccccc1)C(=O)NCC(=O)NCC(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)O)C(C)C\n", - "JSON saved: json_inputs/6qtr.json\n", - "Processing 6oy1, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oy1/6oy1_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oy1/6oy1_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CCC(CC)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@@H](O)CO)cc1\n", - "JSON saved: json_inputs/6oy1.json\n", - "Processing 6n96, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n96/6n96_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n96/6n96_ligand.sdf\n", - "Found 1 chains: {'C': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@@H]1O[C@H](CO[P@](=O)(O)OP(=O)(O)O)[C@@H](OP(=O)(O)O)[C@H]1O\n", - "JSON saved: json_inputs/6n96.json\n", - "Processing 6qzh, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qzh/6qzh_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qzh/6qzh_ligand.sdf\n", - "Found 1 chains: {'A': 'DVRNFKAWFLPIMYSIICFVGLLGNGLVVLTYIYFKRLKTMTDTYLLNLAVADILFLLTLPFWAYSAAKSWVFGVHFCKLIFAIYKMSFFSGMWLLLCISIDRYVAIVHRHRARVLLISKLSCVGIWILATVLSIPELLYSDLQRSSSEQAMRCSLITEHVEAFITIQVAQMVIGFLVPLLAMSFCYLVIISKLHALTEKTDIFESGRNGNPNKDGIKSYRIPALLKTDKGTLIAGADERRLHSSDWGDIGMVIRRSEDNGKTWGDRVTITNLRDNPKASDPSIGSPVNIDMVLVQDPETKRIFSIYDMFPEGKGIFGMSSQKEEAYKKIDGKTYQILYREGEKGAYTIRENGTVYTPDGKATDYRVVVDPVKPAYSDKGDLYKGDQLLGNIYFTTNKTSPFRIAKDSYLWMSYSDDDGKTWSAPQDITPMVKADWMKFLGVGPGTGIVLRNGPHKGRILIPVYTTNNVSHLDGSQSSRVIYSDDHGKTWHAGEAVNDNRQVDGQKIHSSTMNNRRAQNTESTVVQLNNGDVKLFMRGLTGDLQVATSKDGGVTWEKDIKRYPQVKDVYVQMSAIHTMHEGKEYIILSNAGGPKRENGMVHLARVEENGELTWLKHNPIQKGEFAYNSLQELGNGEYGILYEHTEKGQNAYTLSFRKFNWEFLSKSKGHERNIKVIIAVVVVFIVFQLPYNGVVLAQTVTCELSKQLNIAYDVTYSLACVRCCVNPFLYAFIGVKFRNDLFKLF'}\n", - "Ligand SMILES: Cc1ccc([C@H](NC2=NS(=O)(=O)N=C2Nc2ccc(C)c(C(=O)N(C)C)c2O)C(C)(C)C)o1\n", - "JSON saved: json_inputs/6qzh.json\n", - "Processing 6qqz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqz/6qqz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqz/6qqz_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: N#CC1C(N)NNC1c1ccc2ccn(Cc3cccnc3)c2c1\n", - "JSON saved: json_inputs/6qqz.json\n", - "Processing 6qmt, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qmt/6qmt_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qmt/6qmt_ligand.sdf\n", - "Found 1 chains: {'A': 'ILGGREAEAHARPYMASVQLNGAHLCGGVLVAEQWVLSAAHCLEDAADGKVQVLLGAHSLSQPEPSKRLYDVLRAVPHPDSQPDTIDHDLLLLQLSEKATLGPAVRPLPWQRVDRDVAPGTLCDVAGWGIVNHAGRRPDSLQHVLLPVLDRATCNRRTHHDGAITERLMCAESNRRDSCKGDSGGPLVCGGVLEGVVTSGSRVCGNRKKPGIYTRVASYAAWIDSVLASA'}\n", - "Ligand SMILES: [NH3+]Cc1cccc(-c2cccc(C(=O)Nc3ccccc3CC(=O)O)c2)c1\n", - "JSON saved: json_inputs/6qmt.json\n", - "Processing 6ibx, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ibx/6ibx_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ibx/6ibx_ligand.sdf\n", - "Found 1 chains: {'A': 'ELTQSRVQKIWVPVNSPTVIVMVGLPARGKTYISKKLTRYLNWIGVPTKVFNVGEYRREAVKQYSSYNFFRPDNEEAMKVRKQCALAALRDVKSYLAKEGGQIAVFDATNTTRERRHMILHFAKENDFKAFFIESVCDDPTVVASNIMEVKISSPDYKDCNSAEAMDDFMKRISCYEASYQPLDPDKCDRDLSLIKVIDVGRRFLVNRVQDHIQSRIVYYLMNIHVQPRTIYLCRHGENEHNLQGRIGGDSGLSSRGKKFASALSKFVEEQNLKDLRVWTSQLKSTIQTAEALRLPYEQWKALNEIDAGVCEELTYEEIRDTYPEEYALREQDKYYYRYPTGESYQDLVQRLEPVIMELERQENVLVICHQAVLRCLLAYFLDKSAEEMPYLKCPLHTVLKLTPVAYGCRVESIYLNVESVCTHRERSE'}\n", - "Ligand SMILES: Cn1ccc2ccc(-c3cc(Nc4cnccc4C(=O)N[C@H]4CCC[N@H+](C)C4)cc4nccnc34)cc21\n", - "JSON saved: json_inputs/6ibx.json\n", - "Processing 6hmt, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hmt/6hmt_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hmt/6hmt_ligand.sdf\n", - "Found 2 chains: {'A': 'GAMGSMERASLIQKAKLAEQAERYEDMAAFMKGAVEKGEELSNEERCLLSVAYKNVVGGQRAAWRVLSSIEQKSNEEGSEEKGPEVREYREKVETELQGVCDTVLGLLDSHLIKEAGDAESRVFYLKMKGDYYRYLAEVATGDDKKRIIDSARSAYQEAMDISKKEMPPTNPIRLGLALNFSVFHYEIANSPEEAISLAKTTFDEAMADLHTLSEDSYKDSTLIMQLLRDNLTLWT', 'B': 'GAMGSMERASLIQKAKLAEQAERYEDMAAFMKGAVEKGEELSNEERCLLSVAYKNVVGGQRAAWRVLSSIEQKSNEEGSEEKGPEVREYREKVETELQGVCDTVLGLLDSHLIKEAGDAESRVFYLKMKGDYYRYLAEVATGDDKKRIIDSARSAYQEAMDISKKEMPPTNPIRLGLALNFSVFHYEIANSPEEAISLAKTTFDEAMADLHTLSEDSYKDSTLIMQLLRDNLTLWT'}\n", - "Ligand SMILES: CC(C)[C@H](NC(=O)[C@@H](NC(=O)[C@H](C)NC(=O)[C@@H]1CCCN1C(=O)[C@@H]([NH3+])Cc1ccccc1)[C@@H](C)OP(=O)(O)O)C(=O)O\n", - "JSON saved: json_inputs/6hmt.json\n", - "Processing 5zk7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zk7/5zk7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zk7/5zk7_ligand.sdf\n", - "Found 1 chains: {'A': 'ANPEHYIKHPLQNRWALWFFKWQANLRLISKFDTVEDFWALYNHIQLSSNLMPGCDYSLFKDGIEPMWEDEKNKRGGRWLITLNKQQRRSDLDRFWLETLLCLIGESFDDYSDDVCGAVVNVRAKGDKIAIWTTECENREAVTHIGRVYKERLGLPPKIVIGYQSHADTATTKNRFVV'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H](C=O)NC(=O)[C@H](CO)NC(=O)[C@H](Cc1ccc(O)cc1)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(C)=O\n", - "JSON saved: json_inputs/5zk7.json\n", - "Processing 6k3l, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k3l/6k3l_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k3l/6k3l_ligand.sdf\n", - "Found 1 chains: {'B': 'RSVARVYANVNEKLGRSWWDYDNLVVQWGVQDNYEIVRKVGRGKYSEVFESIHLPTDSKCIVKVLKPVKKKKIKREIKILQNLAGGPNVVGLLDVVRDSQSKTPSIVTEYVNNTEFKTLYPKFSDFDVRYYIFELLKALDFCHSKGIMHRDVKPHNVMIDHEKRTLRLIDWGLAEFYHPGTEYNVRVASRYFKGPELLVDFQEYDYSLDMWSLGCMFASMIFRKEPFFHGHDNADQLVKIAKVLGTDELYTYLERYDIDLDAQFDDILGRYPRKPWSRFVSSENQRYISSEAIDFLDKLLRYDHQERLTAEEAKEHPYFEPVRQAAAQA'}\n", - "Ligand SMILES: O=C(O)c1ccc2c(c1)nc(Nc1cccc(Cl)c1)c1ccncc12\n", - "JSON saved: json_inputs/6k3l.json\n", - "Processing 6cjs, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjs/6cjs_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjs/6cjs_ligand.sdf\n", - "Found 1 chains: {'A': 'NLYFQGETHEFTAEISQLMSLIINTVYSNKEIFLRELISNASDALDKIRYQALSDPSQLESEPELFIRIIPQKDQKVLEIRDSGIGMTKADLVNNLGTIAKSGTKSFMEALSAGADVSMIGQFGVGFYSLFLVADHVQVISKHNDDEQYVWESNAGGKFTVTLDETNERLGRGTMLRLFLKEDQLEYLEEKRIKEVVKKHSEFVAYPIQLVVTKEVEK'}\n", - "Ligand SMILES: CCNC(=O)c1noc(-c2cc(C(C)C)c(O)cc2O)c1-c1ccc(C[NH+]2CCOCC2)cc1\n", - "JSON saved: json_inputs/6cjs.json\n", - "Processing 6n9l, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n9l/6n9l_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n9l/6n9l_ligand.sdf\n", - "Found 1 chains: {'A': 'NEIVVKGARVHNLKNITVRIPKNRLVVITGVSGSGKSSLAMDTIYAEGQRRYLESLSTYKKPDVDEIEGLSPAIAIDQKTVSHNPRSTVGTVTEIYDYLRVLYARIGKKINGLNIHEFTELSISEELEFLKNLNLTEREREIVGELLKEIEKRLEFLVDVGLEYLTLSRSATTLSGGESQRIRLATQIGSGLTGVIYVLDEPTIGLHPRDTERLIKTLKKLRDLGNTVIVVEHDEEVIRNADHIIDIGPGGGTNGGRVVFQGTVDELLKNPDSSLTGEYLSGKRKITVNKTRRLPYASLKIKGVRHNNLKNIDVEIPLGVFVCVTGVSGSGKSSLVMETLYPALMNLLHKTKLPAGEFDSIEGHENIDKMIAIDQSPIGRTPRSNPATYTKVFDEIRSLFAMTPAAKARGYNKSRFSFNLKGGRCEACQGQGYVKIEMLFLPDVYVECDVCKGKRYNRETLEITYKGKNISDILDMTVDEALEFFKNIPSIKRTLQVLHDVGLGYVKLGQPATTLSGGEAQRIKLASELRKRDTGRTLYILDEPTVGLHFEDVRKLVEVLHRLVDRGNTVIVIEHNLDVIKNADHIIDLGPEGGKEGGYIVATGTPEEIAKNPHSYTGRFLKNVL'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@@H]1O[C@H](CO[P@@](=O)(O)OP(=O)(O)O)[C@@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6n9l.json\n", - "Processing 6ibz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ibz/6ibz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ibz/6ibz_ligand.sdf\n", - "Found 1 chains: {'A': 'ELTQSRVQKIWVPVDHNSPTVIVMVGLPARGKTYISKKLTRYLNWIGVPTKVFNVGEYRREAVKQYSSYNFFRPDNEEAMKVRKQCALAALRDVKSYLAKEGGQIAVFDATNTTRERRHMILHFAKENDFKAFFIESVCDDPTVVASNIMEVKISSPDYKDCNSAEAMDDFMKRISCYEASYQPLDPDKCDRDLSLIKVIDVGRRFLVNRVQDHIQSRIVYYLMNIHVQPRTIYLCRHGENEHNLQGRIGGDSGLSSRGKKFASALSKFVEEQNLKDLRVWTSQLKSTIQTAEALRLPYEQWKALNEIDAGVCEELTYEEIRDTYPEEYALREQDKYYYRYPTGESYQDLVQRLEPVIMELERQENVLVICHQAVLRCLLAYFLDKSAEEMPYLKCPLHTVLKLTPVAYGCRVESIYLNVESVCTHRERSE'}\n", - "Ligand SMILES: Cn1ccc2ccc(-c3cc(Nc4ccccc4S(=O)(=O)NCc4cncnc4)cc4nccnc34)cc21\n", - "JSON saved: json_inputs/6ibz.json\n", - "Processing 6ott, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ott/6ott_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ott/6ott_ligand.sdf\n", - "Found 3 chains: {'A': 'CGIVGIAGVMPVNQSIYDALTVLQHRGQDAAGIITIDANNCFRLRKANGLVSDVFEARHMQRLQGNMGIGHVRYPTAGSSSASEAQPFYVNSPYGITLAHNGNLTNAHELRKKLFEEKRRHINTTSDSEILLNIFASELDNFRHYPLEADNIFAAIAATNRLIRGAYACVAMIIGHGMVAFRDPNGIRPLVLGKRDIDENRTEYMVASESVALDTLGFDFLRDVAPGEAIYITEEGQLFTRQCADNPVSNPCLFEYVYFARPDSFIDKISVYSARVNMGTKLGEKIAREWEDLDIDVVIPIPETSCDIALEIARILGKPYRQGFVKNRYVGRTFIMPGQQLRRKSVRRKLNANRAEFRDKNVLLVDDSIVRGTTSEQIIEMAREAGAKKVYLASAAPEIRFPNVYGIDMPSATELIAHGREVDEIRQIIGADGLIFQDLNDLIDAVRAENPDIQQFECSVFNGVYVTKDVDQGYLDFLDTLRNDDAKAVQRQNEVE', 'C': 'CGIVGIAGVMPVNQSIYDALTVLQHRGQDAAGIITIDANNCFRLRKANGLVSDVFEARHMQRLQGNMGIGHVRYPTAGSSSASEAQPFYVNSPYGITLAHNGNLTNAHELRKKLFEEKRRHINTTSDSEILLNIFASELDNFRHYPLEADNIFAAIAATNRLIRGAYACVAMIIGHGMVAFRDPNGIRPLVLGKRDIDENRTEYMVASESVALDTLGFDFLRDVAPGEAIYITEEGQLFTRQCADNPVSNPCLFEYVYFARPDSFIDKISVYSARVNMGTKLGEKIAREWEDLDIDVVIPIPETSCDIALEIARILGKPYRQGFVKNRYVGRTFIMPGQQLRRKSVRRKLNANRAEFRDKNVLLVDDSIVRGTTSEQIIEMAREAGAKKVYLASAAPEIRFPNVYGIDMPSATELIAHGREVDEIRQIIGADGLIFQDLNDLIDAVRAENPDIQQFECSVFNGVYVTKDVDQGYLDFLDTLRNDDAKAVQRQNEVE', 'D': 'CGIVGIAGVMPVNQSIYDALTVLQHRGQDAAGIITIDANNCFRLRKANGLVSDVFEARHMQRLQGNMGIGHVRYPTAGSSSASEAQPFYVNSPYGITLAHNGNLTNAHELRKKLFEEKRRHINTTSDSEILLNIFASELDNFRHYPLEADNIFAAIAATNRLIRGAYACVAMIIGHGMVAFRDPNGIRPLVLGKRDIDENRTEYMVASESVALDTLGFDFLRDVAPGEAIYITEEGQLFTRQCADNPVSNPCLFEYVYFARPDSFIDKISVYSARVNMGTKLGEKIAREWEDLDIDVVIPIPETSCDIALEIARILGKPYRQGFVKNRYVGRTFIMPGQQLRRKSVRRKLNANRAEFRDKNVLLVDDSIVRGTTSEQIIEMAREAGAKKVYLASAAPEIRFPNVYGIDMPSATELIAHGREVDEIRQIIGADGLIFQDLNDLIDAVRAENPDIQQFECSVFNGVYVTKDVDQGYLDFLDTLRNDDAKAVQRQNEVE'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@@H]1O[C@H](CO[P@@](=O)(O)OP(=O)(O)O)[C@@H](O[P@@](=O)(O)OP(=O)(O)O)[C@H]1O\n", - "JSON saved: json_inputs/6ott.json\n", - "Processing 6gge, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gge/6gge_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gge/6gge_ligand.sdf\n", - "Found 1 chains: {'A': 'SVPSQKTYQGSYGFRLGFLHSGTAKSVTCTYSPALNKLFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPCEPPEVGSDCTTIHYNYMCYSSCMGGMNRRPILTIITLEDSSGNLLGRDSFEVRVCACPGRDRRTEEENLRKK'}\n", - "Ligand SMILES: CCn1c2ccc(C[NH2+]C)cc2c2ccc(-c3ccc(C)s3)cc21\n", - "JSON saved: json_inputs/6gge.json\n", - "Processing 6hot, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hot/6hot_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hot/6hot_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKD'}\n", - "Ligand SMILES: COc1cc(/C=C/C=O)ccc1O\n", - "JSON saved: json_inputs/6hot.json\n", - "Processing 6e3p, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3p/6e3p_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3p/6e3p_ligand.sdf\n", - "Found 1 chains: {'A': 'AMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSER'}\n", - "Ligand SMILES: O=C(O)C1=NC(c2cccc(C3NNNN3)c2)=CC(=O)[C@@H]1O\n", - "JSON saved: json_inputs/6e3p.json\n", - "Processing 6md6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6md6/6md6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6md6/6md6_ligand.sdf\n", - "Found 1 chains: {'A': 'AADYVLYKDATKPVEDRVADLLGRMTLAEKIGQMTQIERLVATPDVLRDNFIGSLLSGGGSVPRKGATAKEWQDMVDGFQKACMSTRLGIPMIYGIDAVHGQNNVYGATIFPHNVGLGATRDPYLVKRIGEATALEVRATGIQYAFAPCIAVCRDPRWGRCYESYSEDRRIVQSMTELIPGLQGDVPKDFTSGMPFVAGKNKVAACAKHFVGDGGTVDGINENNTIINREGLMNIHMPAYKNAMDKGVSTVMISYSSWNGVKMHANQDLVTGYLKDTLKFKGFVISDWEGIDRITTPAGSDYSYSVKASILAGLDMIMVPNKYQQFISILTGHVNGGVIPMSRIDDAVTRILRVKFTMGLFENPYADPAMAEQLGKQEHRDLAREAARKSLVLLKNGKTSTDAPLLPLPKKAPKILVAGSHADNLGYQCGGWTIEWQGDTGRTTVGTTILEAVKAAVDPSTVVVFAENPDAEFVKSGGFSYAIVAVGEHPYTETKGDNLNLTIPEPGLSTVQAVCGGVRCATVLISGRPVVVQPLLAASDALVAAWLPGSEGQGVTDALFGDFGFTGRLPRTWFKSVDQLPMNVGDAHYDPLFRLGYGLTTNAT'}\n", - "Ligand SMILES: CO[C@@H]1O[C@H](CO)[C@@H](O)[C@H](O)[C@H]1S[C@@H]1O[C@H](CO)[C@@H](O)[C@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6md6.json\n", - "Processing 6hlb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hlb/6hlb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hlb/6hlb_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTAS'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCCC[NH3+])NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@@H]([NH3+])CCCN/C(N)=N\\[H])C(=O)NCc1ccc(/C(N)=N\\[H])cc1\n", - "JSON saved: json_inputs/6hlb.json\n", - "Processing 6fe5, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6fe5/6fe5_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6fe5/6fe5_ligand.sdf\n", - "Found 1 chains: {'A': 'KHNMKAFLDELKAENIKKFLYNFTQIPHLAGTEQNFQLAKQIQSQWKEFGLDSVELAHYDVLLSYPNKTHPNYISIINEDGNEIFNTSLFEPPPPGYENVSDIVPPFSAFSPQGMPEGDLVYVNYARTEDFFKLERDMKINCSGKIVIARYGKVFRGNKVKNAQLAGAKGVILYSDPADYFAPGVKSYPDGWNLPGGGVQRGNILNLNGAGDPLTPGYPANEYAYRRGIAEAVGLPSIPVHPIGYYDAQKLLEKMGGSAPPDSSWRGSLKVPYNVGPGFTGNFSTQKVKMHIHSTNEVTRIYNVIGTLRGAVEPDRYVILGGHRDSWVFGGIDPQSGAAVVHEIVRSFGTLKKEGWRPRRTILFASWDAMEFGLLGSTEWAEENSRLLQERGVAYINADSSIEGNYTLRVDCTPLMYSLVHNLTKELKSPDEGFEGKSLYESWTKKSPSPEFSGMPRISKLGSGNDFEVFFQRLGIASGRARYTKNNKFSGYPLYHSVYETYELVEKFYDPMFKYHLTVAQVRGGMVFELANSIVLPFDCRDYAVVLRKYADKIYSISMKHPQEMKTYSVSFDSLFSAVKNFTEIASKFSERLQDFDKSNPIVLRMMNDQLMFLERAFIDPLGLPDRPFYRHVIYAPSSHNKYAGESFPGIYDALFDIESKVDPSKAWGEVKRQIYVAAFTVQAAAETLSEVA'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)N[C@@H](CCC(=O)O)C(=O)O)C(=O)O\n", - "JSON saved: json_inputs/6fe5.json\n", - "Processing 6uwp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uwp/6uwp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uwp/6uwp_ligand.sdf\n", - "Found 1 chains: {'A': 'PGRRGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGFPLNQSEVLASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1\\N[C@@]2([C@@H]3C[C@H]3C(=O)NC[C@@H]3C[C@H]3C)CN(c3ncccn3)C[C@H]2CS1\n", - "JSON saved: json_inputs/6uwp.json\n", - "Processing 6npp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6npp/6npp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6npp/6npp_ligand.sdf\n", - "Found 1 chains: {'B': 'SNPKFENIAEGLRALLARSHVERTTDEGTWVAGVFVYGGSKTSLYNLRRGTALAIPQCRLTPLSRLPFGMAPGPGPQPGPLRESIVCYFMVFLQTHIFAEVLKDAIKDLVMTKPAPTCNIRVTVCSFDDGVDLP'}\n", - "Ligand SMILES: O=C(O)c1cccc(C#Cc2ccccc2)c1-n1cccc1\n", - "JSON saved: json_inputs/6npp.json\n", - "Processing 6g2f, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2f/6g2f_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2f/6g2f_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEQKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYID'}\n", - "Ligand SMILES: Cc1noc(C)c1-c1ncn(C)c1-c1ccnc2cc(F)ccc12\n", - "JSON saved: json_inputs/6g2f.json\n", - "Processing 6mo7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo7/6mo7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo7/6mo7_ligand.sdf\n", - "Found 1 chains: {'A': 'RVTNQLQYLHKVVMKALWKHQFAWPFRQPVDAVKLGLPDYHKIIKQPMDMGTIKRRLENNYYWAASECMQDFNTMFTNCYIYNKPTDDIVLMAQTLEKIFLQKVASMPQEEQEL'}\n", - "Ligand SMILES: CC(=O)NCc1onc(C)c1-c1ccc(C)c(S(=O)(=O)NC2CCCC2)c1\n", - "JSON saved: json_inputs/6mo7.json\n", - "Processing 6bqd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6bqd/6bqd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6bqd/6bqd_ligand.sdf\n", - "Found 1 chains: {'A': 'DDDQVAFSFILDNIVTQKMMAVPDSWPFHHPVNKKFVPDYYKVIVNPMDLETIRKNISKHKYQSRESFLDDVNLILANSVKYNGPESQYTKTAQEIVNVCYQTLTEYDEHLTQLEKDICTAKEAALEEA'}\n", - "Ligand SMILES: C/C=C/CN1C=C(c2cccc(C(=O)N(C)C)c2)C2CCNC2C1=O\n", - "JSON saved: json_inputs/6bqd.json\n", - "Processing 6nsv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nsv/6nsv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nsv/6nsv_ligand.sdf\n", - "Found 1 chains: {'A': 'SPSAQELKEQGNRLFVGRKYPEAAACYGRAITRNPLVAVYYTNRALCYLKMQQHEQALADCRRALELDGQSVKAHFFLGQCQLEMESYDEAIANLQRAYSLAKEQRLNFGDDIPSALRIAKKKRWNSI'}\n", - "Ligand SMILES: no ligand\n", - "JSON saved: json_inputs/6nsv.json\n", - "Processing 6i76, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i76/6i76_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i76/6i76_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4c(F)c(F)c(N=[N+]=[N-])c(F)c4F)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6i76.json\n", - "Processing 6n53, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n53/6n53_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n53/6n53_ligand.sdf\n", - "Found 1 chains: {'A': 'EPFLIGVSGGTASGKSSVCAKIVQLLGQNQKQVVILSQDSFYRVLTSEQKAKALKGQFNFDHPDAFDNELILKTLKEITEGKTVQIPVYDFVSHSRKEETVTVYPADVVLFEGILAFYSQEVRDLFQMKLFVDTDADTRLSRRVLRDISERGRDLEQILSQYITFVKPAFEEFCLPTKKYADVIIPRGADNLVAINLIVQHIQDILN'}\n", - "Ligand SMILES: [N-]=[N+]=N[C@@H]1[C@H](O)[C@@H](COP(=O)(O)O)O[C@H]1n1ccc(=O)[nH]c1=O\n", - "JSON saved: json_inputs/6n53.json\n", - "Processing 6g2c, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2c/6g2c_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2c/6g2c_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEQKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYIDK'}\n", - "Ligand SMILES: Cc1noc(C)c1-c1ncn(C)c1-c1ccncc1\n", - "JSON saved: json_inputs/6g2c.json\n", - "Processing 6eeb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6eeb/6eeb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6eeb/6eeb_ligand.sdf\n", - "Found 1 chains: {'A': 'TEEQIAEFKEAFSLFDKDGDGTITTKELGTVMRSLGQNPTEAELQDMINEVDADGNGTIDFPEFLTMMARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVMTNLGEKLTDEEVDEMIREADIDGDGQVNYEEFVQMMT'}\n", - "Ligand SMILES: CC1(C)C2NC3CC(Cl)C(Cl)CC3C2C[C@@]23C[N@@H+]4CC=C[C@]4(C[C@@H]12)C(=O)N3\n", - "JSON saved: json_inputs/6eeb.json\n", - "Processing 6n0m, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n0m/6n0m_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n0m/6n0m_ligand.sdf\n", - "Found 1 chains: {'A': 'GLEALMSSGRVDNLAVVMGLHPDYFTSFWRLHYLLLHTDGPLASSWRHYIAIMAAARHQCSYLVGSHMAEFLQTGGDPEWLLGLHRAPEKLRKLSEINKLLAHRPWLITKEHIQALLKTGEHTWSLAELIQALVLLTHCHSLSSFVFGCGILPEGDPPSEQSSPRDVEALMERMQQLQESEEMESRFELEKSESLPDMLCFVEDPTFGYEDFTRRGAQAPPTFRAQDYTWEDHGYSLIQRLYPEGGQLLDEKFQAAYSLTYNTIAMHSGVDTSVLRRAIWNYIHCVFGIRYDDYDYGEVNQLLERNLKVYIKTVACYPEKTTRRMYNLFWRHFRHSEKVHVNLLLLEARMQAALLYALRAITRYMT'}\n", - "Ligand SMILES: CC(C)(C[C@H]([NH3+])C(=O)O)C(F)F\n", - "JSON saved: json_inputs/6n0m.json\n", - "Processing 6uvy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uvy/6uvy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uvy/6uvy_ligand.sdf\n", - "Found 1 chains: {'A': 'GSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGFPLNQSEVLASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1\\N[C@@]2([C@@H]3C[C@H]3C(=O)NC[C@@H]3C[C@H]3C)COC[C@H]2CS1\n", - "JSON saved: json_inputs/6uvy.json\n", - "Processing 6ovz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ovz/6ovz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ovz/6ovz_ligand.sdf\n", - "Found 2 chains: {'A': 'DQRFGDLVFRQLAPNVWQHTSYLDMPGFGAVASNGLIVRDGGRVLVVDTAWTDDQTAQILNWIKQEINLPVALAVVTHAHQDKMGGMDALHAAGIATYANALSNQLAPQEGMVAAQHSLTFAANGWVEPATAPNFGPLKVFYPGPGHTSDNITVGIDGTDIAFGGCLIKDSKAKSLGNLGDADTEHYAASARAFGAAFPKASMIVMSHSAPDSRAAITHTARMADKL', 'B': 'DQRFGDLVFRQLAPNVWQHTSYLDMPGFGAVASNGLIVRDGGRVLVVDTAWTDDQTAQILNWIKQEINLPVALAVVTHAHQDKMGGMDALHAAGIATYANALSNQLAPQEGMVAAQHSLTFAANGWVEPATAPNFGPLKVFYPGPGHTSDNITVGIDGTDIAFGGCLIKDSKAKSLGNLGDADTEHYAASARAFGAAFPKASMIVMSHSAPDSRAAITHTARMADKL'}\n", - "Ligand SMILES: O=CONC(=O)OCc1ccccc1\n", - "JSON saved: json_inputs/6ovz.json\n", - "Processing 6olx, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6olx/6olx_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6olx/6olx_ligand.sdf\n", - "Found 1 chains: {'A': 'EVETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNASDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVEK'}\n", - "Ligand SMILES: CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21\n", - "JSON saved: json_inputs/6olx.json\n", - "Processing 6v5l, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6v5l/6v5l_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6v5l/6v5l_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGAGGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKEK'}\n", - "Ligand SMILES: NC(=O)[C@H]([NH2+]NC(=O)C1CNC2CCCCC21)c1ccccc1\n", - "JSON saved: json_inputs/6v5l.json\n", - "Processing 6hhg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhg/6hhg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhg/6hhg_ligand.sdf\n", - "Found 1 chains: {'A': 'DVAIVKEGWLHKRGEYIKTWRPRYFLLKNDGTFIGYKERPQDEAPLNNFSVAQCQLMKTERPRPNTFIIRCLQWTTVIERTFHVETPEEREEWTTAIQTVADGLKKRVTMNEFEYLKLLGKGTFGKVILVKEKATGRYYAMKILKKEVISRHPFLTALKYSFQTHDRLCFVMEYANGGELFFHLSRERVFSEDRARFYGAEIVSALDYLHSEKNVVYRDLKLENLMLDKDGHIKITDFGLCKEGIKTMKTFCGTPEYLAPEVLEDNDYGRAVDWWGLGVVMYEMMCGRLPFYNQDHEKLFELILMEEIRFPRTLGPEAKSLLSGLLKKDPKQRLGGGSEDAKEIMQHRFFAGIVWQHVYEKKLSPPFKPQVTSETDTRYFDEEFTA'}\n", - "Ligand SMILES: CCC(=O)Nc1cc(NC(=O)N[C@H]2CC[N@H+](Cc3ccc(-c4nc5c(cc4-c4ccccc4)C(=O)N=CC5)cc3)CC2)ccc1Cl\n", - "JSON saved: json_inputs/6hhg.json\n", - "Processing 5zcu, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zcu/5zcu_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zcu/5zcu_ligand.sdf\n", - "Found 2 chains: {'A': 'APVWGCASTRGRSAEMEDASAAVPRFADVPVRLLASRRDLDALGLDADALRLPAHLFGVFDGHGGAEVANYCRERIHVVLSAALARLGKDMKEHWDDVFTKCFQRVDDEVSGRVTRVVGGEVRSEPVTAENVGSTAVVALVCSSHVVVANCGDSRIVLCRGKEPVALSIDHKPDRKDERARIEAQGGKVIQWNGYRVSGILAMSRSIGDRYLKPFVIPKPEVMVVPRAKDDDCLILASDGLWDVVSNEEACKVARRQILLWHKNNGSTDPAAQAAADYLMRLALKKGSEDNITVIVVDL', 'C': 'VRRFHRHEPRDHQCSSAVAKHIKAPVHLVWSLVRRFDQPQLFKPFVSRCEMKGNIEIGSVREVNVKSGLPATRSTERLELLDDNEHILSVRFVGGDHRLKNYSSILTVHPEVIDGRPGTLVIESFVVDVPEGNTKDETCYFVEALLKCNLKSLAEVSERLVV'}\n", - "Ligand SMILES: O=S(=O)(NCc1ccccn1)c1ccc(Br)c2ccccc12\n", - "JSON saved: json_inputs/5zcu.json\n", - "Processing 6dz2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dz2/6dz2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dz2/6dz2_ligand.sdf\n", - "Found 2 chains: {'A': 'AVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLLP', 'C': 'AVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLLP'}\n", - "Ligand SMILES: NC1NCNC2C(C[N@@H+]3C[C@H](CSCCCc4cn(Cc5ccccc5)nn4)[C@@H](O)C3)CNC12\n", - "JSON saved: json_inputs/6dz2.json\n", - "Processing 6mjq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mjq/6mjq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mjq/6mjq_ligand.sdf\n", - "Found 4 chains: {'C': 'KTQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNFACANAFNNSIIPEDTFFPS', 'D': 'EAAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'KNYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPSSAHGHRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'KTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRDM'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCc2ccc(C(F)(F)F)cc2)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6mjq.json\n", - "Processing 6efk, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6efk/6efk_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6efk/6efk_ligand.sdf\n", - "Found 1 chains: {'A': 'SPSAQELKEQGNRLFVGRKYPEAAACYGRAITRNPLVAVYYTNRALCYLKMQQHEQALADCRRALELDGQSVKAHFFLGQCQLEMESYDEAIANLQRAYSLAKEQRLNFGDDIPSALRIAKKKRWNSIEERR'}\n", - "Ligand SMILES: CC[C@H](C)[C@H](NC(C)=O)C(=O)N[C@@H](CCC(=O)O)C(=O)N[C@@H](CCC(=O)O)C(=O)N[C@H](C(=O)N[C@@H](CC(=O)O)C(=O)O)C(C)C\n", - "JSON saved: json_inputs/6efk.json\n", - "Processing 6s9w, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s9w/6s9w_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s9w/6s9w_ligand.sdf\n", - "Found 1 chains: {'A': 'DVAIVKEGWLHKRGEYIKTWRPRYFLLKNDGTFIGYKERPQDVDQREAPLNNFSVAQCQLMKTERPRPNTFIIRCLQWTTVIERTFHVETPEEREEWTTAIQTVADGLKKKHRVTMNEFEYLKLLGKGTFGKVILVKEKATGRYYAMKILKKEVIVAKDEVAHTLTENRVLQNSRHPFLTALKYSFQTHDRLCFVMEYANGGELFFHLSRERVFSEDRARFYGAEIVSALDYLHSEKNVVYRDLKLENLMLDKDGHIKITDFGLCKEGIKATMKTFCGTPEYLAPEVLEDNDYGRAVDWWGLGVVMYEMMCGRLPFYNQDHEKLFELILMEEIRFPRTLGPEAKSLLSGLLKKDPKQRLGGGSEDAKEIMQHRFFAGIVWQHVYEKKLSPPFKPQVTSETDTRYFDEEFTA'}\n", - "Ligand SMILES: C=C1NC(c2ccccc2)=C(c2ccc(C[N@H+]3CC[C@H](n4c(=O)[nH]c5ccc(NC(=O)CC)cc54)CC3)cc2)NC1=O\n", - "JSON saved: json_inputs/6s9w.json\n", - "Processing 6gdy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gdy/6gdy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gdy/6gdy_ligand.sdf\n", - "Found 1 chains: {'A': 'MNHKSKKRIREAKRSARPELKDSLDWTRHNYYESFSLSPAAVADNVERADALQLSVEEFVERYERPYKPVVLLNAQEGWSAQEKWTLERLKRKYRNQKFKCGEDNDGYSVKMKMKYYIEYMESTRDDSPLYIFDSSYGEHPKRRKLLEDYKVPKFFTDDLFQYAGEKRRPPYRWFVMGPPRSGTGIHIDPLGTSAWNALVQGHKRWCLFPTSTPRELIKVTRDEGGNQQDEAITWFNVIYPRTQLPTWPPEFKPLEILQKPGETVFVPGGWWHVVLNLDTTIAITQNFASSTNFPVVWHKTVRGRPKLSRKWYRILKQEHPELAVLADSVDLQE'}\n", - "Ligand SMILES: O=C(O)CCC(=O)C(=O)O\n", - "JSON saved: json_inputs/6gdy.json\n", - "Processing 6kqi, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6kqi/6kqi_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6kqi/6kqi_ligand.sdf\n", - "Found 1 chains: {'A': 'NFMDIECFMVLNPSQQLAIAVLSLTLGTFTVLENLLVLCVILHSRSLRCRPSYHFIGSLAVADLLGSVIFVYSFIDFHVFHRKDSRNVFLFKLGGVTASFTAKVGSLFLAAIDRYISIHRPLAYKRIVTRPKAVVAFCLMWTIAIVIAVLPLLGWNCEKLQSVCSDIFPHIDKTYLMFWIGVVSVLLLFIVYAYMYILWKAGINESYLTGSRDERKKSLLSKFGMDEGVTFMFIGRFDRGQKGVDVLLKAIEILSSKKEFQEMRFIIIGKGDPELEGWARSLEEKHGNVKVITEMLSREFVRELYGSVDFVIIPSYFEPFGLVALEAMCLGAIPIASAVGGLRDIITNETGILVKAGDPGELANAILKALELSRSDLSKFRENCKKRAMSFSDQARMDIELAKTLVLILVVLIICWGPLLAIMVYDVFGKMNKLIKTVFAFCSMLCLLNSTVNPIIYALRSKDLRHAFRSMFP'}\n", - "Ligand SMILES: CCCCCCC(C)(C)c1ccc([C@@H]2C[C@H](O)CC[C@H]2CCCO)c(O)c1\n", - "JSON saved: json_inputs/6kqi.json\n", - "Processing 6ueg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ueg/6ueg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ueg/6ueg_ligand.sdf\n", - "Found 3 chains: {'A': 'SLIDPRAIIDPSARLAADVQVGPWSIVGAEVEIGEGTVIGPHVVLKGPTKIGKHNRIYQFSSVGEDTPDLKYKGEPTRLVIGDHNVIREGVTIHRGTVQDRAETTIGDHNLIMAYAHIGHDSVIGNHCILVNNTALAGHVHVDDWAILSGYTLVHQYCRIGAHSFSGMGSAIGKDVPAYVTVFGNPAEARSMNFEGMRRRGFSSEAIHALRRAYKVVYRQGHTVEEALAELAESAAQFPEVAVFRDSIQSATRGITR', 'B': 'SLIDPRAIIDPSARLAADVQVGPWSIVGAEVEIGEGTVIGPHVVLKGPTKIGKHNRIYQFSSVGEDTPDLKYKGEPTRLVIGDHNVIREGVTIHRGTVQDRAETTIGDHNLIMAYAHIGHDSVIGNHCILVNNTALAGHVHVDDWAILSGYTLVHQYCRIGAHSFSGMGSAIGKDVPAYVTVFGNPAEARSMNFEGMRRRGFSSEAIHALRRAYKVVYRQGHTVEEALAELAESAAQFPEVAVFRDSIQSATRGITR', 'C': 'LIDPRAIIDPSARLAADVQVGPWSIVGAEVEIGEGTVIGPHVVLKGPTKIGKHNRIYQFSSVGEDTPDLKYKGEPTRLVIGDHNVIREGVTIHRGTVQDRAETTIGDHNLIMAYAHIGHDSVIGNHCILVNNTALAGHVHVDDWAILSGYTLVHQYCRIGAHSFSGMGSAIGKDVPAYVTVFGNPAEARSMNFEGMRRRGFSSEAIHALRRAYKVVYRQGHTVEEALAELAESAAQFPEVAVFRDSIQSATRGITR'}\n", - "Ligand SMILES: NC(=O)[C@H]1CN(C(=O)CSCCC(=O)O)c2ccccc2O1\n", - "JSON saved: json_inputs/6ueg.json\n", - "Processing 6oxt, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxt/6oxt_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxt/6oxt_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC[C@H](C)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)[C@H]1CC[C@@H]([C@H](C)O)CC1\n", - "JSON saved: json_inputs/6oxt.json\n", - "Processing 6oy0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oy0/6oy0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oy0/6oy0_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC[C@H](C)CN(C[C@@H](O)[C@H](CC1CCCCC1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)[C@H]1CC[C@@H]([C@H](O)CO)CC1\n", - "JSON saved: json_inputs/6oy0.json\n", - "Processing 6qr7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr7/6qr7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr7/6qr7_ligand.sdf\n", - "Found 2 chains: {'A': 'GSMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPGLVDVAVHDLRRWTHDVSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDS'}\n", - "Ligand SMILES: N#CC1C(N)NNC1c1ccc2ccn(Cc3ccc(C[NH+]4CCCCC4)cc3)c2c1\n", - "JSON saved: json_inputs/6qr7.json\n", - "Processing 6i41, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i41/6i41_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i41/6i41_ligand.sdf\n", - "Found 1 chains: {'A': 'ASGKVVKFSYMWTINNFSFCREGEVIKSSTFSSGANDKLKWCLRVNPKGLDEESKDYLSLYLLLVSCPKSEVRAKFKFSILNAKGEETKAMESQRAYRFVQGKDWGFKKFIRRDFLLDEANGLLPDDKLTLFCEVSVVQD'}\n", - "Ligand SMILES: C[C@H]([NH3+])C(=O)N[C@@H](C)C(=O)N[C@@H](CC(=O)O)C(=O)N[C@H](C(=O)N[C@H](C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)O)[C@@H](C)O)[C@@H](C)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6i41.json\n", - "Processing 6cyg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cyg/6cyg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cyg/6cyg_ligand.sdf\n", - "Found 1 chains: {'A': 'EVETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNSSDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVEKE'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@@H]1O[C@H](C(=O)NCCO)[C@@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6cyg.json\n", - "Processing 6qmr, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qmr/6qmr_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qmr/6qmr_ligand.sdf\n", - "Found 1 chains: {'A': 'ILGGREAEAHARPYMASVQLNGAHLCGGVLVAEQWVLSAAHCLEDAADGKVQVLLGAHSLSQPEPSKRLYDVLRAVPHPDSQPDTIDHDLLLLQLSEKATLGPAVRPLPWQRVDRDVAPGTLCDVAGWGIVNHAGRRPDSLQHVLLPVLDRATCNRRTHHDGAITERLMCAESNRRDSCKGDSGGPLVCGGVLEGVVTSGSRVCGNRKKPGIYTRVASYAAWIDSVLASA'}\n", - "Ligand SMILES: [NH3+][C@H](CO)c1cccc(-c2cccc(COc3ccccc3CC(=O)O)c2)c1\n", - "JSON saved: json_inputs/6qmr.json\n", - "Processing 6g27, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g27/6g27_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g27/6g27_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYID'}\n", - "Ligand SMILES: Cc1cc(=O)n(C2CC[NH2+]CC2)nc1-c1ccccc1\n", - "JSON saved: json_inputs/6g27.json\n", - "Processing 6ggb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ggb/6ggb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ggb/6ggb_ligand.sdf\n", - "Found 1 chains: {'A': 'SSVPSQKTYQGSYGFRLGFLHSGTAKSVTCTYSPALNKLFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPCEPPEVGSDCTTIHYNYMCYSSCMGGMNRRPILTIITLEDSSGNLLGRDSFEVRVCACPGRDRRTEEENLRKK'}\n", - "Ligand SMILES: CCn1c2ccc(C[NH2+]C)cc2c2ccc(-c3cccs3)cc21\n", - "JSON saved: json_inputs/6ggb.json\n", - "Processing 6g3c, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g3c/6g3c_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g3c/6g3c_ligand.sdf\n", - "Found 1 chains: {'A': 'FHKIRNEDLIFNESLGQGTFTKIFKGVRREVGDYGQLHETEVLLKVLDKAHRNYSESFFEAASMMSKLSHKHLVLNYGVCFCGDENILVQEFVKFGSLDTYLKKNKNCINILWKLEVAKQLAAAMHFLEENTLIHGNVCAKNILLIREEDRKTGNPPFIKLSDPGISITVLPKDILQERIPWVPPECIENPKNLNLATDKWSFGTTLWEICSGGDKPLSALDSQRKLQFYEDRHQLPAPKAAELANLINNCMDYEPDHRPSFRAIIRDLNSL'}\n", - "Ligand SMILES: CC(C)CCN1c2nc(Nc3cc(F)c(O)c(F)c3)ncc2N(C)C(=O)C1(C)C\n", - "JSON saved: json_inputs/6g3c.json\n", - "Processing 6n4e, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n4e/6n4e_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n4e/6n4e_ligand.sdf\n", - "Found 2 chains: {'A': 'MPNYKLTYFNMRGRAEIIRYIFAYLDIQYEDHRIEQADWPEIKSTLPFGKIPILEVDGLTLHQSLAIARYLTKNTDLAGNTEMEQCHVDAIVDTLDDFMSCFPWAEKKQDVKEQMFNELLTYNAPHLMQDLDTYLGGREWLIGNSVTWADFYWEICSTTLLVFKPDLLDNHPRLVTLRKKVQAIPAVANWIKRRPQTKL', 'B': 'MPNYKLTYFNMRGRAEIIRYIFAYLDIQYEDHRIEQADWPEIKSTLPFGKIPILEVDGLTLHQSLAIARYLTKNTDLAGNTEMEQCHVDAIVDTLDDFMSCFPWAEKKQDVKEQMFNELLTYNAPHLMQDLDTYLGGREWLIGNSVTWADFYWEICSTTLLVFKPDLLDNHPRLVTLRKKVQAIPAVANWIKRRPQTKL'}\n", - "Ligand SMILES: CC(C)(O)[C@H]1CC[C@H](NC(=O)c2cnc3cc(OC(F)F)ccc3c2)CC1\n", - "JSON saved: json_inputs/6n4e.json\n", - "Processing 6fcj, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6fcj/6fcj_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6fcj/6fcj_ligand.sdf\n", - "Found 1 chains: {'A': 'EVETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNSSDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVE'}\n", - "Ligand SMILES: Oc1ccc(-c2ccnn2-c2ccccc2Cl)c(O)c1\n", - "JSON saved: json_inputs/6fcj.json\n", - "Processing 6quv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6quv/6quv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6quv/6quv_ligand.sdf\n", - "Found 2 chains: {'A': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK', 'B': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK'}\n", - "Ligand SMILES: C[N@H+]1CC[C@](C)([C@]23NC(=O)c4ccccc4[C@H]2c2ccccc2N3)CC1\n", - "JSON saved: json_inputs/6quv.json\n", - "Processing 6iql, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6iql/6iql_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6iql/6iql_ligand.sdf\n", - "Found 2 chains: {'A': 'GAAALVGGVLLIGLVLAGNSLVCVSVASERTLQTPTNYFIVSLAAADLLLAVLVLPLFVYSEVQGGVWLLSPRLCDTLMAMDVMLCTASIWNLCAISVDRFVAVTGQCQLLLIAATWLLSAAVASPVVCGLNDVPGRDPENRDYVVYSSVCSFFLPCILMLLLYWATFRGLRRWEADLEDNWETLNDNLKVIEKADNAAQVKDALTKMRAAALDAQKAKDFRHGFDILVGQIDDALKLANEGKVKEAQAAAEQLKTTRNAYIQKYLKITGRERKAMRVLAVVVGAFLVCWTPFFVVHITRALCPACFVSPRLVSAVTWLGYVNSALNPIIYTIFNAEFRSV', 'B': 'GAAALVGGVLLIGLVLAGNSLVCVSVASERTLQTPTNYFIVSLAAADLLLAVLVLPLFVYSEVQGGVWLLSPRLCDTLMAMDVMLCTASIWNLCAISVDRFVAVTVGQCQLLLIAATWLLSAAVASPVVCGVCRLENRDYVVYSSVCSFFLPCILMLLLYWATFRGLRRWEADLEDNWETLNDNLKVIEKADNAAQVKDALTKMRAAALDAQKPEMKDFRHGFDILVGQIDDALKLANEGKVKEAQAAAEQLKTTRNAYIQKYLKITGRERKAMRVLAVVVGAFLVCWTPFFVVHITRALCPACFVSPRLVSAVTWLGYVNSALNPIIYTIFNAEFRSVF'}\n", - "Ligand SMILES: Clc1ccc(N2CC[NH+](CC3CNC4NCCCC34)CC2)cc1\n", - "JSON saved: json_inputs/6iql.json\n", - "Processing 6i74, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i74/6i74_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i74/6i74_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4c(F)c(F)c(F)c(F)c4F)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6i74.json\n", - "Processing 6qr4, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr4/6qr4_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr4/6qr4_ligand.sdf\n", - "Found 2 chains: {'A': 'GSMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: C[N@@H+]1CCCC[C@@H]1Cn1ccc2ccc(C3NNC(N)C3C#N)cc21\n", - "JSON saved: json_inputs/6qr4.json\n", - "Processing 6rnu, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rnu/6rnu_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rnu/6rnu_ligand.sdf\n", - "Found 2 chains: {'A': 'SQSNRELVVDFLSYKLSQKGYSWSQFSESEAVKQALREAGDEFELRYRRAFSDLTSQLHITPGTAYQSFEQVVNELFRDGVNWGRIVAFFSFGGALCVESVDKEMQVLVSRIAAWMATYLNDHLEPWIQENGGWDTFVELYG', 'B': 'SQSNRELVVDFLSYKLSQKGYSWSQFSESEAVKQALREAGDEFELRYRRAFSDLTSQLHITPGTAYQSFEQVVNELFRDGVNWGRIVAFFSFGGALCVESVDKEMQVLVSRIAAWMATYLNDHLEPWIQENGGWDTFVELYG'}\n", - "Ligand SMILES: O=C(O)c1ccc(-c2ccc(F)cc2)c([SH](=O)=O)c1\n", - "JSON saved: json_inputs/6rnu.json\n", - "Processing 6jib, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jib/6jib_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jib/6jib_ligand.sdf\n", - "Found 1 chains: {'A': 'EAVVISGRKLAQQIKQEVRQEVEEWVASGNKRPHLSVILVGENPASHSYVLNKTRAAAVVGINSETIMKPASISEEELLNLINKLNNDDNVDGLLVQLPLPEHIDERRICNAVSPDKDVDGFHVINVGRMCLDQYSMLPATPWGVWEIIKRTGIPTLGKNVVVAGRSKNVGMPIAMLLHTDGAHERPGGDATVTISHRYTPKEQLKKHTILADIVISAAGIPNLITADMIKEGAAVIDVGINRVHKPKLVGDVDFEGVRQKAGYITPVPGGVGPMTVAMLMKNTIIAAKKVLR'}\n", - "Ligand SMILES: O=C(O)c1ccc(C(=O)N2CCc3c(c(=O)oc4ccccc34)C2)cc1\n", - "JSON saved: json_inputs/6jib.json\n", - "Processing 6izq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6izq/6izq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6izq/6izq_ligand.sdf\n", - "Found 1 chains: {'A': 'SAVQYFQFYGYLSQQQNMMQDYVRTGTYQRAILQNHTDFKDKIVLDVGCGSGILSFFAAQAGARKIYAVEASTMAQHAEVLVKSNNLTDRIVVIPGKVEEVSLPEQVDIIISEPMGYMLFNERMLESYLHAKKYLKPSGNMFPTIGDVHLAPFTDEQLYMEQFTKANFWYQPSFHGVDLSALRGAAVDEYFRQPVVDTFDIRILMAKSVKYTVNFLEAKEGDLHRIEIPFKFHMLHSGLVHGLAFWFDVAFIGSIMTVWLSTAPTEPLTHWYQVRCLFQSPLFAKAGDTLSGTCLLIANKRQSYDISIVAQVDQTGSKSSNLLDLKNPFFRY'}\n", - "Ligand SMILES: C[NH2+]C[C@@H](O)C[N@H+]1CCCc2ccccc2C1\n", - "JSON saved: json_inputs/6izq.json\n", - "Processing 6qw8, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qw8/6qw8_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qw8/6qw8_ligand.sdf\n", - "Found 1 chains: {'A': 'ADVQQKLAELERQSGGRLGVALINTADNSQILYRADERFAMCSTSKVMAAAAVLKKSESEPNLLNQRVEIKKSDLVNYNPIAEKHVNGTMSLAELSAAALQYSDNVAMNKLIAHVGGPASVTAFARQLGDETFRLDRTEPTLNTAIPGDPRDTTSPRAMAQTLRNLTLGKALGDSQRAQLVTWMKGNTTGAASIQAGLPASWVVGDKTGSGGYGTTNDIAVIWPKDRAPLILVTYFTQPQPKAESRRDVLASAAKIVTDGL'}\n", - "Ligand SMILES: O=CN1C[C@H]([NH2+]OS(=O)(=O)O)CC[C@H]1C(=O)NC1CC[NH2+]CC1\n", - "JSON saved: json_inputs/6qw8.json\n", - "Processing 6qto, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qto/6qto_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qto/6qto_ligand.sdf\n", - "Found 1 chains: {'A': 'MTFTRYSRLRVIAEIRNIVSSIEFDRDDELFATAGVSRIKVFDFSSVVNEPQCPIVEMSTRSKLSLSWNKHEKNHIASSDYEGIVTVWDVTTRQSLMEYEEHEKRAWSVDFSRTEPSMLVSGSDDCKVKVWTRQEASVINIDMKANICVKYNPGSSNYIAVGSADHHIHYYDLRNISQPLHVFSGHKKAVSYVKFLSNNELASASTDSTLRLWDVKDNLPVRTFRGHTNEKNFVGLTVNSEYLACGSETNEVYVYHKEITRPVTSHRFGSPDMDDAEEEAGSYFISAVCWKSDSPTMLTANSQGTIKVLVLAA'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@@H](NC(=O)[C@H](CCC(=O)O)NC(C)=O)[C@@H](C)CC)C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)N[C@@H](CCC(=O)O)C(=O)N[C@@H](Cc1ccccc1)C(=O)O)C(C)C\n", - "JSON saved: json_inputs/6qto.json\n", - "Processing 6qrd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrd/6qrd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrd/6qrd_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: CC(C)[N@H+]1CC[N@@H+](Cc2ccc(Cn3ccc4ccc(C5NNC(N)C5C#N)cc43)cc2)CC1\n", - "JSON saved: json_inputs/6qrd.json\n", - "Processing 6hza, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hza/6hza_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hza/6hza_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTASGSLVPR'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)CCCC(=O)NCCCC[C@@H](C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)NCc2ccc(/C(N)=N\\[H])cc2)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC1=O\n", - "JSON saved: json_inputs/6hza.json\n", - "Processing 6e5s, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e5s/6e5s_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e5s/6e5s_ligand.sdf\n", - "Found 2 chains: {'A': 'TRDQNGTWEMESNENFEGYMKALDIDFATRKIAVRLTQTKVIDQDGDNFKDKTTSTFRNYDVDFTVGVEFDEYTKSLDNRHVKALVTWEGDVLVCVQKGEKENRGWKKWIEGDKLYLELTCGDQVCRQVFKKK', 'C': 'TRDQNGTWEMESNENFEGYMKALDIDFATRKIAVRLTQTKVIDQDGDNFKDKTTSTFRNYDVDFTVGVEFDEYTKSLDNRHVKALVTWEGDVLVCVQKGEKENRGWKKWIEGDKLYLELTCGDQVCRQVFKKK'}\n", - "Ligand SMILES: C/C=C(C)/C=C/C=C(C)/C=C/C1=C(C)CCCC1(C)C\n", - "JSON saved: json_inputs/6e5s.json\n", - "Processing 6dz3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dz3/6dz3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dz3/6dz3_ligand.sdf\n", - "Found 2 chains: {'A': 'AVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGRQHTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLLP', 'C': 'AVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGRQHTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLLP'}\n", - "Ligand SMILES: CCCCn1cc(CCCSC[C@H]2C[N@@H+](CC3CNC4C(N)NCNC34)C[C@@H]2O)nn1\n", - "JSON saved: json_inputs/6dz3.json\n", - "Processing 6e6w, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e6w/6e6w_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e6w/6e6w_ligand.sdf\n", - "Found 1 chains: {'A': 'MAMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSE'}\n", - "Ligand SMILES: Cc1cc(C2NNNN2)ccc1C1=CC(=O)[C@@H](O)C(C(=O)O)=N1\n", - "JSON saved: json_inputs/6e6w.json\n", - "Processing 6cyh, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cyh/6cyh_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cyh/6cyh_ligand.sdf\n", - "Found 1 chains: {'A': 'EVETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNSSDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVEKE'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@@H]1O[C@H](C(=O)NCC[NH3+])[C@@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6cyh.json\n", - "Processing 5zlf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zlf/5zlf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zlf/5zlf_ligand.sdf\n", - "Found 2 chains: {'A': 'NLEKINELTAQDMAGVNAAILEQLNSDVQLINQLGYYIVSGGGKRIRPMIAVLAARAVGYEGNAHVTIAALIEFIHTATLLHDDVVDESDMRRGKATANAAFGNAASVLVGDFIYTRAFQMMTSLGSLKVLEVMSEAVNVIAEGEVLQLMNVNITEENYMRVIYSKTARLFEAAAQCSGILAGCTPEEEKGLQDYGRYLGTAFQLIDDLLDYNNVGDDLNEGKPTLPLLHQAQMIRTAIEQGNGRHLLEPVLEAMEWTRQRAEEEADKAIAALQVLPDTPWREALIGLAHIAV', 'B': 'MNLEKINELTAQDMAGVNAAILEQLNSDVQLINQLGYYIVSGGGKRIRPMIAVLAARAVGYEGNAHVTIAALIEFIHTATLLHDDVFGNAASVLVGDFIYTRAFQMMTSLGSLKVLEVMSEAVNVIAEGEVLQLMNVNDPDITEENYMRVIYSKTARLFEAAAQCSGILAGCTPEEEKGLQDYGRYLGTAFQLIDDLLLNEGKPTLPLRHLLEPVLEAMNACEWTRQRAEEEADKAIAALQVDTPWREALIGLAHIAVQ'}\n", - "Ligand SMILES: O=P(O)(O)C(O)(Cc1cccc(-c2cccc3c2oc2ccccc23)c1)P(=O)(O)O\n", - "JSON saved: json_inputs/5zlf.json\n", - "Processing 6om4, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6om4/6om4_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6om4/6om4_ligand.sdf\n", - "Found 1 chains: {'A': 'MDYILGRYVKIARYGSGGLVGGGGKEQYVENLVLWENIIKTAYCFITPSSYTAALETANIPEKDFSNCFRFLKENFFIIPSEYNNNNRYSRNFLHYQSYGANPVLVQDKLKNAKVVILGCGGIGNHVSVILATSGIGEIILIDNDQIENTNLTRQVLFSEDDVGKNKTEVIKRELLKRNSEISVSEIALNINDYTDLHKVPEADIWVVSADHPFNLINWVNKYCVRANQPYINAGYVNDIAVFGPLYVPGKTGCYECQKVVADLYGAEKENIDHKIKLINSRFKPATFAPVNNVAAALCAADVIKFIGKYSEPLSLNKRIGIWSDEIKIHSQNMGRSPVCSVCGN'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCSC)NC=O)C(=O)N[C@H](C(=O)NCC(=O)N[C@@H](CC(N)=O)C(=O)N[C@@H](C)C(=O)N[C@@H](CC(=O)O)C(=O)N[P@@](=O)(O)OC[C@H]1O[C@@H](n2cnc3c(N)ncnc32)[C@H](O)[C@@H]1O)[C@@H](C)O\n", - "JSON saved: json_inputs/6om4.json\n", - "Processing 6gga, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gga/6gga_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gga/6gga_ligand.sdf\n", - "Found 1 chains: {'A': 'SVPSQKTYQGSYGFRLGFLHSGTAKSVTCTYSPALNKLFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPCEPPEVGSDCTTIHYNYMCYSSCMGGMNRRPILTIITLEDSSGNLLGRDSFEVRVCACPGRDRRTEEENLRK'}\n", - "Ligand SMILES: CCn1c2ccc(C[NH2+]C)cc2c2ccc(Br)cc21\n", - "JSON saved: json_inputs/6gga.json\n", - "Processing 6pgp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pgp/6pgp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pgp/6pgp_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETSLLDILDTAGQEEYSAMRDQYMRTGEGFLLVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKEK'}\n", - "Ligand SMILES: CCC(=O)N1CCN(c2nc(=O)n(-c3ccccc3C(C)C)c3cc(-c4c(O)cccc4F)c(Cl)cc23)CC1\n", - "JSON saved: json_inputs/6pgp.json\n", - "Processing 6qqv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqv/6qqv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqv/6qqv_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: N#Cc1ccccc1Cn1ccc2ccc(C3CC(N)NN3)cc21\n", - "JSON saved: json_inputs/6qqv.json\n", - "Processing 6qtq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtq/6qtq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtq/6qtq_ligand.sdf\n", - "Found 1 chains: {'A': 'TRYSRLRVIAEIRHNIVSSIEFDRDDELFATAGVSRIKVFDFSSVVNEPQCPIVEMSTRSKLSLSWNKHEKNHIASSDYEGIVTVWDVTTRQSLMEYEEHEKRAWSVDFSRTEPSMLVSGSDDCKVKVWTRQEASVINIDMKANICVKYNPGSSNYIAVGSADHHIHYYDLRNISQPLHVFSGHKKAVSYVKFLSNNELASASTDSTLRLWDVKDNLPVRTFRGHTNEKNFVGLTVNSEYLACGSETNEVYVYHKEITRPVTSHRFGGSYFISAVCWKSDSPTMLTANSQGTIKVLVLAA'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H]([NH3+])C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](C)C(=O)N[C@H](C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)O)C(C)C)C(C)C\n", - "JSON saved: json_inputs/6qtq.json\n", - "Processing 6gj6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj6/6gj6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj6/6gj6_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK'}\n", - "Ligand SMILES: C[NH+](C)CC1NC2CCCCC2C1[C@H]1NC(=O)c2ccc(O)cc21\n", - "JSON saved: json_inputs/6gj6.json\n", - "Processing 6os5, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6os5/6os5_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6os5/6os5_ligand.sdf\n", - "Found 1 chains: {'A': 'TTVRDACARTLENTARTLHLGASGTEFVAAFRAMTDHWGAARPHDLPLSDVSPDGSPVEYAVDLGGLAPALQFAMEPLTAGVPARDPLAARAIMPLLAGRYGADATRWSALADRLLPDDAHGPHVSMYGAEVRAGAPIRFKAWFYLNVTGPDGAFNLLYSALERMGTTHLWPVVQAHVHRAGEDVPFLLSLDLSDDPAARVKVYFRHFAADVEEVAAVLKAYPGFEPGEVRAFCKVMMGGRRRFSDQPAVTCVSLLDAQTFDRTAATLYVPLWTYAEHDGEVRQRVHRTLAAWPEALYRYDSVLAGIAHRGLDAGTGIHNYISWQPGRTRPRMKVYLSPEMHDVTPPPLGVSQ'}\n", - "Ligand SMILES: [NH3+][C@@H](CC1CNC2CCCCC12)C(=O)O\n", - "JSON saved: json_inputs/6os5.json\n", - "Processing 6s07, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s07/6s07_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s07/6s07_ligand.sdf\n", - "Found 1 chains: {'A': 'HMPSFDFDIPRRSPQEIAKGMVAIPGGTFRMGGEDPDAFPEDGEGPVRTVRLSPFLIDRYAVSNRQFAAFVKATGYVTDAERYGWSFVFHAHVAPGTPVMDAVVPEAPWWVAVPGAYWKAPEGPGSSITDRPNHPVVHVSWNDAVAYATWAGKRLPTEAEWEMAARGGLDQARYPWGNELTPRGRHRCNIWQGTFPVHDTGEDGYTGTAPVNAFAPNGYGLYNVAGNVWEWCADWWSADWHATESPATRIDPRGPETGTARVTKGGSFLCHESYCNRYRVAARTCNTPDSSAAHTGFRCAADP'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CO)NC(=O)[C@@H]1CCCN1C(=O)CNC(=O)[C@H](CS)NC(=O)[C@H](CC(C)C)NC(=O)[C@@H]1CCCN1C(=O)[C@@H](NC(=O)[C@@H](NC(=O)[C@H](C)NC(=O)c1ccccc1N)[C@@H](C)O)[C@@H](C)O)C(=O)N[C@@H](C)C(=O)N[C@@H](CO)C(=O)N[C@H](C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](CO)C(=O)NCC(=O)O)[C@@H](C)CC\n", - "JSON saved: json_inputs/6s07.json\n", - "Processing 6i77, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i77/6i77_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i77/6i77_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4c(F)c(F)c(N)c(F)c4F)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6i77.json\n", - "Processing 6hhj, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhj/6hhj_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhj/6hhj_ligand.sdf\n", - "Found 1 chains: {'A': 'DVAIVKEGWLHKRGEYIKTWRPRYFLLKNDGTFIGYKERPQDQREAPLNNFSVAQCQLMKTERPRPNTFIIRCLQWTTVIERTFHVETPEEREEWTTAIQTVADGLKKQRVTMNEFEYLKLLGKGTFGKVILVKEKATGRYYAMKILKKEVIVAKDEVAHTLTENRVLQNSRHPFLTALKYSFQTHDRLCFVMEYANGGELFFHLSRERVFSEDRARFYGAEIVSALDYLHSEKNVVYRDLKLENLMLDKDGHIKITDFGLCKEGIKDGATMKTFCGTPEYLAPEVLEDNDYGRAVDWWGLGVVMYEMMCGRLPFYNQDHEKLFELILMEEIRFPRTLGPEAKSLLSGLLKKDPKQRLGGGSEDAKEIMQHRFFAGIVWQHVYEKKLSPPFKPQVTSETDTRYFDEEFTA'}\n", - "Ligand SMILES: CCC(=O)Nc1ccc2c(c1)n([C@H]1CC[N@H+](Cc3ccc(-c4nc5c(cc4-c4ccccc4)C(=O)N=CC5)cc3)CC1)c(=O)n2C\n", - "JSON saved: json_inputs/6hhj.json\n", - "Processing 6ahs, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ahs/6ahs_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ahs/6ahs_ligand.sdf\n", - "Found 1 chains: {'A': 'IIDGYKCKEGSHPWQVALLKGNQLHCGGVLVDKYWVLTAAHCKMGQYQVQLGSDKIGDQSAQKIKATKSFRHPGYSTKTHVNDIMLVRLDEPVKMSSKVEAVQLPEHCEPPGTSCTVSGWGTTTSPDVTFPSDLMCSDVKLISSRECKKVYKDLLGKTMLCAGIPDSKTNTCNGDSGGPLVCNDTLQGLVSWGTYPCGQPNDPGVYTQVCKYKRWVMETMKTHR'}\n", - "Ligand SMILES: CC1=N[C@H](c2cn(S(=O)(=O)c3ccccc3Cl)c3ccc(C)cc23)CN1\n", - "JSON saved: json_inputs/6ahs.json\n", - "Processing 6oxx, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxx/6oxx_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxx/6oxx_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC(C)CN(C[C@@H](O)[C@H](CC1CCCCC1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@@H](O)CO)cc1\n", - "JSON saved: json_inputs/6oxx.json\n", - "Processing 6mjj, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mjj/6mjj_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mjj/6mjj_ligand.sdf\n", - "Found 4 chains: {'C': 'KTQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNFACANAFNNSIIPEDTFFPS', 'D': 'AAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'NYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPSSAHGHRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'KTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRDM'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCc2ccc(Cl)c(Cl)c2)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6mjj.json\n", - "Processing 6hor, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hor/6hor_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hor/6hor_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKD'}\n", - "Ligand SMILES: COc1cc(/C=C/C(C)=O)ccc1O\n", - "JSON saved: json_inputs/6hor.json\n", - "Processing 6jb0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jb0/6jb0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jb0/6jb0_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGAQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O[C@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jb0.json\n", - "Processing 6i68, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i68/6i68_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i68/6i68_ligand.sdf\n", - "Found 1 chains: {'A': 'SGKVVKFSYMWTINNFSFCREEMGEVIKSSTFSSGANDKLKWCLRVNPKGLDEESKDYLSLYLLLVSCPKSEVRAKFKFSILNAKGEETKAVESQRAYRFVQGKDWGFKKFIRRDFLLDEANGLLPDDKLTLFCEVSVVQD'}\n", - "Ligand SMILES: CCCC[C@H]([NH3+])C(=O)N[C@@H](C)C(=O)N[C@@H](CC(=O)O)C(=O)N[C@H](C(=O)N[C@H](C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)O)[C@@H](C)O)[C@@H](C)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6i68.json\n", - "Processing 6pz4, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pz4/6pz4_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pz4/6pz4_ligand.sdf\n", - "Found 1 chains: {'A': 'FVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAVLASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYNI'}\n", - "Ligand SMILES: [H]/N=C1\\N[C@](C)(c2cc(NC(=O)c3cnc(OCC#C)cn3)cc(F)c2F)[C@@H]2C[C@]2(COC)S1\n", - "JSON saved: json_inputs/6pz4.json\n", - "Processing 6mhb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mhb/6mhb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mhb/6mhb_ligand.sdf\n", - "Found 1 chains: {'A': 'ARSLGKGSAPPGPVPEGSIRIYSMRFCPFAERTRLVLKAKGIRHEVININLKNKPEWFFKKNPFGLVPVLENSQGQLIYESAITCEYLDEAYPGKKLLPDDPYEKACQKMILELFSKVPSLVGSFIRKEDYAGLKEEFRKEFTKLEEVLTNKKTTFFGGNSISMIDYLIWPWFERLEAMKLNECVDHTPKLKLWMAAMKEDPTVSALLTSEKDWQGFLELYLQNSPEACDYGL'}\n", - "Ligand SMILES: CCC(=O)Nc1nc(-c2ccc(Cl)cc2)cs1\n", - "JSON saved: json_inputs/6mhb.json\n", - "Processing 6uim, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uim/6uim_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uim/6uim_ligand.sdf\n", - "Found 1 chains: {'A': 'AASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGYNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKHLAQSVRTVVVPPPGVELTLPKNCQHSISESTAKEVQRIRDKHFTDQNILRSLGNIISVLDRMMRSDEVCNGCVVVSDLSVSVQCALQHALTEPAERVLVVYVGDGELPVKTNDGKVFLVQICTKETEDKCVNRLTLCLREGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETTRLMRVWGHMTCLIQGLARGRMLTLLQGYDKDLLELTVSALSGASISPLGPRAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: [NH3+]CCC[NH2+]CCCCCC(=O)CS\n", - "JSON saved: json_inputs/6uim.json\n", - "Processing 6jsg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsg/6jsg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsg/6jsg_ligand.sdf\n", - "Found 1 chains: {'A': 'RGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYNI'}\n", - "Ligand SMILES: [H]/N=C1/N[C@](C)(c2cc(NC(=O)c3ccc(Cl)cn3)ccc2F)CCS1\n", - "JSON saved: json_inputs/6jsg.json\n", - "Processing 6i78, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i78/6i78_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i78/6i78_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: CNc1c(F)c(F)c(-c2cn([C@H]3[C@@H](O)[C@@H](CO)O[C@@H](Sc4ccc(C)cc4)[C@@H]3O)nn2)c(F)c1F\n", - "JSON saved: json_inputs/6i78.json\n", - "Processing 6oxy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxy/6oxy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxy/6oxy_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC(C)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@H](O)CO)cc1\n", - "JSON saved: json_inputs/6oxy.json\n", - "Processing 6gbw, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gbw/6gbw_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gbw/6gbw_ligand.sdf\n", - "Found 1 chains: {'H': 'IVEGSDAEIGMSPWQVMLFRKSPQELLCGASLISDRWVLTAAHCLLYPPWDKNFTENDLLVRIGKHSRTRYERNIEKISMLEKIYIHPRYNWRENLDRDIALMKLKKPVAFSDYIHPVCLPDRETAASLLQAGYKGRVTGWGNLKETGQPSVLQVVNLPIVERPVCKDSTRIRITDNMFCAGYKPDEGKRGDACEGDSGGPFVMKSPFNNRWYQMGIVSWGEGCDRDGKYGFYTHVFRLKKWIQKVIDQF'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NS(=O)(=O)Cc1ccccc1)C(=O)N1CCC[C@H]1C(=O)NCc1cc(Cl)ccc1C[NH3+]\n", - "JSON saved: json_inputs/6gbw.json\n", - "Processing 6mo0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo0/6mo0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo0/6mo0_ligand.sdf\n", - "Found 1 chains: {'A': 'MADLELERAADVRWEEQAEISGSSLEDGAYRIKQKGILGYSQIGAGVYKEGTFHTMWHVTRGAVLMHKGKRIEPSWADVKKDLISYGGGWKLEGEWKEGEEVQVLALEPGKNPRAVQTKPGLFKTNTGTIGAVSLDFSPGTSGSPIVDKKGKVVGLYGIANTEK'}\n", - "Ligand SMILES: [NH3+]Cc1ccc(-c2ncc(OCC3CC[NH2+]CC3)nc2-c2ccc(-c3ccoc3)cc2)cc1\n", - "JSON saved: json_inputs/6mo0.json\n", - "Processing 6ggf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ggf/6ggf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ggf/6ggf_ligand.sdf\n", - "Found 1 chains: {'A': 'SVPSQKTYQGSYGFRLGFLHSGTAKSVTCTYSPALNKLFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPCEPPEVGSDCTTIHYNYMCYSSCMGGMNRRPILTIITLEDSSGNLLGRDSFEVRVCACPGRDRRTEEENLRK'}\n", - "Ligand SMILES: CCn1c2ccc(C[NH2+]C)cc2c2ccc(-c3cc(C)cs3)cc21\n", - "JSON saved: json_inputs/6ggf.json\n", - "Processing 6qge, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qge/6qge_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qge/6qge_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: OC[C@H]1O[C@@H](SC[C@@H](O)Cn2cc(-c3cccc(F)c3)nn2)[C@H](O)[C@@H](n2cc(-c3cccc(F)c3)nn2)[C@H]1O\n", - "JSON saved: json_inputs/6qge.json\n", - "Processing 6cjr, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjr/6cjr_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjr/6cjr_ligand.sdf\n", - "Found 1 chains: {'A': 'GETHEFTAEISQLMSLIINTVYSNKEIFLRELISNASDALDKIRYQALSDPSQLESEPELFIRIIPQKDQKVLEIRDSGIGMTKADLVNNLGTIAKSGTKSFMEALSAGADVSMIGQFGVGFYSLFLVADHVQVISKHNDDEQYVWESNAGGKFTVTLDETNERLGRGTMLRLFLKEDQLEYLEEKRIKEVVKKHSEFVAYPIQLVVTKEVEK'}\n", - "Ligand SMILES: CC1(C)CC(=O)c2c(C(F)(F)F)nn(-c3ccc(C(N)=O)c(N[C@H]4CC[C@H](O)CC4)c3)c2C1\n", - "JSON saved: json_inputs/6cjr.json\n", - "Processing 6oxp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxp/6oxp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxp/6oxp_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC[C@H](C)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc(CO)cc1\n", - "JSON saved: json_inputs/6oxp.json\n", - "Processing 6d07, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d07/6d07_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d07/6d07_ligand.sdf\n", - "Found 1 chains: {'A': 'GEYVVEKVLDRRVVKGKVEYLLKWKGFSDEDNTWEPEENLDCPDLIAEFLQSQK'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](C)NC(=O)[C@@H](NC(=O)[C@H](CCC(N)=O)NC(=O)[C@@H]([NH3+])CCCC[NH3+])[C@@H](C)O)C(=O)N[C@@H](CCCC[N+](C)(C)C)C(=O)N[C@@H](CO)C(=O)N[C@H](C(=O)NCC(=O)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6d07.json\n", - "Processing 6i63, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i63/6i63_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i63/6i63_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEAKV'}\n", - "Ligand SMILES: CC(C)(c1ccc(O)cc1)c1ccc(O)cc1\n", - "JSON saved: json_inputs/6i63.json\n", - "Processing 6ten, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ten/6ten_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ten/6ten_ligand.sdf\n", - "Found 1 chains: {'A': 'LELRLKSPVGAEPAVYPWPLPVYDKHHDAAHEIIETIRWVCEEIPDLKLAMENYVLIDYDTKSFESMQRLCDKYNRAIDSIHQLWKGNTRPSTGLLRHILQQVYNHSVTDPEKLNNYEPFSPEVYGETSFDLVAQMIDEIKMTDDDLFVDLGSGVGQVVLQVAAATNCKHHYGVEKADIPAKYAETMDREFRKWMKWYGKKHAEYTLERGDFLSEEWRERIANTSVIFVNNFAFGPEVDHQLKERFANMKEGGRIVSSKPFAPLNFRINSRNLSDIGTIMRVVELSPLKSWTGKPVSYYLHTIDRTILENYFSSLKNP'}\n", - "Ligand SMILES: COc1nc(N)nc(Nc2cc(S(N)(=O)=O)ccc2N[C@@H](c2cccc3c2OC(F)(F)O3)c2ncccc2Cl)n1\n", - "JSON saved: json_inputs/6ten.json\n", - "Processing 6uii, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uii/6uii_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uii/6uii_ligand.sdf\n", - "Found 1 chains: {'A': 'AASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGFNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKHLAQSVRTVVVPPPGVELTLPKNCQHSISESTAKEVQRIRDKHFDLTDNILRSLGNIISVLDRMMRSDEVCNGCVVVSDLSVSVQCALQHALTEPAERVLVVYVGDGELPVKTNDGKVFLVQICTKETDKCVNRLTLCLGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETLMRVWGHMTCLIQGLARGRMLTLLQGYDKDLLELTVSALSGASISPLGLRAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: [NH3+]CCC[NH2+]CCCCCS\n", - "JSON saved: json_inputs/6uii.json\n", - "Processing 6qlr, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlr/6qlr_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlr/6qlr_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4cc(F)cc(F)c4)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qlr.json\n", - "Processing 6sen, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6sen/6sen_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6sen/6sen_ligand.sdf\n", - "Found 1 chains: {'A': 'RSVASSKLWMLEFSAFLEQQQDPDTYNKHLFVHIGQSYLEAVDIRQIYDKFPEKKGGLKDLFERGPSNAFFLVKFWADLNTNSSFYGVSSQYESPENMIITCSTKVCSFGKQVVEVETEYARYENGHYSYRIHRSPLCEYMINFIHKLKHLPEKYMMNSVLENFTILQVVTNRDTQETLLCIAYVFEVSASEHGAQHHIYRLVK'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](C)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CCSC)NC(=O)[C@@H]1CCCN1C(=O)[C@@H](NC(C)=O)C(C)C)C(=O)N[C@@H](CCC(N)=O)C(=O)N[C@@H](CC(C)C)C(=O)N1CCC[C@H]1C(=O)N[C@@H](C)C(=O)N[C@@H](CO)C(=O)N[C@@H](Cc1ccccc1)C(=O)N[C@@H](CC1CNC2CCCCC12)C(=O)N[C@@H](CCC(=O)O)C(=O)N[C@@H](CCC(=O)O)C(=O)N1CCC[C@H]1C(N)=O\n", - "JSON saved: json_inputs/6sen.json\n", - "Processing 6oxv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxv/6oxv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxv/6oxv_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CCC(CC)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@H](C)O)cc1\n", - "JSON saved: json_inputs/6oxv.json\n", - "Processing 6g2b, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2b/6g2b_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2b/6g2b_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEAQKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYIDKQ'}\n", - "Ligand SMILES: Cn1cnc(-c2ccccc2)c1-c1ccncc1\n", - "JSON saved: json_inputs/6g2b.json\n", - "Processing 5zr3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zr3/5zr3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zr3/5zr3_ligand.sdf\n", - "Found 1 chains: {'A': 'MEEEEVETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNSSDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVE'}\n", - "Ligand SMILES: Cc1cc(C(N)=O)ccc1-n1nc(C(C)C)c2c(-n3cnc(-c4cnn(C)c4)c3)ccnc21\n", - "JSON saved: json_inputs/5zr3.json\n", - "Processing 6kjf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6kjf/6kjf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6kjf/6kjf_ligand.sdf\n", - "Found 1 chains: {'B': 'HMDTTFQAAIDTGKINGAVVCATDAQGHFVYNKATGERTLLSGEKQPQQLDDVLYLASATKLITTIAALQCVEDGLLSLDGDLSSIAPELAAKYVLTGFTDDESPLDDPPARPITLKMLLTHSSGTSYHFLDPSIAKWRAQYANPENEKPRLVEEMFTYPLSFQPGTGWMYGPGLDWAGRVVERVTGGTLMEFMQKRIFDPLGITDSQFYPVTREDLRARLVDLNPSDPGALGSAVIGGGGEMNLRGRGAFGGHGLFLTGLDFVKILRSLLANDGMLLKPAAVDNMFQQHLGPEAAASHRAALASPLGPFFRVGTDPETKVGYGLGGLLTLEDVDGWYGERTLTWGGGLTLTWFIDRKNNLCGVGAIQAVLPVDGDLMADLKQTFRHDIYRKYSAWKGQQ'}\n", - "Ligand SMILES: CCC(C)(C)C(=O)O[C@H]1C[C@@H](C)C=C2C=C[C@H](C)[C@H](CC[C@@H](O)C[C@@H](O)CC(=O)O)[C@H]21\n", - "JSON saved: json_inputs/6kjf.json\n", - "Processing 6qr9, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr9/6qr9_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr9/6qr9_ligand.sdf\n", - "Found 2 chains: {'A': 'GSMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDS'}\n", - "Ligand SMILES: N#CC1C(N)NNC1c1ccc2ccn(Cc3ccc(C[NH+]4CCOCC4)cc3)c2c1\n", - "JSON saved: json_inputs/6qr9.json\n", - "Processing 6g9f, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g9f/6g9f_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g9f/6g9f_ligand.sdf\n", - "Found 1 chains: {'A': 'NRIKLVPIAPSRGIIYDRNGIPLALNRTIYQIEMMPEKVDNVQQTLDALRSVVDLTDDDIAAFRKERARSHRFTSIPVKTNLTEVQVARFAVNQYRFPGVEVKGYKRRYYPYGSALTHVIGYVSKINDKDVERLNNDGKLANYAATHDIGKLGIERYYEDVLHGQTGYEEVEVNNRGRVIRQLKEVPPQAGHDIYLTLDLKLQQYIETLLAGSRAAVVVTDPRTGGVLALVSTPSYDPNLFVDGISSKDYSALLNDPNTPLVNRATQGVYPPASTVKPYVAVSALSAGVITRNTTLFDPGWWQLPGSEKRYRDWKKWGHGRLNVTRSLEESADTFFYQVAYDMGIDRLSEWMGKFGYGHYTGIDLAEERSGNMPTREWKQKRFKKPWYQGDTIPVGIGQGYWTATPIQMSKALMILINDGIVKVPHLLMSTAEDGKQVPWVQPHEPPVGDIHSGYWELAKDGMYGVANRPNGTAHKYFASAPYKIAAKSGTAQLRDHKLMTAFAPYNNPQVAVAMILENGGAGPAVGTLMRQILDHIML'}\n", - "Ligand SMILES: NC(=O)[C@@H]1CC[C@@H]([NH2+]OS(=O)(=O)O)CN1C=O\n", - "JSON saved: json_inputs/6g9f.json\n", - "Processing 6e6v, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e6v/6e6v_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e6v/6e6v_ligand.sdf\n", - "Found 1 chains: {'A': 'MAMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIKSEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSERGE'}\n", - "Ligand SMILES: CC1=CC(=O)[C@H](O)C(C(=O)O)=N1\n", - "JSON saved: json_inputs/6e6v.json\n", - "Processing 5zk9, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zk9/5zk9_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zk9/5zk9_ligand.sdf\n", - "Found 1 chains: {'A': 'PEHYIKHPLQNRWALWFFKNDKSKTWQANLRLISKFDTVEDFWALYNHIQLSSNLMPGCDYSLFKDGIEPMWEDEKNKRGGRWLITLNKQQRRSDLDRFWLETLLCLIGESFDDYSDDVCGAVVNVRAKGDKIAIWTTECENREAVTHIGRVYKERLGLPPKIVIGYQSHADTATKTKNRFVV'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(C)=O)C(=O)N[C@H](C(=O)N[C@H](C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](CO)C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)N[C@@]1(C)CCC/C=C\\CCC[C@@](C)(C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](CCCC[NH3+])C(N)=O)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CCC(N)=O)NC1=O)[C@@H](C)CC)[C@@H](C)CC\n", - "JSON saved: json_inputs/5zk9.json\n", - "Processing 6pnn, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pnn/6pnn_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pnn/6pnn_ligand.sdf\n", - "Found 1 chains: {'A': 'ESARSLGKGSAPPGPVPEGSIRIYSMRFCPFAERTRLVLKAKGIRHEVININLKNKPEWFFKKNPFGLVPVLENSQGQLIYESAITCEYLDEAYPGKKLLPDDPYEKACQKMILELFSKVPSLVGSFIRSQNKEDYAGLKEEFRKEFTKLEEVLTNKKTTFFGGNSISMIDYLIWPWFERLEAMKLNECVDHTPKLKLWMAAMKEDPTVSALLTSEKDWQGFLELYLQNSPEACDYGL'}\n", - "Ligand SMILES: COCCN(C)S(=O)(=O)c1cc(NC(C)=O)ccc1Cl\n", - "JSON saved: json_inputs/6pnn.json\n", - "Processing 6nri, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nri/6nri_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nri/6nri_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLPKPVQDLIKMIFGGDPIDVNYEKLKTDIKVVDRDSEEAEIIRKYVKNTHATTHNAYDLEVIDIFKIEREGECQRYKPFKQLHNRRLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQGDPIGLILLGEVALGNMYELKHASHISKLPKGKHSVKGLGKTTPDPSANISLDGVDVPLGTGISSGVNDTSLLYNEYIVYDIAQVNLKYLLKLKFNFK'}\n", - "Ligand SMILES: NC(=O)c1cccc2c1O/C(=C\\c1ccc(C(=O)N3CCn4c(nnc4C4C=C4)C3)cc1)C2=O\n", - "JSON saved: json_inputs/6nri.json\n", - "Processing 6uwv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uwv/6uwv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uwv/6uwv_ligand.sdf\n", - "Found 1 chains: {'A': 'RRGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGFPLNQSEVLASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1\\N[C@@]2([C@@H]3C[C@H]3C(C)(C)OC[C@@H]3C[C@H]3C)CN(c3ncccn3)C[C@H]2CS1\n", - "JSON saved: json_inputs/6uwv.json\n", - "Processing 6ooz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ooz/6ooz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ooz/6ooz_ligand.sdf\n", - "Found 3 chains: {'A': 'TPSDKPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPSTHVLLTHTISRIAVSYQTKVNLLSAIKSPCQRETPAKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL', 'B': 'RTPSDKPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPHVLLTHTISRIAVSYQTKVNLLSAIKSPCEAKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL', 'C': 'DKPVAHVVANPEGQLQWLNANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCTHVLLTHTISRIAVQTKVNLLSAIKSPCQREAKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFGQVYFGIIAL'}\n", - "Ligand SMILES: Cc1ccc(C)c(Cn2c([C@@H](O)c3ccncc3)nc3ccccc32)c1\n", - "JSON saved: json_inputs/6ooz.json\n", - "Processing 6npi, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6npi/6npi_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6npi/6npi_ligand.sdf\n", - "Found 1 chains: {'B': 'SNPKFENIAEGLRALLARSHVERTTDEGTWVAGVFVYGGSKTSLYNLRRGTALAIPQCRLTPLSRLPFGMAPGPGPQPGPLRESIVCYFMVFLQTHIFAEVLKDAIKDLVMTKPAPTCNIRVTVCSFDDGVDLP'}\n", - "Ligand SMILES: O=C(O)c1ccccc1-n1cccc1\n", - "JSON saved: json_inputs/6npi.json\n", - "Processing 6oip, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oip/6oip_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oip/6oip_ligand.sdf\n", - "Found 1 chains: {'A': 'KYVDKIHIGNYEIDAWYFSPFPEDYGKQPKLWLCEYCLKYMKYEKSYRFHLGQCQWRQPPGKEIYRKSNISVHEVDGKDHKIYCQNLCLLAKLFLDHTLYFDVEPFVFYILTEVDRQGAHIVGYFSKEKESPDGNNVSCIMILPPYQRRGYGRFLIAFSYELSKLESTVGSPEKPLSDLGKLSYRSYWSWVLLENLRDFRGTLSIKDLSQMTSITQNDIISTLQSLNMVKYWKGQHVICVTPKLVEEHLKSAQYKKPPITVDSVCLKWAPP'}\n", - "Ligand SMILES: Cc1cccc(C(=O)NNS(=O)(=O)c2ccc3ccccc3c2)c1F\n", - "JSON saved: json_inputs/6oip.json\n", - "Processing 6miv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6miv/6miv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6miv/6miv_ligand.sdf\n", - "Found 4 chains: {'C': 'TQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNKFACANAFNNSIIPEDTFFPS', 'D': 'AAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'NYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPSSAHRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'QKTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRDM'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCc2ccc(C(C)(C)C)cc2)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6miv.json\n", - "Processing 6s57, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s57/6s57_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s57/6s57_ligand.sdf\n", - "Found 1 chains: {'A': 'SMQEEDTFRELRIFLRNVTHRLAIDKRFRVFTKPVDPDEVPDYVTVIKQPMDLSSVISKIDLHKYLTVKDYLRDIDLICSNALEYNPDRDPGDRLIRHRACALRDTAYAIIKEELDEDFEQLCEEIQESR'}\n", - "Ligand SMILES: Cc1ccc(NC(=O)CN2C(=O)NC(C)(C)C2=O)cc1S(=O)(=O)N1CCCCCC1\n", - "JSON saved: json_inputs/6s57.json\n", - "Processing 6p8x, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6p8x/6p8x_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6p8x/6p8x_ligand.sdf\n", - "Found 1 chains: {'A': 'TEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETSLLDILDTAGQEEYSAMRDQYMRTGEGFLLVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK'}\n", - "Ligand SMILES: CCC(=O)N1CC(NC(=O)COc2ccc(Br)cc2C(=O)N2CC=C(c3ccccc3)C2)C1\n", - "JSON saved: json_inputs/6p8x.json\n", - "Processing 6hoq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hoq/6hoq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hoq/6hoq_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKD'}\n", - "Ligand SMILES: COc1cc(/C=C/C(=O)O)ccc1O\n", - "JSON saved: json_inputs/6hoq.json\n", - "Processing 6qts, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qts/6qts_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qts/6qts_ligand.sdf\n", - "Found 1 chains: {'A': 'TRYSRLRVIAEIRHNIVSSIEFDRDDELFATAGVSRIKVFDFSSVVNEPQPIVEMSTRSKLSLSWNKHEKNHIASSDYEGIVTVWDVTTRQSLMEYEEHEKRAWSVDFSRTEPSMLVSGSDDKVKVWTRQEASVINIDMKANICVKYNPGSSNYIAVGSADHHIHYYDLRNISQPLHVFSGHKKAVSYVKFLSNNELASASTDSTLRLWDVKDNLPVRTFRGHTNEKNFVGLTVNSEYLACGSETNEVYVYHKEITRPVTSHRFGGSYFISAVCWKSDSPTMLTANSQGTIKVLVLAA'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H]([NH3+])C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](C)C(=O)N[C@H](C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)N[C@@H](CC(=O)O)C(=O)O)C(C)C)C(C)C\n", - "JSON saved: json_inputs/6qts.json\n", - "Processing 6ggd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ggd/6ggd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ggd/6ggd_ligand.sdf\n", - "Found 1 chains: {'A': 'SVPSQKTYQGSYGFRLGFLHSGTAKSVTCTYSPALNKLFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPCEPPEVGSDCTTIHYNYMCYSSCMGGMNRRPILTIITLEDSSGNLLGRDSFEVRVCACPGRDRRTEEENLRK'}\n", - "Ligand SMILES: CCn1c2ccc(C[NH2+]C)cc2c2ccc(-c3cnoc3)cc21\n", - "JSON saved: json_inputs/6ggd.json\n", - "Processing 6pnm, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pnm/6pnm_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pnm/6pnm_ligand.sdf\n", - "Found 1 chains: {'A': 'GESARSLGKGSAPPGPVPEGSIRIYSMRFCPFAERTRLVLKAKGIRHEVININLKNKPEWFFKKNPFGLVPVLENSQGQLIYESAITCEYLDEAYPGKKLLPDDPYEKACQKMILELFSKVPSLVGSFIRSQNKEDYAGLKEEFRKEFTKLEEVLTNKKTTFFGGNSISMIDYLIWPWFERLEAMKLNECVDHTPKLKLWMAAMKEDPTVSALLTSEKDWQGFLELYLQNSPEACDYGL'}\n", - "Ligand SMILES: CC(=O)Nc1ccc(Cl)c(S(=O)(=O)N2CCOCC2)c1\n", - "JSON saved: json_inputs/6pnm.json\n", - "Processing 6oy2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oy2/6oy2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oy2/6oy2_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CCC(CC)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@H](O)CO)cc1\n", - "JSON saved: json_inputs/6oy2.json\n", - "Processing 6oi8, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oi8/6oi8_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oi8/6oi8_ligand.sdf\n", - "Found 1 chains: {'A': 'MLEKVVIANRGEIALRILRACKELGIKTVAVHSTADRDLKHVLLADETICIGPAPSAKSYLNIPAIIAAAEVTGADAIHPGYGFLSENADFAEQVERSGFTFIGPTADVIRLMGDKVSAIKAMKKAGVPCVPGSDGPVSNDIAKNKEIAKRIGYPIIIKASGGMRVVRSEDALEESIAMTKAEAKAAFNNDMVYMEKYLENPRHVEIQVLADTHGNAVYLAERDCSMQRRHQKVVEEAPAPGITEEVRRDIGSRCANACVEIGYRGAGTFEFLYENGEFYFIEMNTRIQVEHPVTEMITGVDLVKEQLRIAAGLPISFKQEDIKVKGHAMECRINAEDPKTFLPSPGKVNHLHSPGGLGVRWDSHVYGGYTVPPHYDSMIAKLITYGDTREVAIRRMQNALSETIIDGIKTNIPLHELILEDENFQKGGTNIHYLEKKLG'}\n", - "Ligand SMILES: Nc1ncc2cc(-c3c(Cl)cccc3-c3cccnc3)c(N3C[C@@H]4[C@@H]([NH3+])[C@@H]4C3)nc2n1\n", - "JSON saved: json_inputs/6oi8.json\n", - "Processing 6mhd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mhd/6mhd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mhd/6mhd_ligand.sdf\n", - "Found 1 chains: {'A': 'SNAMSGESARSLGKGSAPPGPVPEGSIRIYSMRFCPFAERTRLVLKAKGIRHEVININLKNKPEWFFKKNPFGLVPVLENSQGQLIYESAITCEYLDEAYPGKKLLPDDPYEKACQKMILELFSKVPSLVGSFIRSQNKEDYAGLKEEFRKEFTKLEEVLTNKKTTFFGGNSISMIDYLIWPWFERLEAMKLNECVDHTPKLKLWMAAMKEDPTVSALLTSEKDWQGFLELYLQNSPEACDYGL'}\n", - "Ligand SMILES: CCC(=O)N(Cc1cc(C)no1)c1nc(-c2ccccc2)cs1\n", - "JSON saved: json_inputs/6mhd.json\n", - "Processing 6agt, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6agt/6agt_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6agt/6agt_ligand.sdf\n", - "Found 2 chains: {'A': 'DPRLYFENRSKFIQDQKDKGINPYPHKFERTISIPEFIEKYKDLGNGEHLEDTILNITGRIMRVSQKLRFFDLVGDGEKIQVLANYSFHNHEKGNFAECYDKIRRGDIVGIVGFPGKSKKGELSIFPKETILLSACLHMLPMTEIRYRQRYLDLLINESSRHTFVTRTKIINFLRNFLNERGFFEVETPMMNLIAGGANARPFITHHNDLDLDLYLRIATELPLKMLIVGGIDKVYEIGKVFRNEGIDNTHNPEFTSCEFYWAYADYNDLIKWSEDFFSQLVYHLFGTYKISYNKDGPENQPIEIDFTPPYPKVSIVEEIEKVTNTILEQPFDSNETIEKMINIIKEHKIELPNPPTAAKLLDQLASHFIENKYNDKPFFIVEHPQIMSPLAKYHRTKPGLTERLEMFICGKEVLNAYTELNDPFKQKECFKLQQKDREKGDTEAAQLDSAFCTSLEYGLPPTGGLGLGIDRITMFLTNKNSIKDVILFPTMRPA', 'B': 'VDPRLYFENRSKFIQDQKDKGINPYPHKFERTISIPEFIEKYKDLGNGEHLEDTILNITGRIMRVSASGQKLRFFDLVGDGEKIQVLANYSFHNHEKGNFAECYDKIRRGDIVGIVGFPGKSKKGELSIFPKETILLSACLHMLPMKYGLKDTEIRYRQRYLDLLINESSRHTFVTRTKIINFLRNFLNERGFFEVETPMMNLIAGGANARPFITHHNDLDLDLYLRIATELPLKMLIVGGIDKVYEIGKVFRNEGIDNTHNPEFTSCEFYWAYADYNDLIKWSEDFFSQLVYHLFGTYKISYNKDGPENQPIEIDFTPPYPKVSIVEEIEKVTNTILEQPFDSNETIEKMINIIKEHKIELPNPPTAAKLLDQLASHFIENKYNDKPFFIVEHPQIMSPLAKYHRTKPGLTERLEMFICGKEVLNAYTELNDPFKQKECFKLQQKDREKGDTEAAQLDSAFCTSLEYGLPPTGGLGLGIDRITMFLTNKNSIKDVILFPTMRPAN'}\n", - "Ligand SMILES: O=C(NCC1CCCCC1)c1cc(=O)c2ccccc2o1\n", - "JSON saved: json_inputs/6agt.json\n", - "Processing 6i5p, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i5p/6i5p_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i5p/6i5p_ligand.sdf\n", - "Found 1 chains: {'A': 'KVVKFSYMWTINNFSFCREKMGEVIKSSTFSSGANDKLKWCLRVNPKGLDEESKDYLSLYLLLVSCPKSEVRAKFKFSILNAKGEETKAMESQRAYRFVQGKDWGFKKFIRRDFLLDEANGLLPDDKLTLFCEVSVV'}\n", - "Ligand SMILES: CC[C@H]([NH3+])C(=O)N[C@@H](C)C(=O)N[C@@H](CC(=O)O)C(=O)N[C@H](C(=O)N[C@H](C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)O)[C@@H](C)O)[C@@H](C)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6i5p.json\n", - "Processing 6hhr, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhr/6hhr_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhr/6hhr_ligand.sdf\n", - "Found 1 chains: {'A': 'VETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNSSDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVEK'}\n", - "Ligand SMILES: Oc1ccc(-c2n[nH]c(=S)n2-c2ccccc2F)c(O)c1\n", - "JSON saved: json_inputs/6hhr.json\n", - "Processing 6p8z, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6p8z/6p8z_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6p8z/6p8z_ligand.sdf\n", - "Found 1 chains: {'A': 'GMTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETSLLDILDTAGQAMRDQYMRTGEGFLLVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKE'}\n", - "Ligand SMILES: CCC(=O)N1CC(NC(=O)Cn2c(C3CC3)c(C(=O)N3CCc4c(cccc4OC)C3)c3cc(Cl)cc(C)c32)C1\n", - "JSON saved: json_inputs/6p8z.json\n", - "Processing 6c85, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6c85/6c85_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6c85/6c85_ligand.sdf\n", - "Found 1 chains: {'A': 'SKKRCGVLGATGAVGTRFILLLEQSPLLELVAVGASERSAGKKYRDAVRWKQASPMPASVADLTVRRCAPSEFSDCDIIFSGLDPAGDIEMAFLKANFAVFSNAKNYRLDPIVPLVVPLVNAGHIDVIPAQRKHYGLDKGLIVCNSNCAVVGLVIPAKALIQKFGPIESVSMVTMQAVSGAGGVSSMDIFDNIVPFIPGEEGKIATESRKILGNLNPDLAGFSDQQPLQVSVACNRVPVLDGHTVCASLRFVNRPAPTASQVRDALREYKSEVQLLGCPSAPRQAIHVLDDVDRPQPRLDRDTEAGYACSVGRIREDDSGVFDIQFVALSHNTVLGASGSSILNAESAILKGYI'}\n", - "Ligand SMILES: O=C1CCC(=O)CC1\n", - "JSON saved: json_inputs/6c85.json\n", - "Processing 6g5u, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g5u/6g5u_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g5u/6g5u_ligand.sdf\n", - "Found 1 chains: {'B': 'SWGYREHNGPIHWKEFFPIADGDQQSPIEIKTKEVKYDSSLRPLSIKYDPSSAKIISNSGHSFNVDFDDTENKSVLRGGPLTGSYRLRQVHLHWGSADDHGSEHIVDGVSYAAELHVVHWNSDKYPSFVEAAHEPDGLAVLGVFLQIGEPNSQLQKITDTLDSIKEKGKQTRFTNFDLLSLLPPSWDYWTYPGSLTVPPLLESVTWIVLKQPINISSQQLAKFRSLLCTAEGEAAAFLVSNHRPPQPLKGRKVRASFH'}\n", - "Ligand SMILES: CCCCNC(=O)c1cc(S(N)(=O)=O)c(Cl)cc1Cl\n", - "JSON saved: json_inputs/6g5u.json\n", - "Processing 6j06, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6j06/6j06_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6j06/6j06_ligand.sdf\n", - "Found 1 chains: {'A': 'GAYNEWKKALFKPADVILDPKTANPILLVSEDQRSVQRAKEPQDLPDNPERFNWHYCVLGCESFISGRHYWEVEVGDRKEWHIGVCSKNVQRKGWVKMTPENGFWTMGLTDGNKYRTLTEPRTNLKLPKPPKKVGVFLDYETGDISFYNAVDGSHIHTFLDVSFSEALYPVFRILTLEPTALTICPA'}\n", - "Ligand SMILES: Cc1ccc(C/C(=C\\CO[P@@](=O)(O)OP(=O)(O)O)CO)cc1\n", - "JSON saved: json_inputs/6j06.json\n", - "Processing 6qsz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qsz/6qsz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qsz/6qsz_ligand.sdf\n", - "Found 1 chains: {'A': 'SKSSWRQEWLANLKLISVSLVDEFPSELSDSDRQIINEKQLLKDIFANNLKSAISNNFRESDIIILKGEIEDYPSSEIKIYYNELQNKPKARFWSFKTQRFVSNGFDI'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)[C@H](CC(=O)O)NC(=O)[C@@H]([NH3+])[C@@H](C)O)C(=O)N1CCC[C@H]1C(=O)N[C@@H](COP(=O)(O)O)C(=O)N[C@@H](CC(=O)O)C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H](CO)C(=O)O\n", - "JSON saved: json_inputs/6qsz.json\n", - "Processing 6jbb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jbb/6jbb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jbb/6jbb_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGAQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@@](CO)(O[C@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jbb.json\n", - "Processing 6hhp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhp/6hhp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhp/6hhp_ligand.sdf\n", - "Found 2 chains: {'A': 'GAMGSMERASLIQKAKLAEQAERYEDMAAFMKGAVEKGEELSNEERCLLSVAYKNVVGGQRAAWRVLSSIEQKSNEEGSEEKGPEVREYREKVETELQGVCDTVLGLLDSHLIKEAGDAESRVFYLKMKGDYYRYLAEVATGDDKKRIIDSARSAYQEAMDISKKEMPPTNPIRLGLALNFSVFHYEIANSPEEAISLAKTTFDEAMADLHTLSEDSYKDSTLIMQLLRDNLTLWT', 'B': 'GAMGSMERASLIQKAKLAEQAERYEDMAAFMKGAVEKGEELSNEERCLLSVAYKNVVGGQRAAWRVLSSIEQKSNEEGSEEKGPEVREYREKVETELQGVCDTVLGLLDSHLIKEAGDAESRVFYLKMKGDYYRYLAEVATGDDKKRIIDSARSAYQEAMDISKKEMPPTNPIRLGLALNFSVFHYEIANSPEEAISLAKTTFDEAMADLHTLSEDSYKDSTLIMQLLRDNLTLWT'}\n", - "Ligand SMILES: CC(C)[C@H](NC(=O)[C@@H](NC(=O)[C@H](C)NC(=O)[C@@H]1CCCN1C(=O)[C@@H]([NH3+])Cc1ccccc1)[C@@H](C)OP(=O)(O)O)C(=O)O\n", - "JSON saved: json_inputs/6hhp.json\n", - "Processing 6np5, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np5/6np5_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np5/6np5_ligand.sdf\n", - "Found 1 chains: {'A': 'TPWSKSELVRQLRDLGVRSGDMVMPHVSLRAVGPLADGPQTLVDALIEAVGPTGNILAFVSWRDSPYEQTLGHDAPPAAIAQSWPAFDPDHAPAYPGFGAINEFIRTYPGCRRSAHPDASMAAIGPDAAWLVAPHEMGAAYGPRSPIARFLAHAGKILSIGAGPDAVTALHYAEAVARIEGKRRVTYSMPLLREGKRVWVTTSDWDSNGILDEYAAPDGPDAVERIARDYLARTRVAQGPVGGAQSRLIDAADIVSFGIEWLEARHAA'}\n", - "Ligand SMILES: [NH3+]C[C@H]1O[C@H](O[C@H]2[C@H](O)[C@@H](O[C@H]3O[C@H](CO)[C@@H](O)[C@H]([NH3+])[C@H]3O)[C@H]([NH3+])C[C@@H]2[NH3+])[C@H]([NH3+])[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6np5.json\n", - "Processing 6nlj, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nlj/6nlj_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nlj/6nlj_ligand.sdf\n", - "Found 3 chains: {'D': 'MKGDKKVIQHLNKILGNELIAINQYFLHSRMWNDWGLKRLGAHEYHESIDEMKHADKLIERILFLEGLPNLQDLGKLLIGENTQEMLQCDLNLELKATKDLREAIVHCEQVHDYVSRDLLKDILESEEEHIDYLETQLGLIQKVGLENYLQSHMHE', 'H': 'MKGDKKVIQHLNKILGNELIAINQYFLHSRMWNDWGLKRLGAHEYHESIDEMKHADKLIERILFLEGLPNLQDLGKLLIGENTQEMLQCDLNLELKATKDLREAIVHCEQVHDYVSRDLLKDILESEEEHIDYLETQLGLIQKVGLENYLQSHMHE', 'A': 'MKGDKKVIQHLNKILGNELIAINQYFLHSRMWNDWGLKRLGAHEYHESIDEMKHADKLIERILFLEGLPNLQDLGKLLIGENTQEMLQCDLNLELKATKDLREAIVHCEQVHDYVSRDLLKDILESEEEHIDYLETQLGLIQKVGLENYLQSHMHE'}\n", - "Ligand SMILES: O=C1NC(=O)c2c(NCc3cccc(O)c3)cccc21\n", - "JSON saved: json_inputs/6nlj.json\n", - "Processing 6qlp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlp/6qlp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlp/6qlp_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4cc(F)c(F)c(F)c4)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qlp.json\n", - "Processing 6n94, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n94/6n94_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n94/6n94_ligand.sdf\n", - "Found 2 chains: {'A': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH', 'C': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH'}\n", - "Ligand SMILES: C[C@@H](C(=O)NCCNC(=O)CCNC(=O)[C@H](O)C(C)(C)CO[P@@](=O)(O)O[P@](=O)(O)OC[C@H]1O[C@@H](n2cnc3c(N)ncnc32)[C@H](O)[C@@H]1OP(=O)(O)O)[N+](=O)[O-]\n", - "JSON saved: json_inputs/6n94.json\n", - "Processing 6e13, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e13/6e13_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e13/6e13_ligand.sdf\n", - "Found 2 chains: {'A': 'MMYIQVLGSAAAGGFPQWNCNCVNCKGYRDGTLKATARTQSSIALSDDGVHWILCNASPDIRAQLQAFAPMQPARALRDTGINAIVLLDSQIDHTTGLLSLREGCPHQVWCTDMVHQDLTTGFPLFNMLSHWNGGLQWNRIELEGSFVIDACPNLKFTPFPLRSAAPPYSPHRFDPHPGDNLGLMVEDTRTGGKLFYAPGLGQVDEKLLAMMHGADCLLVDGTLWEDDEMQRRGVGTRTGREMGHLAQNGPGGTLEVLDGFPRQRKVLIHINNTNPILDENSPERAEVLRRGVEVAFDGMSIELLEHH', 'B': 'MMYIQVLGSAAAGGFPQWNCNCVNCKGYRDGTLKATARTQSSIALSDDGVHWILCNASPDIRAQLQAFAPMQPARALRDTGINAIVLLDSQIDHTTGLLSLREGCPHQVWCTDMVHQDLTTGFPLFNMLSHWNGGLQWNRIELEGSFVIDACPNLKFTPFPLRSAAPPYSPHRFDPHPGDNLGLMVEDTRTGGKLFYAPGLGQVDEKLLAMMHGADCLLVDGTLWEDDEMQRRGVGTRTGREMGHLAQNGPGGTLEVLDGFPRQRKVLIHINNTNPILDENSPERAEVLRRGVEVAFDGMSIELLEHH'}\n", - "Ligand SMILES: [NH3+][C@H](CSc1cc(C[C@H]([NH3+])C(=O)O)cc(O)c1O)C(=O)O\n", - "JSON saved: json_inputs/6e13.json\n", - "Processing 6qls, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qls/6qls_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qls/6qls_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: OC[C@H]1O[C@@H](S[C@@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@H](O)[C@@H](n2cc(-c3ccccc3)nn2)[C@H]1O\n", - "JSON saved: json_inputs/6qls.json\n", - "Processing 6uil, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uil/6uil_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uil/6uil_ligand.sdf\n", - "Found 1 chains: {'A': 'ASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGYNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKHLAQSVRTVVVPPPGVELTLPKNCQHSISESTAKEVQRIRDKHFDQNILRSLGNIISVLDRMMVCNGCVVVSDLSVSVQCALQHALTEPAERVLVVYVGDGELPVKTNDGKVFLVQICTKETEDKCVNRLTLCGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETRLMRVWGHMTCLIQGLARGRMLTLLQDKDLLELTVSALSGASISPLGPAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: [NH3+]CCC[NH2+]CCCCCC(O)(O)C(F)(F)F\n", - "JSON saved: json_inputs/6uil.json\n", - "Processing 6st3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6st3/6st3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6st3/6st3_ligand.sdf\n", - "Found 1 chains: {'A': 'PALKLALEYIVPCMNKHGICVVDDFLGKETGQQIGDEVRALHDTGKFTDGQLVSQIRGDKITWIEGKEPGCETIGLLMSSMDDLIRHCNGKLGSYKINGRTKAMVACYPGNGTGYVRHVDNPNGDGRCVTCIYYLNKDWDAKVSGGILRIFPEGKAQFADIEPKFDRLLFFWSDRRNPHEVQPAYATRYAITVWYFDADERARAKVKYLT'}\n", - "Ligand SMILES: O=C(NCc1ccc(Oc2ccccc2)cc1)c1cnc(-n2cccn2)[nH]c1=O\n", - "JSON saved: json_inputs/6st3.json\n", - "Processing 6n92, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n92/6n92_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n92/6n92_ligand.sdf\n", - "Found 2 chains: {'A': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH', 'C': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH'}\n", - "Ligand SMILES: C[C@@H](C(=O)SCCNC(=O)CCNC(=O)[C@H](O)C(C)(C)CO[P@@](=O)(O)O[P@@](=O)(O)OC[C@H]1O[C@@H](n2cnc3c(N)ncnc32)[C@H](O)[C@@H]1OP(=O)(O)O)[N+](=O)[O-]\n", - "JSON saved: json_inputs/6n92.json\n", - "Processing 6s56, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s56/6s56_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s56/6s56_ligand.sdf\n", - "Found 1 chains: {'A': 'SMQEEDTFRELRIFLRNVTHRLAIDKRFRVFTKPVDPDEVPDYVTVIKQPMDLSSVISKIDLHKYLTVKDYLRDIDLICSNALEYNPDRDPGDRLIRHRACALRDTAYAIIKEELDEDFEQLCEEIQESR'}\n", - "Ligand SMILES: CN(C)S(=O)(=O)c1cc(NC(=O)CN2C(=O)N[C@@]3(CCCc4ccccc43)C2=O)ccc1Cl\n", - "JSON saved: json_inputs/6s56.json\n", - "Processing 6hzd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hzd/6hzd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hzd/6hzd_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTASGSLVPR'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)CCCC(=O)NCCCC[C@@H](C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)NCc2ccc(/C(N)=N\\[H])cc2)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CCCN/C(N)=N\\[H])NC1=O\n", - "JSON saved: json_inputs/6hzd.json\n", - "Processing 6uhv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uhv/6uhv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uhv/6uhv_ligand.sdf\n", - "Found 1 chains: {'A': 'AASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGYNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKSVRTVVVPPPGVELTLPKNCQHSISESTAKEVQRIRDKHFHDLTDQNILRSLGNIISVLDRMMRSDEVCNGCVVVSDLSVSVQCALQHALTEPAERVLVVYVGDGELPVKTNDGKVFLVQICTKETEDKCVNRLTLCLREGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETARVWGHMTCLIQGLARGRMLTLLQGYDKDLLELTVSALSGASISPLGPLRAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: [NH3+]CCC[NH2+]CCCCCC(=O)NO\n", - "JSON saved: json_inputs/6uhv.json\n", - "Processing 6k05, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k05/6k05_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k05/6k05_ligand.sdf\n", - "Found 1 chains: {'A': 'TNQLQYLHKVVMKALWKHQFAWPFRQPVDAVKLGLPDYHKIIKQPMDMGTIKRRLENNYYWAASECMQDFNTMFTNCYIYNKPTDDIVLMAQTLEKIFLQKVASMPQE'}\n", - "Ligand SMILES: Cc1nnc2n1C1=C(C[C@@H](c3cnn(C)c3)CC1)[C@H](Nc1ccc(Cl)cc1)CC2\n", - "JSON saved: json_inputs/6k05.json\n", - "Processing 6q36, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6q36/6q36_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6q36/6q36_ligand.sdf\n", - "Found 2 chains: {'A': 'PRSVASSKLWMLEFSAFLEQQQDPDTYNKHLFVHIGQSSPSYSDPYLEAVDIRQIYDKFPEKKGGLKDLFERGPSNAFFLVKFWADLNTNGSSFYGVSSQYESPENMIITCSTKVCSFGKQVVEKVETEYARYENGHYSYRIHRSPLCEYMINFIHKLKHLPEKYMMNSVLENFTILQVVTNRDTQETLLCIAYVFEVSASEHGAQHHIYRLVKE', 'B': 'RSVASSKLWMLEFSAFLEQQQDPDTYNKHLFVHIGQSSPSYSDPYLEAVDIRQIYDKFPEKKGGLKDLFERGPSNAFFLVKFWADLNTNGSSFYGVSSQYESPENMIITCSTKVCSFGKQVVEKVETEYARYENGHYSYRIHRSPLCEYMINFIHKLKHLPEKYMMNSVLENFTILQVVTNRDTQETLLCIAYVFEVSASEHGAQHHIYRLVKE'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CC1CNC2CC(Cl)CCC12)NC(=O)[C@@H]1CCCN1C(C)=O)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CC1CCC1)C(=O)N1C[C@H](O)C[C@H]1C(=O)N[C@@H](CC(=O)O)C(=O)N[C@@H](CO)C(=O)N[C@@H](Cc1ccccc1)C(=O)N[C@@H](Cc1cccc2ccccc12)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CCC(=O)O)C(=O)N1CCC[C@H]1C(N)=O\n", - "JSON saved: json_inputs/6q36.json\n", - "Processing 6ic0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ic0/6ic0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ic0/6ic0_ligand.sdf\n", - "Found 1 chains: {'A': 'ELTQSRVQKIWVPVNSPTVIVMVGLPARGKTYISKKLTRYLNWIGVPTKVFNVGEYRREAVKQYSSYNFFRPDNEEAMKVRKQCALAALRDVKSYLAKEGGQIAVFDATNTTRERRHMILHFAKENDFKAFFIESVCDDPTVVASNIMEVKISSPDYKDCNSAEAMDDFMKRISCYEASYQPLDPDKCDRDLSLIKVIDVGRRFLVNRVQDHIQSRIVYYLMNIHVQPRTIYLCRHGENEHNLQGRIGGDSGLSSRGKKFASALSKFVEEQNLKDLRVWTSQLKSTIQTAEALRLPYEQWKALNEIDAGVCEELTYEEIRDTYPEEYALREQDKYYYRYPTGESYQDLVQRLEPVIMELERQENVLVICHQAVLRCLLAYFLDKSAEEMPYLKCPLHTVLKLTPVAYGCRVESIYLNVESVCTHRERS'}\n", - "Ligand SMILES: Cn1ccc2ccc(-c3cc(Nc4cnccc4C(=O)Nc4cncnc4)cc4nccnc34)cc21\n", - "JSON saved: json_inputs/6ic0.json\n", - "Processing 6hhi, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhi/6hhi_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhi/6hhi_ligand.sdf\n", - "Found 1 chains: {'A': 'DVAIVKEGWLHKRGEYIKTWRPRYFLLKNDGTFIGYKERPQDREAPLNNFSVAQCQLMKTERPRPNTFIIRCLQWTTVIERTFHVETPEEREEWTTAIQTVADGLKKRVTMNEFEYLKLLGKGTFGKVILVKEKATGRYYAMKILKKEVIQNSRHPFLTALKYSFQTHDRLCFVMEYANGGELFFHLSRERVFSEDRARFYGAEIVSALDYLHSEKNVVYRDLKLENLMLDKDGHIKITDFGLCKEGIKTMKTFCGTPEYLAPEVLEDNDYGRAVDWWGLGVVMYEMMCGRLPFYNQDHEKLFELILMEEIRFPRTLGPEAKSLLSGLLKKDPKQRLGGGSEDAKEIMQHRFFAGIVWQHVYEKKLSPPFKPQVTSETDTRYFDEEFTA'}\n", - "Ligand SMILES: CCC(=O)Nc1cccc(C(=O)N[C@H]2CC[N@H+](Cc3ccc(-c4nc5c(cc4-c4ccccc4)C(=O)N=CC5)cc3)CC2)c1\n", - "JSON saved: json_inputs/6hhi.json\n", - "Processing 6e3m, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3m/6e3m_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3m/6e3m_ligand.sdf\n", - "Found 1 chains: {'A': 'MAMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGLKHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSER'}\n", - "Ligand SMILES: O=C(O)c1cccc(-c2cc(O)c(O)c(C(=O)O)n2)c1\n", - "JSON saved: json_inputs/6e3m.json\n", - "Processing 6qtx, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtx/6qtx_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtx/6qtx_ligand.sdf\n", - "Found 1 chains: {'A': 'TRYSRLRVIAEIRNIVSSIEFDRDDELFATAGVSRCIKVFDFSSVVNEQCPIVEMSTRSKLSCLSWNKHEKNHIASSDYEGIVTVWDVTTRQSLMEYEEHEKRAWSVDFSRTEPSMLVSGSDDCKVKVWTRQEASVINIDMKANICVKYNPGSSNYIAVGSADHHIHYYDLRNISQPLHVFSGHKKAVSYVKFLSNNELASASTDSTLRLWDVKDNLPVRTFRGHTNEKNFVGLTVNSEYLACGSETNEVYVYHKEITRPVTSHRFEEEAGSYFISAVCWKSDSPTMLTANSQGTIKVLVLAA'}\n", - "Ligand SMILES: CC(C)[C@H](NC(=O)CNC(=O)[C@H](Cc1ccccc1)NC(=O)C[NH3+])C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)N[C@@H](CO)C(=O)N[C@@H](Cc1ccccc1)C(=O)O)C(C)C\n", - "JSON saved: json_inputs/6qtx.json\n", - "Processing 6jse, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jse/6jse_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jse/6jse_ligand.sdf\n", - "Found 1 chains: {'A': 'RGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYNI'}\n", - "Ligand SMILES: [H]/N=C1\\N[C@](C)(c2cc(NC(=O)c3cnc(OCF)cn3)ccc2F)[C@@H](c2ccccc2)CS1\n", - "JSON saved: json_inputs/6jse.json\n", - "Processing 5zjy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zjy/5zjy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zjy/5zjy_ligand.sdf\n", - "Found 1 chains: {'A': 'HYIKHPLQNRWALWFFKNDKSKTWQANLRLISKFDTVEDFWALYNHIQLSSNLMPGCDYSLFKDGIEPMWEDEKNKRGGRWLITLNKQQRRSDLDRFWLETLLCLIGESFDDYSDDVCGAVVNVRAKGDKIAIWTTECENREAVTHIGRVYKERLGLPPKIVIGYQSHADTATTKNRFVV'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCCC[NH3+])NC(=O)[C@H](CCCC[NH3+])NC(C)=O)C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](CO)C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)N[C@]1(C)CCC/C=C\\CCC[C@](C)(C(=O)N[C@@H](Cc2ccccc2)C(N)=O)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CCC(N)=O)NC1=O\n", - "JSON saved: json_inputs/5zjy.json\n", - "Processing 6o3y, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o3y/6o3y_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o3y/6o3y_ligand.sdf\n", - "Found 1 chains: {'A': 'MDFQNFVATLESFKDLKSGISGSRIKKLTTYALDHIDIESKIISLIIDYSRLCPDSHKLGSLYIIDSIGRAYLDETRSNSNSSSNKPGTCAHAINTLGEVIQELLSDAIAKSNQDHKEKIRMLLDIWDRSGLFQKSYLNAIRSKCFA'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)[C@H](CC(=O)O)NC(=O)[C@H](Cc1ccc(O)cc1)NC(=O)[C@@H]1CCCN1C(=O)[C@H](CC(=O)O)NC(=O)[C@@H]([NH3+])CCC(=O)O)C(=O)N[C@@H](CC(N)=O)C(=O)O\n", - "JSON saved: json_inputs/6o3y.json\n", - "Processing 6rpg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rpg/6rpg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rpg/6rpg_ligand.sdf\n", - "Found 2 chains: {'A': 'AFTVTVPKDLYVVEYGSNMTIECKFPVEKQLDLAALIVYWEMEDKNIIQFVHGEEDLKVQHSSYRQRARLLKDQLSLGNAALQITDVKLQDAGVYRCMISYGGADYKRITVKVNAPY', 'B': 'AFTVTVPKDLYVVEYGSNMTIECKFPVEKQLDLAALIVYWEMEDKNIIQFVHGEEDLKVQHSSYRQRARLLKDQLSLGNAALQITDVKLQDAGVYRCMISYGGADYKRITVKVNAPY'}\n", - "Ligand SMILES: CC(=O)NCC[NH2+]Cc1cc(C)c(OCc2cccc(-c3cccc(COc4cc(OCc5cncc(C#N)c5)c(C[NH2+]CCNC(C)=O)cc4C)c3C)c2C)cc1OCc1cncc(C#N)c1\n", - "JSON saved: json_inputs/6rpg.json\n", - "Processing 6rr0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rr0/6rr0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rr0/6rr0_ligand.sdf\n", - "Found 1 chains: {'A': 'LSKSSWRQEWLANLKLISVSLVDEFPSELSDSDRQIINEKMQLLKDIFANNLKSAISNNFRESDIIILKGEIEDYPMSSEIKIYYNELQNKPDAKKARFWSFMKTQRFVSNMGFDI'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)[C@H](CCC(=O)O)NC(=O)[C@@H](NC(=O)[C@H](CO)NC(=O)[C@@H]([NH3+])CC(C)C)[C@@H](C)O)C(=O)N[C@@H](CO)C(=O)N[C@H](C(=O)N[C@@H](CCC(=O)O)C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)O)[C@@H](C)OP(=O)(O)O\n", - "JSON saved: json_inputs/6rr0.json\n", - "Processing 6gzy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gzy/6gzy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gzy/6gzy_ligand.sdf\n", - "Found 1 chains: {'A': 'QGLAMYLQENGIDCPKCKFSYALARGGCMHFHCTQCRHQFCSGCYNAFYAKNKCPEPNCRVKKSLHGHHPRDCLFYLRDWTALRLQKLLQDNNVMFNTEPPGCRVIEQRDEACGKETPAGYAGLCQAHYKEYLVSLINAHSLDPATLYEVEELETATERYLHVRPQPLAGEDPPAYQARLLQKLTEEVPLGQSIPRRRK'}\n", - "Ligand SMILES: COC(=O)CCCNC(=O)c1cc2c([nH]c1=O)CCC2\n", - "JSON saved: json_inputs/6gzy.json\n", - "Processing 6qlt, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlt/6qlt_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlt/6qlt_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4ccccc4F)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qlt.json\n", - "Processing 6ufo, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ufo/6ufo_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ufo/6ufo_ligand.sdf\n", - "Found 1 chains: {'A': 'AASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGYNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKHLAQSETDIVWPEPLKRMPASVRTVVVPPPGVELTLPKNCQHSDISESTAKEVQRIRDKHFHDLTDQNILRSLGNIISVLDRMMRSDEVCNGCVVVSDLSVSVQCALQHALTEPERVLVVYVGDGELPVKTNDGKVFLVQICTKETEDKCVNRLTLCLRGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETARLMRVWGHMTCLIQGLARGRMLTLLQGYDKDLLELTVSALSGASISPLGPLRAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: COCC(O)(O)CCCCC[NH2+]CCC[NH3+]\n", - "JSON saved: json_inputs/6ufo.json\n", - "Processing 6o0h, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o0h/6o0h_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o0h/6o0h_ligand.sdf\n", - "Found 1 chains: {'A': 'SAKAISEQTGKELLYKFICTTSAIQNRFKYARVTPDTDWARLLQDHPWLLSQNLVVKPDQLIKRRGKLGLVGVNLTLDGVKSWLKPRLGQEATVGKATGFLKNFLIEPFVPHSQAEEFYVCIYATREGDYVLFHHEGGVDVGDVDAKAQKLLVGVDEKLNPEDIKKHLLVHAPEDKKEILASFISGLFNFYEDLYFTYLEINPLVVTKDGVYVLDLAAKVDATADYICKVKWGDIEFPPPFGREAYPEEAYIADLDAKSGASLKLTLLNPKGRIWTMVAGGGASVVYSDTICDLGGVNELANYGEYSGAPSEQQTYDYAKTILSLMTREKHPDGKILIIGGSIANFTNVAATFKGIVRAIRDYQGPLKEHEVTIFVRRGGPNYQEGLRVMGEVGKTTGIPIHVFGTETHMTAIVGMALGHRPIPGKSTTLFSRHTKAIVWGMQTRAVQGMLDFDYVCSRDEPSVAAMVYPFTGDHKQKFYWGHKEILIPVFKNMADAMRKHPEVDVLINFASLRSAYDSTMETMNYAQIRTIAIIAEGIPEALTRKLIKKADQKGVTIIGPATVGGIKPGCFKIGNTGGMLDNILASKLYRPGSVAYVSRSGGMSNELNNIISRTTDGVYEGVAIGGDRYPGSTFMDHVLRYQDTPGVKMIVVLGEIGGTEEYKICRGIKEGRLTKPIVCWCIGTCATMFQASETAVAKNQALKEAGVFVPRSFDELGEIIQSVYEDLVANGVIVPAQEVPPPTVPMDYSWARELGLIRKPASFMTSICDERGQELIYAGMPITEVFKEEMGIGGVLGLLWFQKRLPKYSCQFIEMCLMVTADHGPAVSGAHNTIICARAGKDLVSSLTSGLLTIGDRFGGALDAAAKMFSKAFDSGIIPMEFVNKMKKEGKLIMGIGHRVKSINNPDMRVQILKDYVRQHFPATPLLDYALEVEKITTSKKPNLILNVDGLIGVAFVDMLRNCGSFTREEADEYIDIGALNGIFVLGRSMGFIGHYLDQKRLKQGLYRHPWDDISYVLPEHM'}\n", - "Ligand SMILES: COC(=O)c1cc(Cl)c(O)c(S(=O)(=O)Nc2cc(-c3ccccc3)c(F)cc2F)c1\n", - "JSON saved: json_inputs/6o0h.json\n", - "Processing 6o3x, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o3x/6o3x_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o3x/6o3x_ligand.sdf\n", - "Found 1 chains: {'A': 'HMDFQNFVATLESFKDLKSGISGSRIKKLTTYALDHIDIESKIISLIIDYSRLCPDSHKLGSLYIIDSIGRAYLDETRSNSNSSSNKPGTCAHAINTLGEVIQELLSDAIAKSNQDHKEKIRMLLDIWDRSGLFQKSYLNAIRSKCFA'}\n", - "Ligand SMILES: C[C@@H](O)[C@H](NC(=O)[C@H](Cc1ccc(O)cc1)NC(=O)[C@H](CC(=O)O)NC(=O)[C@@H]([NH3+])CC(=O)O)C(=O)N1CCC[C@H]1C(=O)N[C@@H](CO)C(=O)O\n", - "JSON saved: json_inputs/6o3x.json\n", - "Processing 5zjz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zjz/5zjz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zjz/5zjz_ligand.sdf\n", - "Found 1 chains: {'A': 'EHYIKHPLQNRWALWFFKNDKSKTWQANLRLISKFDTVEDFWALYNHIQLSSNLMPGCDYSLFKDGIEPMWEDEKNKRGGRWLITLNKQQRRSDLDRFWLETLLCLIGESFDDYSDDVCGAVVNVRAKGDKIAIWTTECENREAVTHIGRVYKERLGLPPKIVIGYQSHADTATKTKNRFVV'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](CCCC[NH3+])NC(=O)[C@H](CCCC[NH3+])NC(C)=O)C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](CO)C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)N[C@@]1(C)CCC/C=C\\CCC[C@@](C)(C(=O)N[C@@H](Cc2ccccc2)C(=O)N[C@@H](CC2CNC3CCCCC23)C(N)=O)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CC(C)C)NC(=O)[C@H](CCC(N)=O)NC1=O\n", - "JSON saved: json_inputs/5zjz.json\n", - "Processing 6i8t, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i8t/6i8t_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i8t/6i8t_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLAKPIQDLIKMIFDVESMKKAMVEFEIDLQKMPLGKLSKRQIQSAYSILNEVQQAVSDGGSESQILDLSNRFYTLIPHDFGMKKPPLLSNLEYIQAKVQMLDNLLDIEVAYSLLRGGNEDGDKDPIDINYEKLRTDIKVVDKDSEEAKIIKQYVKNTHAATHNAYDLKVVEIFRIEREGESQRYKPFKQLHNRQLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQADPIGLILLGEVALGNMYELKNASHITKLPKGKHSVKGLGKTAPDPTATTTLDGVEVPLGNGISTGINDTCLLYNEYIVYDVAQVNLKYLLKLKFNY'}\n", - "Ligand SMILES: C[C@@H]1c2cccc(C(N)=O)c2C(=O)N1[C@H]1CC[N@H+](C2CCCCC2)CC1\n", - "JSON saved: json_inputs/6i8t.json\n", - "Processing 6ooy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ooy/6ooy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ooy/6ooy_ligand.sdf\n", - "Found 3 chains: {'A': 'TPSDKPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPSHVLLTHTISRIAVSYQTKVNLLSAIKSPCKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL', 'B': 'PSDKPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPSHVLLTHTISRIAVSYQTKVNLLSAIKSPCAKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL', 'C': 'KPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCHVLLTHTISRIAVSYQTKVNLLSAIKSPCKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL'}\n", - "Ligand SMILES: Cc1ccc(C)c(Cn2c(CO)nc3ccccc32)c1\n", - "JSON saved: json_inputs/6ooy.json\n", - "Processing 6oiq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oiq/6oiq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oiq/6oiq_ligand.sdf\n", - "Found 1 chains: {'A': 'KYVDKIHIGNYEIDAWYFSPFPEDYGKQPKLWLCEYCLKYMKYEKSYRFHLGQCQWRQPPGKEIYRKSNISVHEVDGKDHKIYCQNLCLLAKLFLDHTLYFDVEPFVFYILTEVDRQGAHIVGYFSKEKESPDGNNVSCIMILPPYQRRGYGRFLIAFSYELSKLESTVGSPEKPLSDLGKLSYRSYWSWVLLENLRDFRGTLSIKDLSQMTSITQNDIISTLQSLNMVKYWKGQHVICVTPKLVEEHLKSAQYKKPPITVDSVCLKWAPP'}\n", - "Ligand SMILES: O=C(NNS(=O)(=O)c1ccccc1)c1cccc(-c2ccccc2)c1F\n", - "JSON saved: json_inputs/6oiq.json\n", - "Processing 6od6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6od6/6od6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6od6/6od6_ligand.sdf\n", - "Found 1 chains: {'A': 'TTGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVETSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1/N[C@](C)(c2cc(NC(=O)c3ccc(C#N)cn3)ccc2F)Cn2cccc21\n", - "JSON saved: json_inputs/6od6.json\n", - "Processing 6nrh, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrh/6nrh_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrh/6nrh_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLPKPVQDLIKMIFGDPIDVNYEKLKTDIKVVDRDSEEAEIIRKYVKNTHATTHNAYDLEVIDIFKIEREGECQRYKPFKQLHNRRLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQGDPIGLILLGEVALGNMYELKHASHISKLPKGKHSVKGLGKTTPDPSANISLDGVDVPLGTGISSGVNDTSLLYNEYIVYDIAQVNLKYLLKLKFNFK'}\n", - "Ligand SMILES: NC(=O)c1cccc2c1O[C@H](Cc1ccc(C(=O)N3CCN(c4ncccn4)CC3)cc1)C2=O\n", - "JSON saved: json_inputs/6nrh.json\n", - "Processing 6qra, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qra/6qra_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qra/6qra_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: NC1CC(c2ccc3ccn(Cc4ccc(C[NH+]5CCCCC5)cc4)c3c2)NN1\n", - "JSON saved: json_inputs/6qra.json\n", - "Processing 6hhh, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhh/6hhh_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hhh/6hhh_ligand.sdf\n", - "Found 1 chains: {'A': 'SDVAIVKEGWLHKRGEYIKTWRPRYFLLKNDGTFIGYKERPQDVEAPLNNFSVAQCQLMKTERPRPNTFIIRCLQWTTVIERTFHVETPEEREEWTTAIQTVADGLKKRVTMNEFEYLKLLGKGTFGKVILVKEKATGRYYAMKILKKEVRVLQNSRHPFLTALKYSFQTHDRLCFVMEYANGGELFFHLSRERVFSEDRARFYGAEIVSALDYLHSEKNVVYRDLKLENLMLDKDGHIKITDFGLCKEGGTPEYLAPEVLEDNDYGRAVDWWGLGVVMYEMMCGRLPFYNQDHEKLFELILMEEIRFPRTLGPEAKSLLSGLLKKDPKQRLGGGSEDAKEIMQHRFFAGIVWQHVYEKKLSPPFKPQVTSETDTRYFD'}\n", - "Ligand SMILES: CCC(=O)Nc1ccc(N2CC[NH+](Cc3ccc(-c4nc5c(cc4-c4ccccc4)C(=O)N=CC5)cc3)CC2)cc1\n", - "JSON saved: json_inputs/6hhh.json\n", - "Processing 6m7h, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6m7h/6m7h_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6m7h/6m7h_ligand.sdf\n", - "Found 1 chains: {'A': 'LTEEQIAEFKEAFSLFDKDGDGTITTKELGTVRSLGQNPTEAELQDINEVDADGNGTIDFPEFLTARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVTNLGEKLTDEEVDEIREADIDGDGQVNYEEFVQTA'}\n", - "Ligand SMILES: COc1ccc(S(=O)(=O)N(CCO)c2ccccc2C[N@@H+](C)CCCc2ccc(Cl)cc2)cc1\n", - "JSON saved: json_inputs/6m7h.json\n", - "Processing 6ufn, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ufn/6ufn_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ufn/6ufn_ligand.sdf\n", - "Found 1 chains: {'A': 'AASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGYNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKHLAQSETNIVWPEPLKRMPASVRTVVVPPPGVELTLPKNCQHSDISESTAKEVQRIRDKHFHDLTDQNILRSLGNIISVLDRMMRSDEVCNGCVVVSDLSVSVQCALQHALTEERVLVVYVGDGELPVKTNDGKVFLVQICTKETEDKCVNRLTLCLREGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETARLMRVWGHMTCLIQGLARGRMLTLLQGYDKDLLELTVSALSGASISPLGPRAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: CC(O)(O)CCCCC[NH2+]CCC[NH3+]\n", - "JSON saved: json_inputs/6ufn.json\n", - "Processing 6qr0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr0/6qr0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr0/6qr0_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSPT'}\n", - "Ligand SMILES: N#CC1C(N)NNC1c1ccc2ccn(Cc3ccncc3)c2c1\n", - "JSON saved: json_inputs/6qr0.json\n", - "Processing 6o5u, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o5u/6o5u_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o5u/6o5u_ligand.sdf\n", - "Found 1 chains: {'A': 'TPWSKSELVRQLRDLGVRSGDMVMPHVSLRAVGPLADGPQTLVDALIEAVGPTGNILAFVSWRDSPYEQTLGHDAPPAAIAQSWPAFDPDHAPAYPGFGAINEFIRTYPGCRRSAHPDASMAAIGPDAAWLVAPHEMGAAYGPRSPIARFLAHAGKILSIGAGPDAVTALHYAEAVARIEGKRRVTYSMPLLREGKRVWVTTSDWDSNGILDEYAAPDGPDAVERIARDYLARTRVAQGPVGGAQSRLIDAADIVSFGIEWLEARHAA'}\n", - "Ligand SMILES: [NH3+]C[C@H]1O[C@H](O[C@H]2[C@H](O)[C@@H](O[C@H]3O[C@H](CO)[C@@H](O)[C@H]([NH3+])[C@H]3O)[C@H]([NH3+])C[C@@H]2[NH3+])[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6o5u.json\n", - "Processing 6h14, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h14/6h14_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h14/6h14_ligand.sdf\n", - "Found 1 chains: {'B': 'SELLVNTKSGKVMGTRVPVLSSHISAFLGIPFAEPPVGNMRFRRPEPKKPWSGVWNASTYPNNCQQYVDEQFPGFSGSEMWNPNREMSEDCLYLNIWVPSPRPKSTTVMVWIYGGGFYSGSSTLDVYNGKYLAYTEEVVLVSLSYRVGAFGFLALHGSQEAPGNVGLLDQRMALQWVHDNIQFFGGDPKTVTIFGESAGGASVGMHILSPGSRDLFRRAILQSGSPNCPWASVSVAEGRRRAVELGRNLNCNLNSDEELIHCLREKKPQELIDVEWNVLPFDSIFRFSFVPVIDGEFFPTSLESMLNSGNFKKTQILLGVNKDEGSFFLLYGAPGFSKDSESKISREDFMSGVKLSVPHANDLGLDAVTLQYTDWMDDNNGIKNRDGLDDIVGDHNVICPLMHFVNKYTKFGNGTYLYFFNHRASNLVWPEWMGVIHGYEIEFVFGLPLVKELNYTAEEEALSRRIMHYWATFAKTGNPNEPHSSKWPLFTTKEQKFIDLNTEPMKVHQRLRVQMCVFWNQFLPKLLNAT'}\n", - "Ligand SMILES: O=C(Nc1cc(-c2cn(CCNc3c4c(nc5ccccc35)CCCC4)nn2)ccn1)Nc1cccc2c1[C@@H]1CCCCN1C2=O\n", - "JSON saved: json_inputs/6h14.json\n", - "Processing 6jwa, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jwa/6jwa_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jwa/6jwa_ligand.sdf\n", - "Found 1 chains: {'A': 'SGPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVV'}\n", - "Ligand SMILES: Nc1ncnc2c1c(I)cn2[C@@H]1O[C@H](CO)[C@@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6jwa.json\n", - "Processing 6ny0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ny0/6ny0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ny0/6ny0_ligand.sdf\n", - "Found 4 chains: {'A': 'DATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERIN', 'B': 'DATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERIN', 'C': 'DATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERIN', 'D': 'DATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERIN'}\n", - "Ligand SMILES: COCC(O)COC\n", - "JSON saved: json_inputs/6ny0.json\n", - "Processing 6jan, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jan/6jan_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jan/6jan_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSAPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O[C@H]2[C@H](O)[C@@H](O)[C@@H](O)O[C@@H]2CO)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jan.json\n", - "Processing 6ftf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ftf/6ftf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ftf/6ftf_ligand.sdf\n", - "Found 1 chains: {'B': 'GIDPEKAKLYQAPYFEKSEDEMNLITKLLTHNVLFSFLNTKDIKVVAGAMQRATFKHDDCIMEAGQTTCNKLYIIQSGHADIIKEGQKVYLKTEGTAVGELELMYDTPVVATVKVCTDELIAWVLDRDTYRNLVMGTAIRRRETYIQFLANVPFLGGLDSYEKLQLADALSSEEFSPGEYIIHYGEEGEWLYIIMEGTVEVIGRDADGEPTKVCEFTQGDHIGELEFLNNHRTVADVVATTHVITAKLNRRHFEMCLGPVIDVLKRCADDPKYEYYQNVLKTGAAQPSYVD'}\n", - "Ligand SMILES: N#Cc1cn([C@@H]2O[C@H](CO)[C@@H](O)[C@H]2O)c2nc[nH]c(=O)c12\n", - "JSON saved: json_inputs/6ftf.json\n", - "Processing 6oxw, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxw/6oxw_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxw/6oxw_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CCC(CC)CN(C[C@@H](O)[C@H](CC1CCCCC1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)[C@H]1CC[C@@H]([C@@H](C)O)CC1\n", - "JSON saved: json_inputs/6oxw.json\n", - "Processing 6jon, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jon/6jon_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jon/6jon_ligand.sdf\n", - "Found 1 chains: {'A': 'HMIMEIPAIKALSRYAQWVIWKKERDTKIPYNPNNGKKASSTDPLAWGDIDEAQAGLVRYGANGLGFVLTKSDPFVFIDLDHVLDENKRVKCEWARQLLKEIKSYTEISPSGDGLHVVVSGKLPDYIKHKTKFDDGSALEVYESGRYMTITGEVFDGRDDIKELDLSILGEFAEHKILDDEAIIDLMKRKGQWPDAPKDGDDWSSLDMSFANRLAFWCGKDIERMDRIFRQSPLMRQKWDRPTAGSTYGRITLKKACDFVDSVYDPALRNESDCPFEPYN'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@H]1C[C@H](O)[C@@H](CO[P@@](=O)(O)O[P@](=O)(O)OP(=O)(O)O)O1\n", - "JSON saved: json_inputs/6jon.json\n", - "Processing 6cf7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cf7/6cf7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cf7/6cf7_ligand.sdf\n", - "Found 3 chains: {'A': 'DTICIGYHANNSTDTVDTVLEKNVTVTHSVNLLEDSHNGKLCRLKGIAPLQLGNCSVAGWILGNPECELLISRESWSYIVEKPNPENGTCYPGHFADYEELREQLSSVSSFERFEIFPKESSWPNHTTTGVSASCSHNGESSFYKNLLWLTGKNGLYPNLSKSYANNKEKEVLVLWGVHHPPNIGDQRALYHKENAYVSVVSSHYSRKFTPEIAKRPKVRDQEGRINYYWTLLEPGDTIIFEANGNLIAPRYAFALSRGFGSGIINSNAPMDECDAKCQTPQGAINSSLPFQNVHPVTIGECPKYVRSAKLRMVTGLRNIPS', 'B': 'GLFGAIAGFIEGGWTGMVDGWYGYHHQNEQGSGYAADQKSTQNAINGITNKVNSVIEKMNTQFTAVGKEFNKLERRMENLNKKVDDGFIDIWTYNAELLVLLENERTLDFHDSNVKNLYEKVKSQLKNNAKEIGNGCFEFYHKCNDECMESVKNGTYDYPKYSEESKLNRE', 'E': 'DTICIGYHANNSTDTVDTVLEKNVTVTHSVNLLEDSHNGKLCRLKGIAPLQLGNCSVAGWILGNPECELLISRESWSYIVEKPNPENGTCYPGHFADYEELREQLSSVSSFERFEIFPKESSWPNHTTTGVSASCSHNGESSFYKNLLWLTGKNGLYPNLSKSYANNKEKEVLVLWGVHHPPNIGDQRALYHKENAYVSVVSSHYSRKFTPEIAKRPKVRDQEGRINYYWTLLEPGDTIIFEANGNLIAPRYAFALSRGFGSGIINSNAPMDECDAKCQTPQGAINSSLPFQNVHPVTIGECPKYVRSAKLRMVTGLRNIPS'}\n", - "Ligand SMILES: CC(=O)Nc1ccc2oc(-c3ccnc(C(=O)N4CC[NH+]([C@H](c5ccccc5)c5nnn(C)n5)CC4)c3)nc2c1\n", - "JSON saved: json_inputs/6cf7.json\n", - "Processing 6rtn, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rtn/6rtn_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rtn/6rtn_ligand.sdf\n", - "Found 2 chains: {'A': 'GSITENTSWNKEFSAEAVNGVFVLCKSSSKSCATNDLARASKEYLPASTFIPNAIIGLETGVIKNEHQVFKWDGKPRAMKQWERDLTLRGAIQVSAVPVFQQIAREVGEVRMQKYLKKFSYGNQNISGGIDKFWLEGQLRISAVNQVEFLESLYLNKLSASKENQLIVKEALVTEAAPEYLVHSKTGFSGVGTESNPGVAWWVGWVEKETEVYFFAFNMDIDNESKLPLRKSIPTKIMESEGII', 'B': 'MGSITENTSWNKEFSAEAVNGVFVLCKSSSKSCATNDLARASKEYLPASTFIPNAIIGLETGVIKNEHQVFKWDGKPRAMKQWERDLTLRGAIQVSAVPVFQQIAREVGEVRMQKYLKKFSYGNQNISGGIDKFWLEGQLRISAVNQVEFLESLYLNKLSASKENQLIVKEALVTEAAPEYLVHSKTGFSGVGTESNPGVAWWVGWVEKETEVYFFAFNMDIDNESKLPLRKSIPTKIMESEGII'}\n", - "Ligand SMILES: no ligand\n", - "JSON saved: json_inputs/6rtn.json\n", - "Processing 6jsz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsz/6jsz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jsz/6jsz_ligand.sdf\n", - "Found 1 chains: {'A': 'ANFLAMVDNLQGGRGYYLEMLIGTPPQKLQILVDTGSSNFAVAGTPHSYIDTYFDTERSSTYRSKGFDVTVKYTQGSWTGFVGEDLVTIPKGFNTSFLVNIATIFESENFFLPGIKWNGILGLAYATLAKPSSSLETFFDSLVTQANIPNVFSMQMCGAGGGSLVLGGIEPSLYKGDIWYTPIKEEWYYQIEILKLEIGGQSLNLDCREYNADKAIVDSGTTLLRLPQKVFDAVVEAVARASLIPEFSDGFWTGSQLACWWSYFPKISIYLRDENSSRSFRITILPQLYIQPMYECYRFGISPSTNALVIGATVMEGFYVIFDRAQKRVGFAASPCAEIAGAAVSEISGPFSTEDVASNCVPA'}\n", - "Ligand SMILES: [H]/N=C1/N[C@](C)(c2cc(NC(=O)c3cnc(OCF)cn3)ccc2F)C2(CCS(=O)(=O)CC2)CS1\n", - "JSON saved: json_inputs/6jsz.json\n", - "Processing 6o9c, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o9c/6o9c_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o9c/6o9c_ligand.sdf\n", - "Found 2 chains: {'A': 'SGSHSMRYFFTSVSRPGRGEPRFIAVGYVDDTQFVRFDSDAASQRMEPRAPWIEQEGPEYWDQETRNVKAQSQTDRVDLGTLRGYYNQSEAGSHTIQIMYGCDVGSDGRFLRGYRQDAYDGKDYIALNEDLRSWTAADMAAQITKRKWEAAHEAEQLRAYLDGTCVEWLRRYLENGKETLQRTDPPKTHMTHHPISDHEATLRCWALGFYPAEITLTWQRDGEDQTQDTELVETRPAGDGTFQKWAAVVVPSGEEQRYTCHVQHEGLPKPLTLRWELSS', 'B': 'AIQRTPKIQVYSRHPAENGKSNFLNCYVSGFHPSDIEVDLLKNGERIEKVEHSDLSFSKDWSFYLLYYTEFTPTEKDEYACRVNHVTLSQPKIVKWDRDM'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)[C@H](Cc1ccccc1)NC(=O)[C@@H]1CCCN1C(=O)[C@H](C)NC(=O)[C@@H](NC(=O)[C@@H]([NH3+])[C@@H](C)O)[C@@H](C)O)C(=O)N[C@@H](CO)C(=O)NCC(=O)N[C@@H](CCCC[NH3+])C(=O)O\n", - "JSON saved: json_inputs/6o9c.json\n", - "Processing 6mo8, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo8/6mo8_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo8/6mo8_ligand.sdf\n", - "Found 1 chains: {'A': 'RVTNQLQYLHKVVMKALWKHQFAWPFRQPVDAVKLGLPDYHKIIKQPMDMGTIKRRLENNYYWAASECMQDFNTMFTNCYIYNKPTDDIVLMAQTLEKIFLQKVASMPQEEQEL'}\n", - "Ligand SMILES: Cc1noc(C)c1-c1cc(-c2c(C)noc2C)c2cccnc2c1\n", - "JSON saved: json_inputs/6mo8.json\n", - "Processing 6qln, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qln/6qln_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qln/6qln_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4cccc(F)c4)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qln.json\n", - "Processing 6qqu, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqu/6qqu_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqu/6qqu_ligand.sdf\n", - "Found 2 chains: {'A': 'GSMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGNASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: no ligand\n", - "JSON saved: json_inputs/6qqu.json\n", - "Processing 6i66, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i66/6i66_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i66/6i66_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEA'}\n", - "Ligand SMILES: CC[C@@H](C)c1ccc(O)cc1\n", - "JSON saved: json_inputs/6i66.json\n", - "Processing 6mja, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mja/6mja_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mja/6mja_ligand.sdf\n", - "Found 4 chains: {'C': 'TQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNFACANAFNNSIIPEDTFFPS', 'D': 'EAAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'KNYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPSRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'IQKTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRD'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCc2ccc(C)cc2)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6mja.json\n", - "Processing 6gwe, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gwe/6gwe_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gwe/6gwe_ligand.sdf\n", - "Found 1 chains: {'A': 'IVEGSDAEIGMSPWQVMLFRKSPQELLCGASLISDRWVLTAAHCLLYPPWDKNFTENDLLVRIGKHSRTRYERNIEKISMLEKIYIHPRYNWRENLDRDIALMKLKKPVAFSDYIHPVCLPDRETAASLLQAGYKGRVTGWGNLKEGQPSVLQVVNLPIVERPVCKDSTRIRITDNMFCAGYKPDEGKRGDACEGDSGGPFVMKSPFNNRWYQMGIVSWGEGCDRDGKYGFYTHVFRLKKWIQKVIDQF'}\n", - "Ligand SMILES: no ligand\n", - "JSON saved: json_inputs/6gwe.json\n", - "Processing 6d3z, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d3z/6d3z_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d3z/6d3z_ligand.sdf\n", - "Found 1 chains: {'A': 'FDCGKPQVEPKKCPGVVGGCVAHPHSWPWQVSLRTRFGMHFCGGTLISPEWVLTAAHCLEKSPRPSSYKVILGAHQEVNLEPHVQEIEVSRLFLEPTRKDIALLKLSSPAVITDKVIPACLPSPNYVVADRTECFITGWGETQGTFGAGLLKEAQLPVIENKVCNRYEFLNGRVQSTELCAGHLAGGTDSCQGDAGGPLVCFEKDKYILQGVTSWGLGCARPNKPGVYVRVSRFVTWIEGVMRNN'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@@H]2ON2C(=O)[C@H](CC(N)=O)NC(=O)[C@@H]2CCCN2C(=O)[C@H](Cc2ccccc2)NC(=O)[C@@H]2CSSC[C@H](NC1=O)C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CO)C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H]([C@@H](C)CC)C(=O)N2\n", - "JSON saved: json_inputs/6d3z.json\n", - "Processing 6oxr, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxr/6oxr_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxr/6oxr_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC(C)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@H](C)O)cc1\n", - "JSON saved: json_inputs/6oxr.json\n", - "Processing 6r4k, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6r4k/6r4k_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6r4k/6r4k_ligand.sdf\n", - "Found 2 chains: {'A': 'MTIFQFPQDFMWGTATAAYQIEGAYQEDGRGLSIWDTFAHTPGKVFNGDNGNVACDSYHRYEEDIRLMKELGIRTYRFSVSWPRIFPNGDGEVNQKGLDYYHRVVDLLNDNGIEPFCTLYHWDLPQALQDAGGWGNRRTIQAFVQFAETMFREFHGKIQHWLTFNEPWCIAFLSNMLGVHAPGLTNLQTAIDVGHHLLVAHGLSVRRFRELGTSGQIGIAPNVSWAVPYSTSEEDKAACARTISLHSDWFLQPIYQGSYPQFLVDWFAEQGATVPIQDGDMDIIGEPIDMIGINYYSMSVNRFNPEAGFLQSEEINMGLPVTDIGWPVESRGLYEVLHYLQKYGNIDIYITENGACINDEVVNGKVQDDRRISYMQQHLVQVHRAIHDGLHVKGYMAWSLLDNFEWAEGYSMRFGIIHVDFRTQVRTPKESYYWYRKVVGNNWLETRR', 'B': 'MTIFQFPQDFMWGTATAAYQIEGAYQEDGRGLSIWDTFAHTPGKVFNGDNGNVACDSYHRYEEDIRLMKELGIRTYRFSVSWPRIFPNGDGEVNQKGLDYYHRVVDLLNDNGIEPFCTLYHWDLPQALQDAGGWGNRRTIQAFVQFAETMFREFHGKIQHWLTFNEPWCIAFLSNMLGVHAPGLTNLQTAIDVGHHLLVAHGLSVRRFRELGTSGQIGIAPNVSWAVPYSTSEEDKAACARTISLHSDWFLQPIYQGSYPQFLVDWFAEQGATVPIQDGDMDIIGEPIDMIGINYYSMSVNRFNPEAGFLQSEEINMGLPVTDIGWPVESRGLYEVLHYLQKYGNIDIYITENGACINDEVVNGKVQDDRRISYMQQHLVQVHRAIHDGLHVKGYMAWSLLDNFEWAEGYSMRFGIIHVDFRTQVRTPKESYYWYRKVVGNNWLETRR'}\n", - "Ligand SMILES: [H]/N=N\\NCCOCCOc1ccc(C2=NN=[N+](C[C@@H]3[NH2+]C[C@@H](O)[C@H]3O)C2)cc1\n", - "JSON saved: json_inputs/6r4k.json\n", - "Processing 6hle, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hle/6hle_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hle/6hle_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTASGSLVPR'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@@H]([NH3+])CCCCNC(=O)CC[N@H+]2CC[N@@H+](CCC(=O)NCCCC[C@@H](C(=O)NCc3ccc(/C(N)=N\\[H])cc3)NC(=O)[C@H](C(C)(C)C)NC1=O)CC2\n", - "JSON saved: json_inputs/6hle.json\n", - "Processing 6h9v, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h9v/6h9v_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h9v/6h9v_ligand.sdf\n", - "Found 2 chains: {'A': 'TGSKPFTVPILTVEEMTNSRFPIPLEKLFTGPSGAFVVQPQNGRCTTDGVLLGTTQLSPVNICTFRGDVTHIAGSRNYTMNLASLNWNNYDPTEEIPAPLGTPDFVGKIQGLLTQTTKGDGSTRGHKATVYTGSAPFTPKLGSVQFSTDTEDFETHQNTKFTPVGVIQDGSTTHRNEPQQWVLPSYSGRNVHNVHLAPAVAPTFPGEQLLFFRSTMPGCSGYPNMDLDCLLPQEWVQHFYQEAAPAQSDVALLRFVNPDTGRVLFECKLHKSGYVTVAHTGQHDLVIPPNGYFRFDSWVNQFYTLAPM', 'B': 'SKPFTVPILTVEEMTNSRFPIPLEKLFTGPSGAFVVQPQNGRCTTDGVLLGTTQLSPVNICTFRGDVTHIAGSRNYTMNLASLNWNNYDPTEEIPAPLGTPDFVGKIQGLLTQTTKGDGSTRGHKATVYTGSAPFTPKLGSVQFSTDTDFETHQNTKFTPVGVIQDTTHRNEPQQWVLPSYSGRNVHNVHLAPAVAPTFPGEQLLFFRSTMPGCSGYPNMDLDCLLPQEWVQHFYQEAAPAQSDVALLRFVNPDTGRVLFECKLHKSGYVTVAHTGQHDLVIPPNGYFRFDSWVNQFYTLAPM'}\n", - "Ligand SMILES: CO[C@@H]1O[C@@H](C)[C@@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6h9v.json\n", - "Processing 6hou, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hou/6hou_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hou/6hou_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKD'}\n", - "Ligand SMILES: COc1cc(C=O)ccc1O\n", - "JSON saved: json_inputs/6hou.json\n", - "Processing 6nv9, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nv9/6nv9_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nv9/6nv9_ligand.sdf\n", - "Found 1 chains: {'A': 'SFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: CCC[C@H](O)[C@H]([NH2+]C[C@@H]1Cc2cccc(c2)CCCCc2cc(cc(N(CCC)S(C)(=O)=O)c2)C(=O)N1)C(=O)NCC(C)C\n", - "JSON saved: json_inputs/6nv9.json\n", - "Processing 6py0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6py0/6py0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6py0/6py0_ligand.sdf\n", - "Found 3 chains: {'A': 'RWVQFMKEAGQGSRDMWRAYSDMKKANWKNSDKYFHARGNYDAARRGPGGAWAAKVISDAREAVQKFTGHGDSRADQFANEWGRSGKDPNHFRPAGLPKRY', 'B': 'RWVQFMKEAGQGSRDMWRAYSDMKKANWKNSDKYFHARGNYDAARRGPGGAWAAKVISDAREAVQKFTGHDSRADQFANEWGRSGKDPNHFRPAGLPKRY', 'C': 'RWVQFMKEAGQGSRDMWRAYSDMKKANWKNSDKYFHARGNYDAARRGPGGAWAAKVISDAREAVQKFTDSRADQFANEWGRSGKDPNHFRPAGLPKRY'}\n", - "Ligand SMILES: CC(/C=C/[C@@H]1[C@@H](C)CCCC1(C)C)=C\\C=C\\C(C)=C\\CO\n", - "JSON saved: json_inputs/6py0.json\n", - "Processing 6qlq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlq/6qlq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlq/6qlq_ligand.sdf\n", - "Found 1 chains: {'B': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4ccc(F)cc4)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qlq.json\n", - "Processing 6nv7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nv7/6nv7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nv7/6nv7_ligand.sdf\n", - "Found 1 chains: {'A': 'SFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: CCCN(c1cc2cc(c1)C(=O)N[C@H](C[NH2+][C@@H](C(=O)NCC(C)C)[C@H](C)O)Cc1cccc(c1)CCCC2)S(C)(=O)=O\n", - "JSON saved: json_inputs/6nv7.json\n", - "Processing 6n4b, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n4b/6n4b_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n4b/6n4b_ligand.sdf\n", - "Found 1 chains: {'R': 'MVLNPSQQLAIAVLSLTLGTFTVLENLLVLCVILHSRSLRCRPSYHFIGSLAVADLLGSVIFVYSFIDFHVFHRKDSRNVFLFKLGGVTASFTASVGSLFLTAIDRYISIHRPLAYKRIVTRPKAVVAFCLMWTIAIVIAVLPLLGWNCCSDIFPHIDETYLMFWIGVTSVLLLFIVYAYMYILWKAHSHAVRMIQRGTARMDIRLAKTLVLILVVLIICWGPLLAIMVYDVFGKMNKLIKTVFAFCSMLCLLNSTVNPIIYALRSKDLRHAFRSM'}\n", - "Ligand SMILES: COC(=O)[C@@H](NC(=O)c1nn(Cc2ccc(F)cc2)c2ccccc12)C(C)(C)C\n", - "JSON saved: json_inputs/6n4b.json\n", - "Processing 6jaq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jaq/6jaq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jaq/6jaq_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSAPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jaq.json\n", - "Processing 6i8m, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i8m/6i8m_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i8m/6i8m_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLAKPIQDLIKMIFDVESMKKAMVEFEIDLQKMPLGKLSKRQIQSAYSILNEVQQAVSDGGSESQILDLSNRFYTLIPHDFGMKKPPLLSNLEYIQAKVQMLDNLLDIEVAYSLLRGGNEDGDKDPIDINYEKLRTDIKVVDKDSEEAKIIKQYVKNTHAATHNAYDLKVVEIFRIEREGESQRYKPFKQLHNRQLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQADPIGLILLGEVALGNMYELKNASHITKLPKGKHSVKGLGKTAPDPTATTTLDGVEVPLGNGISTGINDTCLLYNEYIVYDVAQVNLKYLLKLKFNY'}\n", - "Ligand SMILES: C[C@H]1c2cccc(C(N)=O)c2C(=O)N1[C@H]1CC[N@H+](C2CCCCC2)CC1\n", - "JSON saved: json_inputs/6i8m.json\n", - "Processing 6dz0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dz0/6dz0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dz0/6dz0_ligand.sdf\n", - "Found 2 chains: {'A': 'TTAVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGRQHTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLL', 'C': 'TTAVKIGIIGGTGLDDPEILEGRTEKYVDTPFGKPSDALILGKIKNVDCVLLARHGRQHTIMPSKVNYQANIWALKEEGCTHVIVTTACGSLREEIQPGDIVIIDQFIDRTTMRPQSFYDGSHSCARGVCHIPMAEPFCPKTREVLIETAKKLGLRCHSKGTMVTIEGPRFSSRAESFMFRTWGADVINMTTVPEVVLAKEAGICYASIAMATDYDCWKEHEEAVSVDRVLKTLKENANKAKSLLLTTIPQIGSTEWSETLHNLKNMAQFSVLL'}\n", - "Ligand SMILES: C#CCCCSC[C@H]1C[N@@H+](CC2CNC3C(N)NCNC23)C[C@@H]1O\n", - "JSON saved: json_inputs/6dz0.json\n", - "Processing 6oxs, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxs/6oxs_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxs/6oxs_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC(C)CN(C[C@@H](O)[C@H](CC1CCCCC1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@@H](C)O)cc1\n", - "JSON saved: json_inputs/6oxs.json\n", - "Processing 6k2n, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k2n/6k2n_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k2n/6k2n_ligand.sdf\n", - "Found 3 chains: {'A': 'ILDGPYQPTTFTPPIDYWILINSNTNGVVYESTNNSDFWTAVVAIEPHVNPVDRQYTVFGENKQFNVRNDSDKWKFLEMFRSSSQNEFYNRRTLTSDTKLVGILKYGGRIWTFHGETPRATTDSSNTANLNDISIIIHSEFYIIPRSQESKCNEYINNGL', 'B': 'ILDGPYQPTTFTPPIDYWILINSNTNGVVYESTNNSDFWTAVVAIEPHVNPVDRQYTVFGENKQFNVRNDSDKWKFLEMFRSSSQNEFYNRRTLTSDTKLVGILKYGGRIWTFHGETPRATTDSSNTANLNDISIIIHSEFYIIPRSQESKCNEYINNGL', 'F': 'ILDGPYQPTTFTPPIDYWILINSNTNGVVYESTNNSDFWTAVVAIEPHVNPVDRQYTVFGENKQFNVRNDSDKWKFLEMFRSSSQNEFYNRRTLTSDTKLVGILKYGGRIWTFHGETPRATTDSSNTANLNDISIIIHSEFYIIPRSQESKCNEYINNGL'}\n", - "Ligand SMILES: CC(=O)N[C@@H]1[C@@H](O[C@@H]2O[C@H](CO)[C@H](O)[C@H](O)[C@H]2O)[C@@H](O)[C@@H](CO[C@@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2NC(C)=O)O[C@@H]1O\n", - "JSON saved: json_inputs/6k2n.json\n", - "Processing 6cjj, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjj/6cjj_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjj/6cjj_ligand.sdf\n", - "Found 1 chains: {'A': 'QGETHEFTAEISQLMSLIINTVYSNKEIFLRELISNASDALDKIRYQALSDPSQLESEPELFIRIIPQKDQKVLEIRDSGIGMTKADLVNNLGTIAKSGTKSFMEALSAGADVSMIGQFGVGFYSLFLVADHVQVISKHNDDEQYVWESNAGGKFTVTLDETNERLGRGTMLRLFLKEDQLEYLEEKRIKEVVKKHSEFVAYPIQLVVTKEVEK'}\n", - "Ligand SMILES: Nc1ncnc2c1ncn2[C@@H]1O[C@H](CO[P@@](=O)(O)OP(=O)(O)O)[C@@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6cjj.json\n", - "Processing 6ffg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ffg/6ffg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ffg/6ffg_ligand.sdf\n", - "Found 1 chains: {'A': 'MGKLSEQLKHCNGILKELLSKKHAAYAWPFYKPVDASALGLHDYHDIIKHPMDLSTVKRKMENRDYRDAQEFAADVRLMFSNCYKYNPPDHDVVAMARKLQDVFEFRYAKMPD'}\n", - "Ligand SMILES: CC(=O)N1c2ccc(C3=CC[NH2+]CC3)cc2N(Cc2ccccc2CO)C[C@@H]1C1C=C1\n", - "JSON saved: json_inputs/6ffg.json\n", - "Processing 6a73, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a73/6a73_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a73/6a73_ligand.sdf\n", - "Found 1 chains: {'A': 'ENQYYNSKALKEDDPKAALSSFQKVLELEGEKGEWGFKALKQMIKINFKLTNFPEMMNRYKQLLTYIRSAVTRNYSEKSINSILDYISTSKQMDLLQEFYETTLEALKDAKNDRLWFKTNTKLGKLYLERNIFEMLRIDEGLRLKIYKDTEGYYTIGIGHLLTKSPSLNAAKSELDKAIGRNTNGVITKDEAEKLFNQDVDAAVRGILRNAKLKPVYDSLDAVRRAALINMVFQMGETGVAGFTNSLRMLQQKRWDEAAVNLAKSRWYNQTPNRAKRVITTFRTGTWDAY'}\n", - "Ligand SMILES: O=P(O)(O)O[C@H]1[C@H](OP(=O)(O)O)[C@@H](OP(=O)(O)O)[C@H](OP(=O)(O)O)[C@@H](OP(=O)(O)O)[C@H]1OP(=O)(O)O\n", - "JSON saved: json_inputs/6a73.json\n", - "Processing 6qqt, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqt/6qqt_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqt/6qqt_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVRQAGLVDVAVHDLRRWTHDVSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: COc1ccc(Cn2ccc3ccc(C4CC(N)NN4)cc32)cc1\n", - "JSON saved: json_inputs/6qqt.json\n", - "Processing 6a1c, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a1c/6a1c_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a1c/6a1c_ligand.sdf\n", - "Found 1 chains: {'A': 'SGPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKDQARMG'}\n", - "Ligand SMILES: CO[C@H]1C=C(/C=N/n2c(SC)nnc2-c2ccccc2)C(Br)=CC1=O\n", - "JSON saved: json_inputs/6a1c.json\n", - "Processing 6oxu, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxu/6oxu_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxu/6oxu_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC[C@H](C)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@@H](C)O)cc1\n", - "JSON saved: json_inputs/6oxu.json\n", - "Processing 6qre, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qre/6qre_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qre/6qre_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVRGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVMASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: COc1cccc(COC(=O)C2CNNC2)c1\n", - "JSON saved: json_inputs/6qre.json\n", - "Processing 6qtw, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtw/6qtw_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtw/6qtw_ligand.sdf\n", - "Found 1 chains: {'A': 'RYSRLRVIAEIRNIVSSIEFDRDDELFATAGVSRCIKVFDFSSVVNEPQCPIVEMSTRSKLSCLSWNKHEKNHIASSDYEGIVTVWDVTTRQSLMEYEEHEKRAWSVDFSRTEPSMLVSGSDDCKVKVWTRQEASVINIDMKANICVKYNPGSSNYIAVGSADHHIHYYDLRNISQPLHVFSGHKKAVSYVKFLSNNELASASTDSTLRLWDVKDNLPVRTFRGHTNEKNFVGLTVNSEYLACGSETNEVYVYHKEITRPVTSHRFSYFISAVCWKSDSPTMLTANSQGTIKVLVLAA'}\n", - "Ligand SMILES: CSCC[C@H](NC(=O)[C@H](CCC(N)=O)NC(=O)[C@H](CC(=O)O)NC(=O)[C@@H]([NH3+])CCC(=O)O)C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)N[C@@H](CO)C(=O)O)C(C)C\n", - "JSON saved: json_inputs/6qtw.json\n", - "Processing 6np4, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np4/6np4_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np4/6np4_ligand.sdf\n", - "Found 1 chains: {'A': 'TPWSKSELVRQLRDLGVRSGDMVMPHVSLRAVGPLADGPQTLVDALIEAVGPTGNILAFVSWRDSPYEQTLGHDAPPAAIAQSWPAFDPDHAPAYPGFGAINEFIRTYPGCRRSAHPDASMAAIGPDAAWLVAPHEMGAAYGPRSPIARFLAHAGKILSIGAGPDAVTALHYAEAVARIEGKRRVTYSMPLLREGKRVWVTTSDWDSNGILDEYAAPDGPDAVERIARDYLARTRVAQGPVGGAQSRLIDAADIVSFGIEWLEARHAA'}\n", - "Ligand SMILES: [NH3+]C[C@H]1O[C@H](O[C@H]2[C@H](O)[C@@H](O[C@H]3O[C@H](CO)[C@@H](O)[C@H]([NH3+])[C@H]3O)[C@H]([NH3+])C[C@@H]2[NH3+])[C@H]([NH3+])C[C@@H]1O\n", - "JSON saved: json_inputs/6np4.json\n", - "Processing 6hv2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hv2/6hv2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hv2/6hv2_ligand.sdf\n", - "Found 1 chains: {'A': 'EYNVRTLKWSKMNLTYRIVNYTPDMTHSEVEKAFKKAFKVWSDVTPLNFTRLHDGIADIMISFGIKEHGDFYPFDGPSGLLAHAFPPGPNYGGDAHFDDDETWTSSSKGYNLFLVAAHEFGHSLGLDHSKDPGALMFPIYTYTGKSHFMLPDDDVQGIQSLYGPGD'}\n", - "Ligand SMILES: CC[C@H](C)[C@H]([NH3+])C(=O)N[C@@H](CCSC)C(=O)N[C@H](C(=O)N[C@@H](CO)C(=O)N[C@@H](Cc1ccccc1)C(=O)O)[C@@H](C)CC\n", - "JSON saved: json_inputs/6hv2.json\n", - "Processing 6n55, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n55/6n55_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n55/6n55_ligand.sdf\n", - "Found 1 chains: {'F': 'GEPFLIGVSGGTASGKSSVCAKIVQLLGQNDYRQKQVVILSQDSFYRVLTSEQKAKALKGQFNFDHPDAFDNELILKTLKEITEGKTVQIPVYDFVSHSRKEETVTVYPADVVLFEGILAFYSQEVRDLFQMKLFVDTDADTRLSRRVLRDISERGRDLEQILSQYITFVKPAFEEFCLPTKKYADVIIPRGADNLVAINLIVQHIQDILNG'}\n", - "Ligand SMILES: [N-]=[N+]=N[C@@H]1[C@H](O)[C@@H](CO)O[C@H]1n1ccc(=O)[nH]c1=O\n", - "JSON saved: json_inputs/6n55.json\n", - "Processing 6e3o, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3o/6e3o_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3o/6e3o_ligand.sdf\n", - "Found 1 chains: {'A': 'AMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGLKHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSE'}\n", - "Ligand SMILES: CCc1ccccc1C1=CC(=O)C(O)C(C(=O)O)=N1\n", - "JSON saved: json_inputs/6e3o.json\n", - "Processing 6kjd, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6kjd/6kjd_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6kjd/6kjd_ligand.sdf\n", - "Found 1 chains: {'B': 'HMDTTFQAAIDTGKINGAVVCATDAQGHFVYNKATGERTLLSGEKQPQQLDDVLYLAAATKLITTIAALQCVEDGLLSLDGDLSSIAPELAAKYVLTGFTDDESPLDDPPARPITLKMLLTHSSGTSYHFLDPSIAKWRAQYANPENEKPRLVEEMFTYPLSFQPGTGWMYGPGLDWAGRVVERVTGGTLMEFMQKRIFDPLGITDSQFYPVTREDLRARLVDLNPSDPGALGSAVIGGGGEMNLRGRGAFGGHGLFLTGLDFVKILRSLLANDGMLLKPAAVDNMFQQHLGPEAAASHRAALASPLGPFFRVGTDPETKVGYGLGGLLTLEDVDGWYGERTLTWGGGLTLTWFIDRKNNLCGVGAIQAVLPVDGDLMADLKQTFRHDIYRKYSAWKGQQ'}\n", - "Ligand SMILES: CC[C@H](C)C(=O)O[C@H]1C[C@@H](C)C=C2C=C[C@H](C)[C@H](CC[C@@H](O)C[C@@H](O)CC(=O)O)[C@H]21\n", - "JSON saved: json_inputs/6kjd.json\n", - "Processing 6sfc, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6sfc/6sfc_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6sfc/6sfc_ligand.sdf\n", - "Found 1 chains: {'B': 'SFKCVNSLKEDHNQPLFGVQFNWHSKEGDPLVFATVGSNRVTLYECHSQGEIRLLQSYVDADADENFYTCAWTYDSNTSHPLLAVAGSRGIIRIINPITMQCIKHYVGHGNAINELKFHPRDPNLLLSVSKDHALRLWNIQTDTLVAIFGGVEGHRDEVLSADYDLLGEKIMSCGMDHSLKLWRINSKRMMNAIKESYDRPFISQKIHFPDFSTRDIHRNYVDCVRWLGDLILSKSCENAIVCWKPGKMEDDIDKIKPSESNVTILGRFDYSQCDIWYMRFSMDFWQKMLALGNQVGKLYVWDLECTTLTHHKCGAAIRQTSFSRDSSILIAVCDDASIWRWDR'}\n", - "Ligand SMILES: Cc1nc(NCc2cccc3c2OCO3)sc1-c1ccn(C)n1\n", - "JSON saved: json_inputs/6sfc.json\n", - "Processing 6qi7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qi7/6qi7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qi7/6qi7_ligand.sdf\n", - "Found 1 chains: {'A': 'VTQTMKGLDIQKVAGTWYSLAMAASDISLLDAQSAPYRVYVEELKPTGDLEILLQKWENGECAQKKIIAEKTKIPAVFKIDENKVLVLDTDYKKYLLFCMENSLACQCLVRTPEVDDEALEKFDKALKALPMHIRLSFNPTQLEEQCHI'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCC(=O)O\n", - "JSON saved: json_inputs/6qi7.json\n", - "Processing 6hzc, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hzc/6hzc_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hzc/6hzc_ligand.sdf\n", - "Found 1 chains: {'A': 'VYQEPTDPKFPQQWYLSGVTQRDLNVKAAWAQGYTGHGIVVSILDDGIEKNHPDLAGNYDPGASFDVNDQDPDPQPRYTQMNDNRHGTRCAGEVAAVANNGVCGVGVAYNARIGGVRMLDGEVTDAVEARSLGLNPNHIHIYSASWGPEDDGKTVDGPARLAEEAFFRGVSQGRGGLGSIFVWASGNGGREHDSCNCDGYTNSIYTLSISSATQFGNVPWYSEACSSTLATTYSSGNQNEKQIVTTDLRQKCTESHTGTSASAPLAAGIIALTLEANKNLTWRDMQHLVVQTSKPAHLNANDWATNGVGRKVSHSYGYGLLDAGAMVALAQNWTTVAPQRKCIIDILTEPKDIGKRLEVRKTVTACLGEPNHITRLEHAQARLTLSYNRRGDLAIHLVSPMGTRSTLLAARPHDYSADGFNDWAFMTTHSWDEDPSGEWVLEIENTSEANNYGTLTKFTLVLYGTASGSLVPR'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@@H]([NH3+])CCCCNC(=O)Cc2ccc(cc2)CNC(=O)CCCC(=O)NCCCC[C@@H](C(=O)NCc2ccc(/C(N)=N\\[H])cc2)NC(=O)[C@H](C(C)(C)C)NC1=O\n", - "JSON saved: json_inputs/6hzc.json\n", - "Processing 6k04, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k04/6k04_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k04/6k04_ligand.sdf\n", - "Found 1 chains: {'A': 'SEQLKHCNGILKELLSKKHAAYAWPFYKPVDASALGLHDYHDIIKHPMDLSTVKRKMENRDYRDAQEFAADVRLMFSNCYKYNPPDHDVVAMARKLQDVFEFRYAKMP'}\n", - "Ligand SMILES: Cc1nnc2n1-c1ccc(-c3cnn(C)c3)cc1[C@H](Nc1ccc(Cl)cc1)CC2\n", - "JSON saved: json_inputs/6k04.json\n", - "Processing 6op0, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6op0/6op0_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6op0/6op0_ligand.sdf\n", - "Found 3 chains: {'A': 'TPSDKPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPSTHVLLTHTISRIAVSYQTKVNLLSAIKSPCQRETPAKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL', 'B': 'TPSDKPVAHVVANPQAEGQLQWLNRRANALLANGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPHVLLTHTISRIAVSYQTKVNLLSAIKSPCEAKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDFAESGQVYFGIIAL', 'C': 'KPVAHVVANEGQLQWLNGVELRDNQLVVPSEGLYLIYSQVLFKGQGCPSTHVLLTHTISRIAVQTKVNLLSAIKSPCKPWYEPIYLGGVFQLEKGDRLSAEINRPDYLDGQVYFGIIAL'}\n", - "Ligand SMILES: Cc1ccc(C)c(Cn2c([C@H](O)c3ccncc3)nc3ccc(-c4cnn(C)c4)cc32)c1\n", - "JSON saved: json_inputs/6op0.json\n", - "Processing 6q38, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6q38/6q38_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6q38/6q38_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPSEYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVK'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@@H](NC(=O)CNC(C)=O)Cn2cc(nn2)-c2cc(C(=O)O)cc(c2)-c2cn(nn2)C[C@]2(C(=O)NCC(=O)NCC(N)=O)ON2C(=O)[C@H](CC2CNCN2)NC(=O)[C@H]([C@@H](C)CC)NC(=O)[C@H](CCCC[NH3+])NC(=O)[C@H](Cc2ccccc2)NC(=O)CNC(=O)[C@H](Cc2ccc(O)cc2)NC(=O)[C@H](CC(C)C)NC1=O\n", - "JSON saved: json_inputs/6q38.json\n", - "Processing 6n8x, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n8x/6n8x_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n8x/6n8x_ligand.sdf\n", - "Found 1 chains: {'A': 'EVETFAFQAEIAQLMSLIINTFYSNKEIFLRELISNSSDALDKIRYESLTDPSKLDSGKELHINLIPNKQDRTLTIVDTGIGMTKADLINNLGTIAKSGTKAFMEALQAGADISMIGQFGVGFYSAYLVAEKVTVITKHNDDEQYAWESSAGGSFTVRTDTGEPMGRGTKVILHLKEDQTEYLEERRIKEIVKKHSQFIGYPITLFVEKE'}\n", - "Ligand SMILES: CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21\n", - "JSON saved: json_inputs/6n8x.json\n", - "Processing 6np3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np3/6np3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6np3/6np3_ligand.sdf\n", - "Found 1 chains: {'A': 'TPWSKSELVRQLRDLGVRSGDMVMPHVSLRAVGPLADGPQTLVDALIEAVGPTGNILAFVSWRDSPYEQTLGHDAPPAAIAQSWPAFDPDHAPAYPGFGAINEFIRTYPGCRRSAHPDASMAAIGPDAAWLVAPHEMGAAYGPRSPIARFLAHAGKILSIGAGPDAVTALHYAEAVARIEGKRRVTYSMPLLREGKRVWVTTSDWDSNGILDEYAAPDGPDAVERIARDYLARTRVAQGPVGGAQSRLIDAADIVSFGIEWLEARHAA'}\n", - "Ligand SMILES: C[NH2+][C@@H]1[C@@H](O)[C@@H](O[C@@H]2[C@@H](O)[C@H](O[C@H]3O[C@H](C[NH3+])CC[C@H]3[NH3+])[C@@H]([NH3+])C[C@H]2[NH3+])OC[C@]1(C)O\n", - "JSON saved: json_inputs/6np3.json\n", - "Processing 6uvv, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uvv/6uvv_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uvv/6uvv_ligand.sdf\n", - "Found 1 chains: {'A': 'PGRRGSFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAGFPLNQSEVLASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVEDVATSQDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGYN'}\n", - "Ligand SMILES: [H]/N=C1/N[C@@]2([C@@H]3C[C@H]3C(=O)NCCCC)COC[C@H]2CS1\n", - "JSON saved: json_inputs/6uvv.json\n", - "Processing 6pgo, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pgo/6pgo_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pgo/6pgo_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETSLLDILDTAGRDQYMRTGEGFLLVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK'}\n", - "Ligand SMILES: CCC(=O)N1CCN(c2nnc(-c3ccccc3)c3cc(-c4c(O)cccc4F)c(Cl)cc23)CC1\n", - "JSON saved: json_inputs/6pgo.json\n", - "Processing 6jbe, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jbe/6jbe_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jbe/6jbe_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGAQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jbe.json\n", - "Processing 6i75, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i75/6i75_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i75/6i75_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4c(F)c(F)c(O)c(F)c4F)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6i75.json\n", - "Processing 6qqq, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqq/6qqq_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qqq/6qqq_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: COc1cc(COC(=O)C2CNNC2)cc(-c2cccnc2)c1\n", - "JSON saved: json_inputs/6qqq.json\n", - "Processing 6i62, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i62/6i62_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i62/6i62_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEAK'}\n", - "Ligand SMILES: Oc1ccc(C(c2ccc(O)cc2)C(Cl)(Cl)Cl)cc1\n", - "JSON saved: json_inputs/6i62.json\n", - "Processing 6j9y, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6j9y/6j9y_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6j9y/6j9y_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O[C@H]2[C@H](O)[C@@H](O)[C@@H](O)O[C@@H]2CO)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6j9y.json\n", - "Processing 6g29, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g29/6g29_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g29/6g29_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYIDKQ'}\n", - "Ligand SMILES: CC1=C(c2ccncc2)NN(C2CC[NH2+]CC2)C(=O)C1\n", - "JSON saved: json_inputs/6g29.json\n", - "Processing 6h7d, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h7d/6h7d_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h7d/6h7d_ligand.sdf\n", - "Found 1 chains: {'A': 'VTAFVIMTCIVAAMGGLLFGYDLGISGGVTSMEEFLTKFFPQVESQMKKAKHDTAYCKFDNQMLQLFTSSLYLAALVASFMASVITRKHGRKVSMFIGGLAFLIGALFNAFAVNVSMLIIGRLLLGVGVGFANQSTPVYLSEMAPAKIRGALNIGFQMAITIGILVANLINYGTSKMAQHGWRVSLGLAAVPAVVMVIGSFILPDTPNSMLERGKNEEAKQMLKKIRGADNVDHEFQDLIDAVEAAKKVENPWKNIMESKYRPALIFCSAIPFFQQITGINVIMFYAPVLFKTLGFGDDAALMSAVITGVVNMLSTFVSIYAVDRYGRRLLFLEGGIQMFICQLLVGSFIGARFGTSGTGTLTPATADWILAFICVYVAGFAWSWGPLGWLVPSEICPLEIRPAGQAINVSVNMFFTFLIGQFFLTMLCHMKFGLFYFFASMVAIMTVFIYFLLPETKGVPIEEMGRVWKQHWFWKKYIPEDAIIGG'}\n", - "Ligand SMILES: OC[C@H]1O[C@@H](O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6h7d.json\n", - "Processing 6mo9, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo9/6mo9_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo9/6mo9_ligand.sdf\n", - "Found 1 chains: {'A': 'RVTNQLQYLHKVVMKALWKHQFAWPFRQPVDAVKLGLPDYHKIIKQPMDMGTIKRRLENNYYWAASECMQDFNTMFTNCYIYNKPTDDIVLMAQTLEKIFLQKVASMPQEEQEL'}\n", - "Ligand SMILES: Cc1noc(C)c1-c1cc(S(=O)(=O)NC2CCCC2)c2cccnc2c1\n", - "JSON saved: json_inputs/6mo9.json\n", - "Processing 6jao, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jao/6jao_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jao/6jao_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSAPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](OC[C@H]2O[C@@](O)(CO)[C@@H](O)[C@@H]2O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jao.json\n", - "Processing 6jmf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jmf/6jmf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jmf/6jmf_ligand.sdf\n", - "Found 1 chains: {'A': 'EVQKPLHEQLWYHGAIPRAEVAELLVHSGDFLVRESQGKQEYVLSVLWDGLPRHFIIQSLDNLYRLEGEGFPSIPLLIDHLLSTQQPLTKKSGVVLHRAVPKDKWVLNHEDLVLGEQIGRGNFGEVFSGRLRADNTLVAVKSCRETLPPDLKAKFLQEARILKQYSHPNIVRLIGVCTQKQPIYIVMELVQGGDFLTFLRTEGARLRVKTLLQMVGDAAAGMEYLESKCCIHRDLAARNCLVTEKNVLKISDFGMSREEADGVYAASGGLRQVPVKWTAPEALNYGRYSSESDVWSFGILLWETFSLGASPYPNLSNQQTREFVEKGGRLPCPELCPDAVFRLMEQCWAYEPGQRPSFSTIYQELQSIRKRH'}\n", - "Ligand SMILES: Cc1cccc(Nc2nc(N[C@@H]3CCCC[C@@H]3[NH3+])c(C#N)cc2C(N)=O)c1\n", - "JSON saved: json_inputs/6jmf.json\n", - "Processing 6hmy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hmy/6hmy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hmy/6hmy_ligand.sdf\n", - "Found 3 chains: {'A': 'TPQNITDLCAEYHNTQIHTLNDKIFSYTESLAGKREMAIITFKNGATFQVEVPGSQHIDSQKKAIERMKDTLRIAYLTEAKVEKLCVWNNKTPHAIAAISMAN', 'B': 'TPQNITDLCAEYHNTQIHTLNDKIFSYTESLAGKREMAIITFKNGATFQVEVPGSQHIDSQKKAIERMKDTLRIAYLTEAKVEKLCVWNNKTPHAIAAISMAN', 'E': 'TPQNITDLCAEYHNTQIHTLNDKIFSYTESLAGKREMAIITFKNGATFQVEVPGSQHIDSQKKAIERMKDTLRIAYLTEAKVEKLCVWNNKTPHAIAAISMAN'}\n", - "Ligand SMILES: CC(=O)N[C@H]1[C@H](O[C@@H]2[C@H](O[C@]3(C(=O)O)C[C@H](O)[C@@H](NC(C)=O)[C@H]([C@H](O)[C@H](O)CO)O3)[C@@H](O)[C@H](O[C@H]3[C@H](O)[C@@H](O)[C@H](O)O[C@@H]3CO)O[C@@H]2CO)O[C@H](CO)[C@H](O)[C@@H]1O[C@@H]1O[C@H](CO)[C@H](O)[C@H](O)[C@H]1O[C@@H]1O[C@@H](C)[C@@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6hmy.json\n", - "Processing 6qfe, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qfe/6qfe_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qfe/6qfe_ligand.sdf\n", - "Found 1 chains: {'A': 'IINGSDCDMHTQPWQAALLLRPNQLYCGAVLVHPQWLLTAAHCRKKVFRVRLGHYSLSPVYESGQQMFQGVKSIPHPGYSHPGHSNDLMLIKLNRRIRPTKDVRPINVSSHCPSAGTKCLVSGWGTTKSPQVHFPKVLQCLNISVLSQKRCEDAYPRQIDDTMFCAGDKAGRDSCQGDSGGPVVCNGSLQGLVSWGDYPCARPNRPGVYTNLCKFTKWIQETIQANS'}\n", - "Ligand SMILES: [H]/N=C(\\N)c1ccc(NCC2NCC(c3ccccc3)N2)cc1OCc1cccnc1\n", - "JSON saved: json_inputs/6qfe.json\n", - "Processing 5zml, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zml/5zml_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/5zml/5zml_ligand.sdf\n", - "Found 1 chains: {'A': 'EVANPEHYIKHPLQNRWALWFFKNDKSKTWQANLRLISKFDTVEDFWALYNHIQLSSNLMPGCDYSLFKDGIEPMWEDEKNKRGGRWLITLNKQQRRSDLDRFWLETLLCLIGESFDDYSDDVCGAVVNVRAKGDKIAIWTTECENREAVTHIGRVYKERLGLPPKIVIGYQSHADTATKSGSTTKNRFVV'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](Cc1ccccc1)NC(=O)[C@]1(C)CCC/C=C\\CCC[C@](C)(NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CO)NC(=O)[C@H](Cc2ccc(O)cc2)NC(=O)[C@H](CCCN/C(N)=N\\[H])NC(=O)[C@H](CCCC[NH3+])NC(=O)[C@H](CCCC[NH3+])NC(C)=O)C(=O)N[C@@H](CCC(N)=O)C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](CC(C)C)C(=O)N1)C(=O)N[C@@H](C)C(=O)O\n", - "JSON saved: json_inputs/5zml.json\n", - "Processing 6i65, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i65/6i65_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i65/6i65_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEAK'}\n", - "Ligand SMILES: CC(C)c1ccc(O)cc1\n", - "JSON saved: json_inputs/6i65.json\n", - "Processing 6e7m, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e7m/6e7m_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e7m/6e7m_ligand.sdf\n", - "Found 2 chains: {'B': 'TRDQNGTWEMESNENFEGYMKALDIDFCTRKIAVRLTQTKVIDQDGDNFKDKTTSTFRNYDVDFTVGVEFDEYTKSLDNRHVKALVTWEGDVLVCVQKGEKENRGWKKWIEGDKLYLELTCGDQVCRQVFKKK', 'D': 'TRDQNGTWEMESNENFEGYMKALDIDFCTRKIAVRLTQTKVIDQDGDNFKDKTTSTFRNYDVDFTVGVEFDEYTKSLDNRHVKALVTWEGDVLVCVQKGEKENRGWKKWIEGDKLYLELTCGDQVCRQVFKKK'}\n", - "Ligand SMILES: C/C=C(C)/C=C/C=C(C)/C=C/[C@@H]1[C@H](C)CCCC1(C)C\n", - "JSON saved: json_inputs/6e7m.json\n", - "Processing 6i61, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i61/6i61_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i61/6i61_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEAK'}\n", - "Ligand SMILES: CCC(C)(c1ccc(O)cc1)c1ccc(O)cc1\n", - "JSON saved: json_inputs/6i61.json\n", - "Processing 6rz6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rz6/6rz6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rz6/6rz6_ligand.sdf\n", - "Found 1 chains: {'A': 'RNCTIENFKREFFPIVYLIIFFVGVLGNGLSIYVFLQPYKKSTSVNVFMLNLAISNLLFISTLPFRADYYLRGSNWIFGDLACRIMSYSLYVNMYSSIYFLTVLSVVRYLAMVHPFRVTSIRSAWILCGIIWILIMASSIMLLDSEQNGSVTSCLELNLYKIAKLQTMNYIALVVGCLLPFFTLSICYLLIIRVLLKVEADLEDNWETLNDNLKVIEKAAAQVKDALTKMRAAALDAQMKDFRHGFDILVGQIDDALKLVKEAQAAAEQLKTTRNAYIQKYLVSHRKALTTIIITLIIFFLCFLPYHTLRTVHLTTWKVGLCKDRLHKALVITLALAAANACFNPLLYYFAGENFKDRLKSALRK'}\n", - "Ligand SMILES: O=C(O)CCCN1C[C@@H](C(=O)O)Oc2c(NC(=O)c3ccc(OCCCCc4cc(F)ccc4Cl)cc3)cccc21\n", - "JSON saved: json_inputs/6rz6.json\n", - "Processing 6qtm, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtm/6qtm_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qtm/6qtm_ligand.sdf\n", - "Found 1 chains: {'A': 'LSKSSWRQEWLANLKLISVSLVDEFPSELSDSDRQIINEKQLLKDIFANNLKSAISNNFRESDIIILKGEIEDYPSSEIKIYYNELQNKKARFWSFKTQRFVSNGFDI'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)[C@@H]([NH3+])CO)C(=O)N[C@@H](CC(=O)O)C(=O)N[C@@H](CO)C(=O)N[C@@H](COP(=O)(O)O)C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H](CC(N)=O)C(=O)N[C@H](C(=O)N[C@@H](CO)C(=O)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6qtm.json\n", - "Processing 6qlo, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlo/6qlo_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qlo/6qlo_ligand.sdf\n", - "Found 1 chains: {'A': 'PLIVPYNLPLPGGVVPRMLITILGTVKPNANRIALDFQRGNDVAFHFNPRFNENNRRVIVCNTKLDNNWGREERQSVFPFESGKPFKIQVLVEPDHFKVAVNDAHLLQYNHRVKKLNEISKLGISGDIDLTSASYTMI'}\n", - "Ligand SMILES: Cc1ccc(S[C@@H]2O[C@H](CO)[C@H](O)[C@H](n3cc(-c4ccc(F)c(F)c4)nn3)[C@H]2O)cc1\n", - "JSON saved: json_inputs/6qlo.json\n", - "Processing 6oie, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oie/6oie_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oie/6oie_ligand.sdf\n", - "Found 1 chains: {'A': 'MDPIPICSFCLGTKESNREKKPEELLSCADCGSSGHPSCLKFCPELTTNVKALRWQCIECKTCSACRVQGRNADNMLFCDSCDRGFHMECCDPPLSRMPKGMWICQVCRPK'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@H](NC(=O)[C@H](C)[NH3+])C(=O)N[C@H](C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CCC(N)=O)C(=O)N[C@H](C(=O)N[C@@H](C)C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CO)C(=O)N[C@H](C(=O)NCC(=O)NCC(=O)N[C@@H](CCCCNC(=O)/C=C/C)C(=O)N[C@@H](C)C(=O)N1CCC[C@H]1C(=O)O)[C@@H](C)O)[C@@H](C)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6oie.json\n", - "Processing 6miy, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6miy/6miy_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6miy/6miy_ligand.sdf\n", - "Found 4 chains: {'C': 'TQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNFACANAFNNSIIPEDTFFPS', 'D': 'EAAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'KNYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPSSHRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'QKTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRDM'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCc2ccccc2)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6miy.json\n", - "Processing 6nrf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrf/6nrf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrf/6nrf_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLPKPVQDLIKMIFGDPIDVNYEKLKTDIKVVDRDSEEAEIIRKYVKNTHATTHNAYDLEVIDIFKIEREGECQRYKPFKQLHNRRLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQGDPIGLILLGEVALGNMYELKHASHISKLPKGKHSVKGLGKTTPDPSANISLDGVDVPLGTGISSGVNDTSLLYNEYIVYDIAQVNLKYLLKLKFNFK'}\n", - "Ligand SMILES: NC(=O)c1cccc2c1O/C(=C\\c1ccc(C(=O)N3CCN(C4NC5CCCCC5N4)CC3)cc1)C2=O\n", - "JSON saved: json_inputs/6nrf.json\n", - "Processing 6gj5, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj5/6gj5_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj5/6gj5_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK'}\n", - "Ligand SMILES: O=C1N[C@H](C2C3CCCCC3NC2[C@H]2CCC[NH2+]2)c2ccccc21\n", - "JSON saved: json_inputs/6gj5.json\n", - "Processing 6jad, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jad/6jad_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jad/6jad_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](OC[C@H]2O[C@@](O)(CO)[C@@H](O)[C@@H]2O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jad.json\n", - "Processing 6mj4, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mj4/6mj4_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mj4/6mj4_ligand.sdf\n", - "Found 4 chains: {'C': 'KTQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNFACANAFNNSIIPEDTFFPS', 'D': 'AAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'NYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPSSAHGHRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'QKTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRDM'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCCC)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6mj4.json\n", - "Processing 6h12, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h12/6h12_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h12/6h12_ligand.sdf\n", - "Found 1 chains: {'A': 'SELLVNTKSGKVMGTRVPVLSSHISAFLGIPFAEPPVGNMRFRRPEPKKPWSGVWNASTYPNNCQQYVDEQFPGFSGSEMWNPNREMSEDCLYLNIWVPSPRPKSTTVMVWIYGGGFYSGSSTLDVYNGKYLAYTEEVVLVSLSYRVGAFGFLALHGSQEAPGNVGLLDQRMALQWVHDNIQFFGGDPKTVTIFGESAGGASVGMHILSPGSRDLFRRAILQSGSPNCPWASVSVAEGRRRAVELGRNLNCNLNSDEELIHCLREKKPQELIDVEWNVLPFDSIFRFSFVPVIDGEFFPTSLESMLNSGNFKKTQILLGVNKDEGSFFLLYGAPGFSKDSESKISREDFMSGVKLSVPHANDLGLDAVTLQYTDWMDDNNGIKNRDGLDDIVGDHNVICPLMHFVNKYTKFGNGTYLYFFNHRASNLVWPEWMGVIHGYEIEFVFGLPLVKELNYTAEEEALSRRIMHYWATFAKTGNPNEPHSQESKWPLFTTKEQKFIDLNTEPMKVHQRLRVQMCVFWNQFLPKLLNAT'}\n", - "Ligand SMILES: O=C(Nc1cc(COCc2cn(CCNc3c4ccccc4nc4ccccc34)nn2)ccn1)Nc1cccc2c1[C@H]1CCCCN1C2=O\n", - "JSON saved: json_inputs/6h12.json\n", - "Processing 6d3y, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d3y/6d3y_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d3y/6d3y_ligand.sdf\n", - "Found 1 chains: {'A': 'SFDCGKPQVEPKKCPVVGGCVAHPHSWPWQVSLRTRFGMHFCGGTLISPEWVLTAAHCLEKSPRPSSYKVILGAHQEVNLEPHVQEIEVSRLFLEPTRKDIALLKLSSPAVITDKVIPACLPSPNYVVADRTECFITGWGETQGTFGAGLLKEAQLPVIENKVCNRYEFLNGRVQSTELCAGHLAGGTDSCQGDSGGPLVCFEKDKYILQGVTSWGLGCARPNKPGVYVRVSRFVTWIEGVMRNN'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@@H]2ON2C(=O)[C@H](CC(=O)O)NC(=O)[C@@H]2CCCN2C(=O)[C@H](Cc2ccccc2)NC(=O)[C@@H]2CSSC[C@H](NC1=O)C(=O)N[C@@H]([C@@H](C)O)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CO)C(=O)N[C@@H](CCCN/C(N)=N\\[H])C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H]([C@@H](C)CC)C(=O)N2\n", - "JSON saved: json_inputs/6d3y.json\n", - "Processing 6qr2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr2/6qr2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr2/6qr2_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVGLVDVAVHDLRRWTSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: N#CC1C(N)NNC1c1ccc2ccn(Cc3ccc[nH]c3=O)c2c1\n", - "JSON saved: json_inputs/6qr2.json\n", - "Processing 6qxa, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qxa/6qxa_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qxa/6qxa_ligand.sdf\n", - "Found 1 chains: {'A': 'YVAALFFLIPLVALGFAAANFAAVVRKPEGTERMKEISSYIRSGADSFLAHETKAIFKVAIVIAILLMIFTTWQTGVAFLLGAVMSASAGIVGMKMATRANVRVAEAARTTKKIGPALKVAYQGGSVMGLSVGGFALLGLVLVYLIFGKWMGQVDNLNIYTNWLGINFVPFAMTVSGYALGCSIIAMFDRVGGGVYTKAADMAADLVGKTELNLPEDDPRNPATIADNVGDNVGDVAGLGADLLESFVGAIVSSIILASYMFPIYVQKIGENLVHQVPKETIQALISYPIFFALVGLGCSMLGILYVIVKKPSDNPQRELNISLWTSALLTVVLTAFLTYFYLKDLQGLDVLGFRFGAISPWFSAIIGIFSGILIGFWAEYYTSYRYKPTQFLGKSSIEGTGMVISNGLSLGMKSVFPPTLTLVLGILFADYFAGLYGVAIAALGMLSFVATSVSVDSYGPIADNAGGISEMCELDPEVRKITDHLDAVGNTTAAIGKGFAIGSAIFAALSLFASYMFSQISPSDIGKPPSLVLLLNMLDARVIAGALLGAAITYYFSGYLISAVTKAAMKMVDEIRRQAREIPGLLEGKAKPDYNRCIEITSDNALKQMGYPAFIAILTPLVTGFLLGAEFVGGVLIGTVLSGAMLAILTANSGGAWDNAKKYLEAGNLEGYGKGSEPHKALVIGDTVGDPLKDTVGPSLDILIKIMSVVSVIAVSIFKHVHLF'}\n", - "Ligand SMILES: Nc1nc2ccc(CNC(=O)C3CC4CCCCC4N3)cc2s1\n", - "JSON saved: json_inputs/6qxa.json\n", - "Processing 6o9b, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o9b/6o9b_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o9b/6o9b_ligand.sdf\n", - "Found 2 chains: {'A': 'SGSHSMRYFFTSVSRPGRGEPRFIAVGYVDDTQFVRFDSDAASQRMEPRAPWIEQEGPEYWDQETRNVKAQSQTDRVDLGTLRGYYNQSEAGSHTIQIMYGCDVGSDGRFLRGYRQDAYDGKDYIALNEDLRSWTAADMAAQITKRKWEAAHEAEQLRAYLDGTCVEWLRRYLENGKETLQRTDPPKTHMTHHPISDHEATLRCWALGFYPAEITLTWQRDGEDQTQDTELVETRPAGDGTFQKWAAVVVPSGEEQRYTCHVQHEGLPKPLTLRWELS', 'B': 'EAIQRTPKIQVYSRHPAENGKSNFLNCYVSGFHPSDIEVDLLKNGERIEKVEHSDLSFSKDWSFYLLYYTEFTPTEKDEYACRVNHVTLSQPKIVKWDRDM'}\n", - "Ligand SMILES: CC(C)C[C@H](NC(=O)[C@H](CO)NC(=O)[C@@H]1CCCN1C(=O)[C@H](C)NC(=O)[C@@H](NC(=O)[C@@H]([NH3+])[C@@H](C)O)[C@@H](C)O)C(=O)N[C@@H](CO)C(=O)NCC(=O)N[C@@H](CCCC[NH3+])C(=O)O\n", - "JSON saved: json_inputs/6o9b.json\n", - "Processing 6ckl, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ckl/6ckl_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ckl/6ckl_ligand.sdf\n", - "Found 2 chains: {'A': 'MEKQNIAVILARQNSKGLPLKNLRKMNGISLLGHTINAAISSKCFDRIIVSTDGGLIAEEAKNFGVEVVLRPAELASDTASSISGVIHALETIGSNSGTVTLLQPTSPLRTGAHIREAFSLFDEKIKGSVVSACPMEHHPLKTLLQINNGEYAPMRHLSDLEQPRQQLPQAFRPNGAIYINDTASLIANNCFFIAPTKLYIMSHQDSIDIDTELDLQQAENILNH', 'B': 'MEKQNIAVILARQNSKGLPLKNLRKMNGISLLGHTINAAISSKCFDRIIVSTDGGLIAEEAKNFGVEVVLRPAELASDTASSISGVIHALETIGSNSGTVTLLQPTSPLRTGAHIREAFSLFDEKIKGSVVSACPMEHHPLKTLLQINNGEYAPMRHLSDLEQPRQQLPQAFRPNGAIYINDTASLIANNCFFIAPTKLYIMSHQDSIDIDTELDLQQAENILNH'}\n", - "Ligand SMILES: CC(=O)N[C@H]1[C@H]([C@H](O)[C@H](O)CO)OC(C(=O)O)=C[C@@H]1O\n", - "JSON saved: json_inputs/6ckl.json\n", - "Processing 6oir, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oir/6oir_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oir/6oir_ligand.sdf\n", - "Found 1 chains: {'A': 'KYVDKIHIGNYEIDAWYFSPFPEDYGKQPKLWLCEYCLKYMKYEKSYRFHLGQCQWRQPPGKEIYRKSNISVHEVDGKDHKIYCQNLCLLAKLFLDHTLYFDVEPFVFYILTEVDRQGAHIVGYFSKEKESPDGNNVSCIMILPPYQRRGYGRFLIAFSYELSKLESTVGSPEKPLSDLGKLSYRSYWSWVLLENLRDFRGTLSIKDLSQMTSITQNDIISTLQSLNMVKYWKGQHVICVTPKLVEEHLKSAQYKKPPITVDSVCLKWAPP'}\n", - "Ligand SMILES: O=C(NNS(=O)(=O)c1ccccc1)c1cc(-c2ccccc2)ccc1F\n", - "JSON saved: json_inputs/6oir.json\n", - "Processing 6d40, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d40/6d40_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d40/6d40_ligand.sdf\n", - "Found 1 chains: {'A': 'PSFDCGKPQVEPKKCPVVGGCVAHPHSWPWQVSLRTRFGMHFCGGTLISPEWVLTAAHCLEKSPRPSSYKVILGAHQEVNLEPHVQEIEVSRLFLEPTRKDIALLKLSSPAVITDKVIPACLPSPNYVVADRTECFITGWGETQGTFGAGLLKEAQLPVIENKVCNRYEFLNGRVQSTELCAGHLAGGTDSCQGDSGGPLVCFEKDKYILQGVTSWGLGCARPNKPGVYVRVSRFVTWIEGVMRNN'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@@H]2ON2C(=O)[C@H](CC(=O)O)NC(=O)[C@@H]2CCCN2C(=O)[C@H](Cc2ccccc2)NC(=O)[C@@H]2CSSC[C@H](NC1=O)C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CO)C(=O)N[C@@H]([C@@H](C)CC)C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H]([C@@H](C)CC)C(=O)N2\n", - "JSON saved: json_inputs/6d40.json\n", - "Processing 6e6j, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e6j/6e6j_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e6j/6e6j_ligand.sdf\n", - "Found 1 chains: {'A': 'HMEQLKHCNGILKELLSKKHAAYAWPFYKPVDASALGLHDYHDIIKHPMDLSTVKRKMENRDYRDAQEFAADVRLMFSNCYKYNPPDHDVVAMARKLQDVFEFRYAKMP'}\n", - "Ligand SMILES: CCNC(=O)C1CC2C(c3cc(C(C)(C)O)ccc3Oc3c(C)cc(F)cc3C)=CN(C)C(=O)C2N1\n", - "JSON saved: json_inputs/6e6j.json\n", - "Processing 6i7a, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i7a/6i7a_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i7a/6i7a_ligand.sdf\n", - "Found 1 chains: {'A': 'KVVKFSYMWTINNFSFCREEMGEVIKSSTFSSNDKLKWCLRVNPKGLDEESKDYLSLYLLLVSCPKSEVRAKFKFSILNAKGEETKAMESQRAYRFVQGKDWGFKKFIRRNFLLDEANGLLPDDKLTLFCEVSVVQD'}\n", - "Ligand SMILES: C[C@H]([NH3+])C(=O)N[C@@H](C)C(=O)N[C@@H](CC(=O)O)C(=O)N[C@H](C(=O)N[C@H](C(=O)N[C@H](C(=O)N1CCC[C@H]1C(=O)O)[C@@H](C)O)[C@@H](C)O)[C@@H](C)O\n", - "JSON saved: json_inputs/6i7a.json\n", - "Processing 6g25, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g25/6g25_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g25/6g25_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEAQKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYID'}\n", - "Ligand SMILES: Cc1noc(C)c1C1NNCC1c1ccncc1\n", - "JSON saved: json_inputs/6g25.json\n", - "Processing 6oin, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oin/6oin_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oin/6oin_ligand.sdf\n", - "Found 1 chains: {'A': 'KYVDKIHIGNYEIDAWYFSPFPEDYGKQPKLWLCEYCLKYMKYEKSYRFHLGQCQWRQPPGKEIYRKSNISVHEVDGKDHKIYCQNLCLLAKLFLDHTLYFDVEPFVFYILTEVDRQGAHIVGYFSKEKESPDGNNVSCIMILPPYQRRGYGRFLIAFSYELSKLESTVGSPEKPLSDLGKLSYRSYWSWVLLENLRDFRGTLSIKDLSQMTSITQNDIISTLQSLNMVKYWKGQHVICVTPKLVEEHLKSAQYKKPPITVDSVCLKWAPP'}\n", - "Ligand SMILES: O=C(NNS(=O)(=O)c1ccc2ccccc2c1)c1ccccc1F\n", - "JSON saved: json_inputs/6oin.json\n", - "Processing 6jam, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jam/6jam_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jam/6jam_ligand.sdf\n", - "Found 1 chains: {'A': 'QSGPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSAPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O[C@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6jam.json\n", - "Processing 6oxz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxz/6oxz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oxz/6oxz_ligand.sdf\n", - "Found 2 chains: {'B': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF', 'A': 'PQITLWKRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF'}\n", - "Ligand SMILES: CC[C@H](C)CN(C[C@@H](O)[C@H](Cc1ccccc1)NC(=O)O[C@H]1CO[C@H]2OCC[C@H]21)S(=O)(=O)c1ccc([C@@H](O)CO)cc1\n", - "JSON saved: json_inputs/6oxz.json\n", - "Processing 6hop, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hop/6hop_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hop/6hop_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKD'}\n", - "Ligand SMILES: COc1cc(/C=C/C(=O)O)ccc1O\n", - "JSON saved: json_inputs/6hop.json\n", - "Processing 6rot, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rot/6rot_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6rot/6rot_ligand.sdf\n", - "Found 1 chains: {'H': 'IVEGSDAEIGMSPWQVMLFRKSPQELLCGASLISDRWVLTAAHCLLYPPWDKNFTENDLLVRIGKHSRTRYERNIEKISMLEKIYIHPRYNWRENLDRDIALMKLKKPVAFSDYIHPVCLPDRETAASLLQAGYKGRVTGWGNLKEGQPSVLQVVNLPIVERPVCKDSTRIRITDNMFCAGYKPDEGKRGDACEGDSGGPFVMKSPFNNRWYQMGIVSWGEGCDRDGKYGFYTHVFRLKKWIQKVIDQFG'}\n", - "Ligand SMILES: O=C(NCc1cc(Cl)ccc1CO)[C@@H]1CCCN1C(=O)CNS(=O)(=O)Cc1ccccc1\n", - "JSON saved: json_inputs/6rot.json\n", - "Processing 6uhu, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uhu/6uhu_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6uhu/6uhu_ligand.sdf\n", - "Found 1 chains: {'A': 'AASGSALIFDEEMSRYKLLWTDPACEIEVPERLTVSYEALRTHGLAQRCKAVPVRQATEQEILLAHSEEYLEAVKQTPGMNVEELMAFSKKYNDVYFHQNIYHCAKLAAGATLQLVDSVMKREVRNGMALVRPPGHHSQRSAANGFCVFNNVAFAALYAKKNYNLNRILIVDWDVHHGQGIQYCFEEDPSVLYFSWHRYEHQSFWPNLPESDYSSVGKGKGSGFNINLPWNKVGMTNSDYLAAFFHVLLPVAYEFDPELVIVSAGFDSAIGDPEGEMCALPEIFAHLTHLLMPLAAGKMCVVLEGGYNLTSLGQSVCQTVHSLLGDPTPRISGLGTACDSALESIQNVRNVQSSYWSSFKHLAIVWPEPLKRMPASVRTVVVPPPGVELTLPKNCQHSDISESTAKEVQRIRDKHFHDLTDQNILRSLGNIISVLDRMMRSDEVCNGCVVVSDLSVSVQCALQHALTEPAERVLVVYVGDGELPVKTNDGKVFLVQICTKETEDKCVNRLTLCLREGESLTAGFMQALLGLILPVAYEFNPALVLGIVEETTRLMRVWGHMTCLIQGLARGRMLTLLQGYDKDLLELTVSALSGASISPLGRAPKPEDVEMMEKQRQRLQERWGLLRCTVSESW'}\n", - "Ligand SMILES: no ligand\n", - "JSON saved: json_inputs/6uhu.json\n", - "Processing 6mji, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mji/6mji_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mji/6mji_ligand.sdf\n", - "Found 4 chains: {'C': 'KTQVEQSPQSLVVRQGENCVLQCNYSVTPDNHLRWFKQDTGKGLVSLTVLVDQKDKTSNGRYSATLDKDAKHSTLHITATLLDDTATYICVVGDRGSALGRLHFGAGTQLIVIPDIQNPDPAVYQLRDSKSSDKSVCLFTDFDSQTNVSQSKDSDVYITDKCVLDMRSMDFKSNSAVAWSNKDFACANAFNNSIIPEDTFFPS', 'D': 'AAVTQSPRNKVAVTGGKVTLSCNQTNNHNNMYWYRQDTGHGLRLIHYSYGAGSTEKGDIPDGYKASRPSQENFSLILELATPSQTSVYFCASGDEGYTQYFGPGTRLLVLEDLRNVTPPKVSLFEPSKAEISHTQKATLVCLATGFYPDHVELSWWVNGKEVHSGVCTDPQPLKEQPALNDSRYSLSSRLRVSATFWQNPRNHFRCQVQFYGLSENDEWTQDRAKPVTQIVSAEAWGRA', 'A': 'KNYTFRCLQMSSFANRSWSRTDSVVWLGDLQTHRWSNDSATISFTKPWSQGKLSNQQWEKLQHMFQVYRVSFTRDIQELVKMMSPKEDYPIEIQLSAGCEMYPGNASESFLHVAFQGKYVVRFWGTSWQTVPGAPSWLDLPIKVLNADQGTSATVQMLLNDTCPLFVRGLLEAGKSDLEKQEKPVAWLSSVPGHRQLVCHVSGFYPKPVWVMWMRGDQEQQGTHRGDFLPNADETWYLQATLDVEAGEEAGLACRVKHSSLGGQDIILYW', 'B': 'QKTPQIQVYSRHPPENGKPNILNCYVTQFHPPHIEIQMLKNGKKIPKVEMSDMSFSKDWSFYILAHTEFTPTETDTYACRVKHASMAEPKTVYWDRD'}\n", - "Ligand SMILES: CCCCCCCCCCCCCCCCCCCCCCCCCC(=O)N[C@@H](CO[C@H]1O[C@H](CO)[C@H](OCC2CC2)[C@H](O)[C@H]1O)[C@H](O)[C@H](O)CCCCCCCCCCCCCC\n", - "JSON saved: json_inputs/6mji.json\n", - "Processing 6nrj, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrj/6nrj_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrj/6nrj_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLPKPVQDLIKMIFGDPIDVNYEKLKTDIKVVDRDSEEAEIIRKYVKNTHATTHNAYDLEVIDIFKIEREGECQRYKPFKQLHNRRLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQGDPIGLILLGEVALGNMYELKHASHISKLPKGKHSVKGLGKTTPDPSANISLDGVDVPLGTGISSGVNDTSLLYNEYIVYDIAQVNLKYLLKLKFNFK'}\n", - "Ligand SMILES: NC(=O)c1cccc2c1O/C(=C\\c1ccc(C(=O)NCCC3NC4CCCCC4N3)cc1)C2=O\n", - "JSON saved: json_inputs/6nrj.json\n", - "Processing 6nt2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nt2/6nt2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nt2/6nt2_ligand.sdf\n", - "Found 2 chains: {'A': 'PNAEDMTSKDYYFDSYAHFGIHEEMLKDEVRTLTYRNSMFHNRHLFKDKVVLDVGSGTGILCMFAAKAGARKVIGIECSSISDYAVKIVKANKLDHVVTIIKGKVEEVELPVEKVDIIISEWMGYCLFYESMLNTVLYARDKWLAPDGLIFPDRATLYVTAIEDRQYKDYKIHWWENVYGFDMSCIKDVAIKEPLVDVVDPKQLVTNACLIKEVDIYTVKVEDLTFTSPFCLQVKRNDYVHALVAYFNIEFTRCHKRTGFSTSPESPYTHWKQTVFYMEDYLTVKTGEEIFGTIGMRPNAKNNRDLDFTIDLDFKGQLCELSCSTDYRMR', 'D': 'PNAEDMTSKDYYFDSYAHFGIHEEMLKDEVRTLTYRNSMFHNRHLFKDKVVLDVGSGTGILCMFAAKAGARKVIGIECSSISDYAVKIVKANKLDHVVTIIKGKVEEVELPVEKVDIIISEWMGYCLFYESMLNTVLYARDKWLAPDGLIFPDRATLYVTAIEDRQYKDYKIHWWENVYGFDMSCIKDVAIKEPLVDVVDPKQLVTNACLIKEVDIYTVKVEDLTFTSPFCLQVKRNDYVHALVAYFNIEFTRCHKRTGFSTSPESPYTHWKQTVFYMEDYLTVKTGEEIFGTIGMRPNAKNNRDLDFTIDLDFKGQLCELSCSTDYRMR'}\n", - "Ligand SMILES: CCOCC1(COCC)CCC(C2NNCC2C[N@@H+](C)CC[NH2+]C)CC1\n", - "JSON saved: json_inputs/6nt2.json\n", - "Processing 6op9, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6op9/6op9_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6op9/6op9_ligand.sdf\n", - "Found 1 chains: {'A': 'VLARIFKETELRKLKVLGSGVFGTVHKGVWIPEGESIKIPVCIKVIEDKSGRQSFQAVTDHMLAIGSLDHAHIVRLLGLCPGSSLQLVTQYLPLGSLLDHVRQHRGALGPQLLLNWGVQIAKGMYYLEEHGMVHRNLAARNVLLKSPSQVQVADFGVADLLPPDDKQAKTPIKWMALESIHFGKYTHQSDVWSYGVTVWELMTFGAEPYAGLRLAEVPDLLEKGERLAQPQICTIDVYMVMVKCWMIDENIRPTFKELANEFTRMARDPPRYLVIK'}\n", - "Ligand SMILES: COc1cc(Nc2c(C#N)cnc3cc(OCCC[N@H+]4CC[N@H+](C)CC4)c(OC)cc23)c(Cl)cc1Cl\n", - "JSON saved: json_inputs/6op9.json\n", - "Processing 6pno, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pno/6pno_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pno/6pno_ligand.sdf\n", - "Found 1 chains: {'A': 'GESARSLGKGSAPPGPVPEGSIRIYSMRFCPFAERTRLVLKAKGIRHEVININLKNKPEWFFKKNPFGLVPVLENSQGQLIYESAITCEYLDEAYPGKKLLPDDPYEKACQKMILELFSKVPSLVGSFIRSQNKEDYAGLKEEFRKEFTKLEEVLTNKKTTFFGGNSISMIDYLIWPWFERLEAMKLNECVDHTPKLKLWMAAMKEDPTVSALLTSEKDWQGFLELYLQNSPEACDYGL'}\n", - "Ligand SMILES: CC(=O)Nc1ccc(Cl)c(S(=O)(=O)NC(C)C)c1\n", - "JSON saved: json_inputs/6pno.json\n", - "Processing 6e4v, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e4v/6e4v_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e4v/6e4v_ligand.sdf\n", - "Found 1 chains: {'A': 'NDYSVTSTSAGTKMQMTQRDIPQSVTIVSQQRMEDQQLQTLGEVMENTLGISKSQADSDRALYYSRGFQIDNYMVDGIPTYFESRWNLGDALSDMALFERVEVVRGATGLMTGTGNPSAAINMVRKHATSREFKGDVSAEYGSWNKERYVADLQSPLTEDGKIRARIVGGYQNNDSWLDRYNSEKTFFSGIVDADLGDLTTLSAGYEYQRIDVNSPTWGGLPRWNTDGSSNSYDRARSTAPDWAYNDKEINKVFMTLKQQFADTWQATLNATHSEVEFDSKMMYVDAYVNKADGMLVGPYSNYGPGFDYVGGTGWNSGKRKVDALDLFADGSYELFGRQHNLMFGGSYSKQNNRYFSSWANIFPDEIGSFYNFNGNFPQTDWSPQSLAQDDTTHMKSLYAATRVTLADPLHLILGARYTNWRVDTLTYSMEKNHTTPYAGLVFDINDNWSTYASYTSIFQPQNDRDSSGKYLAPITGNNYELGLKSDWMNSRLTTTLAIFRIEQDNVAQSTGTPIPGSNGETAYKAVDGTVSKGVEFELNGAITDNWQLTFGATRYIAEDNEGNAVNPNLPRTTVKMFTSYRLPVMPELTVGGGVNWQNRVYTDTVTPYGTFRAEQGSYALVDLFTRYQVTKNFSLQGNVNNLFDKTYDTNVEGSIVYGTPRNFSITGTYQF'}\n", - "Ligand SMILES: CC(=O)N[C@H]1CCC[N+]2=C(/C=C(\\C)CCO)O[Fe]345(OC(=[N+](CCC[C@@H]6NC(=O)[C@H](CCC[N+](=C(/C=C(\\C)CCO)O3)O4)NC6=O)O5)/C=C/CCOC1=O)O2\n", - "JSON saved: json_inputs/6e4v.json\n", - "Processing 6k1s, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k1s/6k1s_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6k1s/6k1s_ligand.sdf\n", - "Found 1 chains: {'A': 'RVSSGRDLNCVPEIADTLGAVAKQGFDFLCMPVFHPRFKREFIQEPAKNRPGPQTRSDLLLSGRDWNTLIVGKLSPWIRPDSKVEKIRRNSEAAMLQELNFGAYLGLPAFLLPLNQEDNTNLARVLTNHIHTGHHSSMFWMRVPLVAPEDLRDDIIENAPTTHTEEYSGEEKTWMWWHNFRTLCDYSKRIAVALEIGADLPSNHVIDRWLGEPIKAAILPTSIFLTNKKGFPVLSKMHQRLIFRLLKLEVQFIITGTNHHSEKEFCSYLQYLEYLSQNRPPPNAYELFAKGYEDYLQSPLQPLMDNLESQTYEVFEKDPIKYSQYQQAIYKCLLDRVPEEEKDTNVQVLMVLGAGRGPLVNASLRAAKQADRRIKLYAVEKNPNAVVTLENWQFEEWGSQVTVVSSDMREWVAPEKADIIVSELLGSFADNELSPECLDGAQHFLKDDGVSIPGEYTSFLAPISSSKLYNEVRACREKDRDPEAQFEMPYVVRLHNFHQLSAPQPCFTFSHPNRDPMIDNNRYCTLEFPVEVNTVLHGFAGYFETVLYQDITLSIRPETHSPGMFSWFPILFPIKQPITVREGQTICVRFWRCSNSKKVWYEWAVTAPVCSAIHNPTGRSYTIGL'}\n", - "Ligand SMILES: C/C=N\\c1ncnc2c1ccn2[C@@H]1O[C@H]([C@H](O)c2ccc(Cl)cc2)[C@@H](O)[C@H]1O\n", - "JSON saved: json_inputs/6k1s.json\n", - "Processing 6a87, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a87/6a87_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6a87/6a87_ligand.sdf\n", - "Found 2 chains: {'D': 'APVPVTKLVCDGDTYKCTAYLDYGDGKWVAQWDTAVFHT', 'F': 'APVPVTKLVCDGDTYKCTAYLDYGDGKWVAQWDTAVFHT'}\n", - "Ligand SMILES: CS[C@@H]1O[C@H](CO[C@@H]2O[C@@H](C)[C@@H](O)[C@@H](O)[C@@H]2O)[C@@H](O)[C@H](O)[C@H]1NC(C)=O\n", - "JSON saved: json_inputs/6a87.json\n", - "Processing 6oim, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oim/6oim_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6oim/6oim_ligand.sdf\n", - "Found 1 chains: {'A': 'GMTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETSLLDILDTAGQEEYSAMRDQYMRTGEGFLLVFAINNTKSFEDIHHYREQIKRVKDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKEK'}\n", - "Ligand SMILES: CCC(=O)N1CCN(c2nc(=O)n(-c3c(C)ccnc3C(C)C)c3nc(-c4c(O)cccc4F)c(F)cc23)[C@@H](C)C1\n", - "JSON saved: json_inputs/6oim.json\n", - "Processing 6cjp, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjp/6cjp_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6cjp/6cjp_ligand.sdf\n", - "Found 1 chains: {'A': 'LYFQGETHEFTAEISQLMSLIINTVYSNKEIFLRELISNASDALDKIRYQALSDPSQLESEPELFIRIIPQKDQKVLEIRDSGIGMTKADLVNNLGTIAKSGTKSFMEALSAGADVSMIGQFGVGFYSLFLVADHVQVISKHNDDEQYVWESNGKFTVTLDETNERLGRGTMLRLFLKEDQLEYLEEKRIKEVVKKHSEFVAYPIQLVVTKEVE'}\n", - "Ligand SMILES: COc1ccc(CO/N=C2/C=C/C=C\\[C@H]3O[C@@H]3C[C@@H](C)OC(=O)c3c(O)cc(O)cc3C2)cc1\n", - "JSON saved: json_inputs/6cjp.json\n", - "Processing 6pyb, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pyb/6pyb_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pyb/6pyb_ligand.sdf\n", - "Found 1 chains: {'A': 'PAVHLSNGPGQEPIAVMTFDLTKITKTSSSFEVRTWDPEGVIFYGDTNPKDDWFMLGLRDGRPEIQLHNHWAQLTVGAGPRLDDGRWHQVEVKMEGDSVLLEVDGEEVLRLRQVSGPKRHPIMRIALGGLLFPASNLRLPLVPALDGCLRRDSWLDKQAKISASAPTSLRSC'}\n", - "Ligand SMILES: COc1cc(C[C@H]2COC[C@@H]2Cc2ccc(O)c(OC)c2)ccc1O\n", - "JSON saved: json_inputs/6pyb.json\n", - "Processing 6h13, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h13/6h13_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6h13/6h13_ligand.sdf\n", - "Found 1 chains: {'B': 'SELLVNTKSGKVMGTRVPVLSSHISAFLGIPFAEPPVGNMRFRRPEPKKPWSGVWNASTYPNNCQQYVDEQFPGFSGSEMWNPNREMSEDCLYLNIWVPSPRPKSTTVMVWIYGGGFYSGSSTLDVYNGKYLAYTEEVVLVSLSYRVGAFGFLALHGSQEAPGNVGLLDQRMALQWVHDNIQFFGGDPKTVTIFGESAGGASVGMHILSPGSRDLFRRAILQSGSPNCPWASVSVAEGRRRAVELGRNLNCNLNSDEELIHCLREKKPQELIDVEWNVLPFDSIFRFSFVPVIDGEFFPTSLESMLNSGNFKKTQILLGVNKDEGSFFLLYGAPGFSKDSESKISREDFMSGVKLSVPHANDLGLDAVTLQYTDWMDDNNGIKNRDGLDDIVGDHNVICPLMHFVNKYTKFGNGTYLYFFNHRASNLVWPEWMGVIHGYEIEFVFGLPLVKELNYTAEEEALSRRIMHYWATFAKTGNPNEPHSQESKWPLFTTKEQKFIDLNTEPMKVHQRLRVQMCVFWNQFLPKLLNAT'}\n", - "Ligand SMILES: C[N@@H+](Cc1ccnc(NC(=O)Nc2cccc3c2[C@@H]2CCCCN2C3=O)c1)Cc1cn(CCNc2c3ccccc3nc3ccccc23)nn1\n", - "JSON saved: json_inputs/6h13.json\n", - "Processing 6qrf, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrf/6qrf_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrf/6qrf_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVDAGLVDVAVHDLRRWTKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVASLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: O=C(OCc1ccccc1)C1CNNC1\n", - "JSON saved: json_inputs/6qrf.json\n", - "Processing 6mhc, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mhc/6mhc_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mhc/6mhc_ligand.sdf\n", - "Found 1 chains: {'A': 'SNAMSGESARSLGKGSAPPGPVPEGSIRIYSMRFCPFAERTRLVLKAKGIRHEVININLKNKPEWFFKKNPFGLVPVLENSQGQLIYESAITCEYLDEAYPGKKLLPDDPYEKACQKMILELFSKVPSLVGSFIRSQNKEDYAGLKEEFRKEFTKLEEVLTNKKTTFFGGNSISMIDYLIWPWFERLEAMKLNECVDHTPKLKLWMAAMKEDPTVSALLTSEKDWQGFLELYLQNSPEACDYGL'}\n", - "Ligand SMILES: CCC(=O)Nc1nc(-c2ccccc2)cs1\n", - "JSON saved: json_inputs/6mhc.json\n", - "Processing 6j9w, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6j9w/6j9w_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6j9w/6j9w_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVIRVAGDSTAVGEGGRWMKEMVEAWGKKTGTRVEYIDSPADTNDRLALYQQYWAARSPDVDVYMIDVIWPGIVAPHALDLKPYLTEAELKEFFPRIVQNNTIRGKLTSLPFFTDAGILYYRKDLLEKYGYTSPPRTWNELEQMAERVMEGERRAGNRDFWGFVFQGKPYEGLTCDALEWIYSHGGGRIVEPDGTISVNNGRAALALNRAHGWVGRIAPQGVTSYAEEEARNVWQQGNSLFMRNWPYAYALGQAEGSPIRGKFGVTVLPKASADAPNAATLGGWQLMVSAYSRYPKEAVDLVKYLASYEVQKDNAVRLSRLPTRPALYTDRDVLARNPWFRDLLPVFQNAVSRPSDVAGARYNQVSEAIWTEVHSVLTGRKKGEQAVRDLEARIRRILRHHH'}\n", - "Ligand SMILES: OC[C@H]1O[C@H](O[C@H]2O[C@H](CO)[C@@H](O)[C@H](O)[C@H]2O)[C@H](O)[C@@H](O)[C@@H]1O\n", - "JSON saved: json_inputs/6j9w.json\n", - "Processing 6nrg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrg/6nrg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nrg/6nrg_ligand.sdf\n", - "Found 1 chains: {'A': 'KSKLPKPVQDLIKMIFGDPIDVNYEKLKTDIKVVDRDSEEAEIIRKYVKNTHATTHNAYDLEVIDIFKIEREGECQRYKPFKQLHNRRLLWHGSRTTNFAGILSQGLRIAPPEAPVTGYMFGKGIYFADMVSKSANYCHTSQGDPIGLILLGEVALGNMYELKHASHISKLPKGKHSVKGLGKTTPDPSANISLDGVDVPLGTGISSGVNDTSLLYNEYIVYDIAQVNLKYLLKLKFNFK'}\n", - "Ligand SMILES: NC(=O)c1cccc2c1O/C(=C\\c1ccc(C3NNNN3)c(F)c1)C2=O\n", - "JSON saved: json_inputs/6nrg.json\n", - "Processing 6fff, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6fff/6fff_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6fff/6fff_ligand.sdf\n", - "Found 1 chains: {'A': 'MGKLSEQLKHCNGILKELLSKKHAAYAWPFYKPVDASALGLHDYHDIIKHPMDLSTVKRKMENRDYRDAQEFAADVRLMFSNCYKYNPPDHDVVAMARKLQDVFEFRYAKMPD'}\n", - "Ligand SMILES: CC(=O)N1c2ccc(-c3cnc(C(N)=O)nc3)cc2N(Cc2ccccc2CO)C[C@@H]1C1C=C1\n", - "JSON saved: json_inputs/6fff.json\n", - "Processing 6n93, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n93/6n93_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6n93/6n93_ligand.sdf\n", - "Found 2 chains: {'A': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH', 'C': 'AYQYVNVVTINKVAVIEFNYGRKLNALSKVFIDDLMQALSDLNRPEIRCIILRAPSGSKVFSAGHDIHELPSGGRDPLSYDDPLRQITRMIQKFPKPIISMVEGSVWGGAFEMIMSSDLIIAASTSTFSMTPVNLGVPYNLVGIHNLTRDAGFHIVKELIFTASPITAQRALAVGILNHVVEVEELEDFTLQMAHHISEKAPLAIAVIKEELRVLGEAHTMNSDEFERIQGMRRAVYDSEDYQEGMNAFLEKRKPNFVGH'}\n", - "Ligand SMILES: CC(C)(CO[P@@](=O)(O)O[P@](=O)(O)OC[C@H]1O[C@@H](n2cnc3c(N)ncnc32)[C@H](O)[C@@H]1OP(=O)(O)O)[C@@H](O)C(=O)NCCC(=O)NCCO\n", - "JSON saved: json_inputs/6n93.json\n", - "Processing 6jut, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jut/6jut_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6jut/6jut_ligand.sdf\n", - "Found 1 chains: {'A': 'FVQIKFDDLQFFENCGGGSFGSVYRAKWISQDKEVAVKKLLKIEKEAEILSVLSHRNIIQFYGVILEPPNYGIVTEYASLGSLYDYINSNRSEEMDMDHIMTWATDVAKGMHYLHMEAPVKVIHRDLKSRNVVIAADGVLKICDFGASRFHNHTTHMSLVGTFPWMAPEVIQSLPVSETCDTYSYGVVLWEMLTREVPFKGLEGLQVAWLVVEKNERLTIPSSCPRSFAELLHQCWEADAKKRPSFKQIISILESMSNDTSLPDKCNSFLHNKAEWRCEIEATLERLKKLERDLSFK'}\n", - "Ligand SMILES: COC1NNC2NCC(c3cn(-c4c(F)ccc(NS(=O)(=O)c5cccc(Br)c5)c4F)nn3)CC21\n", - "JSON saved: json_inputs/6jut.json\n", - "Processing 6g2e, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2e/6g2e_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6g2e/6g2e_ligand.sdf\n", - "Found 1 chains: {'A': 'VKFQVGDLVWSKVGTYPWWPCMVSSDPQLEVHTKINTRGAREYHVQFFSNQPERAWVHEKRVREYKGHKQYEELLAEATKIRKPRPQRERAQWDIGIAHAEKALKMTREERIEQYTFIYID'}\n", - "Ligand SMILES: Cc1cc(C[NH3+])cc(C)c1-c1ncn(C)c1-c1ccncc1\n", - "JSON saved: json_inputs/6g2e.json\n", - "Processing 6nd3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nd3/6nd3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nd3/6nd3_ligand.sdf\n", - "Found 1 chains: {'A': 'SGIPDGPTPRHVKLKENFLKQVPSITVQRAVAITKIAKENPGLPKPLLRAKTFRYCCETAPLVIQDHELIVGSPNGAPRAGAFSPEVAWRWLQDELDTIGSRPQDPFYISEEDKKVLREEVFPFWQNKSVDEFCEGQYREADLWEMSGESFVSDCSYHAVNGGGDSNPGYDVILMKKGMLDIQREAREKLEQLDYANPEDIDKIYFYKSVIETAEGVMIYARRLSAYAAELAARETDPRRKAELQKISEVNARVPAHAPSNFWEAIQAVWTVESLLVVEENQTGMSIGRVDQYMYPFYRADIDSGRLTEYEAFDLAGCMLVKMSEMMWITSEGASKFFAGYQPFVNMCVGGVTREGHDATNDLTYMLMDAVRHVRIYQPTLATRVHNKSPQKYLKKIVDVIRSGMGFPAVHFDDAHIKMMLAKGVSIEDARDYCLMGCVEPQKSGRLYQWTSTGYTQWPICIELVLNHGVPLWYGKKVTPDMGDLSQYDTYEKFEAAVKEQIRWITKNTSVATVISQRAHRELAPKPLMSLMYEGCMESGRDVSAGGAMYNFGPGVVWSGLATYVDSMAAIKKLVYDDRKYTLAQLNEALKADFAGYDQILADCLAAPKYGNDDDYADMIAADLVHFTETEHRKYKTLYSVLSHGTLSISNNTPFGQLLGASANGRRAWMPLSDGISPTQGADYKGPTAIIKSVSKMANDNMNIGMVHNFKLMSGLLDTPEGENGLITLIRTACMLGNGEMQFNYLDNELLLDAQKHPEKYRDLVVRVAGYSAFFVELCKDVQDEIISRTMLHGF'}\n", - "Ligand SMILES: C[N+](C)(C)CCO\n", - "JSON saved: json_inputs/6nd3.json\n", - "Processing 6os6, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6os6/6os6_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6os6/6os6_ligand.sdf\n", - "Found 1 chains: {'A': 'TEELTTVRDACARTLENTARTLHLGASGTEFVAAFRAMTDHWGAARPHDLPLSDVSPDGSPVEYAVDLGGLAPALQFAMEPLTAGVPARDPLAARAIMPLLAGRYGADATRWSALADRLLPDDAHGPHVSMYGAEVRAGAPIRFKAWFYLNVTGPDGAFNLLYSALERMGTTHLWPVVQAHVHRAGEDVPFLLSLDLSDDPAARVKVYFRHFAADVEEVAAVLKAYPGFEPGEVRAFCKVMMGGRRRFSDQPAVTCVSLLDAQTFDRTAATLYVPLWTYAEHDGEVRQRVHRTLAAWPEALYRYDSVLAGIAHRGLDAGTGIHNYISWQPGRTRPRMKVYLSPEMHDVTPPPLGVSQQHHLS'}\n", - "Ligand SMILES: [NH3+][C@@H](CC1CNC2CCCCC12)C(=O)O\n", - "JSON saved: json_inputs/6os6.json\n", - "Processing 6dql, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dql/6dql_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6dql/6dql_ligand.sdf\n", - "Found 1 chains: {'A': 'NVDEFLFISNNFKQYKEFIDMDTAKHYFECRNIEGLNHILDSYKDSKSTKEKNLFALVKVLLATLTEEDCLTERTYLSNYLINIETWSHYETVLFNNCMFIFESCFIEMVFSKVILNLDKYNTLRYYGNESIRMFVNMLILFIQRQEYDKASEILAKIEDYQLNDDCLYERCCVSFFDGIIGLINGKEGAEQKCVQILEIFQLLNCKTIHHMFQTYLEAIKHKLSLE'}\n", - "Ligand SMILES: CSCC[C@H]([NH3+])C(=O)N[C@@H](CC1CNC2CCCCC12)C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](CC(C)C)C(=O)N[C@@H](Cc1ccccc1)C(=O)N[C@@H](CC(C)C)C(=O)O\n", - "JSON saved: json_inputs/6dql.json\n", - "Processing 6inz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6inz/6inz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6inz/6inz_ligand.sdf\n", - "Found 1 chains: {'A': 'PKETTIFAMHLGKALDPNLPVFVKAEKDTNIKLVNVASQNQTDQIQAYNLMLTEGKLPDIVSYELSADLENLGIEGGLIPLEDLINQHAPNLKKFFEENPRYKKDAVAVDGHIYMIPNYYDYFNIKVSQGYFIRQDWLEKLGLKEPRTVDELYTTLKAFREKDPNGNGKKDEVPFFVRANNVRKVLTSLVDLFKASPIWYEENGMVKYGPAQKEFKHAIKELSKWYKEGLIDEEIFTRGLESRDYLLSNNLGGATDDWIASTSSYNRNLADKIPGFNLKLVLPYELNGNAKTRHARTTYLGGWGISKDAKDPVSLIKYFDYWYSVEGRRLWNFGIEGSEYTLVDGKPVFTDKVLKNPDGKTPLAVLREVGAQYRLGAFQDAQYELGWASESAKAGYKYYMDNDVVLDELPILKYTKEKSKEFVSIDTAMRAVVEEKAQQWILGSGDIDKEWDAYIKRLENLGLSKAEQIQNEAF'}\n", - "Ligand SMILES: CC(=O)N[C@@H]1[C@@H](O[C@@H]2OC(C(=O)O)=C[C@H](O)[C@H]2O)[C@H](O)[C@@H](CO)O[C@H]1O\n", - "JSON saved: json_inputs/6inz.json\n", - "Processing 6i67, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i67/6i67_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i67/6i67_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEAKV'}\n", - "Ligand SMILES: Oc1ccc2c(c1)CCCC2\n", - "JSON saved: json_inputs/6i67.json\n", - "Processing 6quw, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6quw/6quw_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6quw/6quw_ligand.sdf\n", - "Found 2 chains: {'A': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK', 'B': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHK'}\n", - "Ligand SMILES: CC1(C)C[C@@]2(C)c3ccccc3N[C@@]2(C)[NH2+]1\n", - "JSON saved: json_inputs/6quw.json\n", - "Processing 6qwi, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qwi/6qwi_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qwi/6qwi_ligand.sdf\n", - "Found 2 chains: {'A': 'MTIFQFPQDFMWGTATAAYQIEGAYQEDGRGLSIWDTFAHTPGKVFNGDNGNVACDSYHRYEEDIRLMKELGIRTYRFSVSWPRIFPNGDGEVNQKGLDYYHRVVDLLNDNGIEPFCTLYHWDLPQALQDAGGWGNRRTIQAFVQFAETMFREFHGKIQHWLTFNEPWCIAFLSNMLGVHAPGLTNLQTAIDVGHHLLVAHGLSVRRFRELGTSGQIGIAPNVSWAVPYSTSEEDKAACARTISLHSDWFLQPIYQGSYPQFLVDWFAEQGATVPIQDGDMDIIGEPIDMIGINYYSMSVNRFNPEAGFLQSEEINMGLPVTDIGWPVESRGLYEVLHYLQKYGNIDIYITENGACINDEVVNGKVQDDRRISYMQQHLVQVHRAIHDGLHVKGYMAWSLLDNFEWAEGYSMRFGIIHVDFRTQVRTPKESYYWYRKVVGNNWLETRR', 'B': 'MTIFQFPQDFMWGTATAAYQIEGAYQEDGRGLSIWDTFAHTPGKVFNGDNGNVACDSYHRYEEDIRLMKELGIRTYRFSVSWPRIFPNGDGEVNQKGLDYYHRVVDLLNDNGIEPFCTLYHWDLPQALQDAGGWGNRRTIQAFVQFAETMFREFHGKIQHWLTFNEPWCIAFLSNMLGVHAPGLTNLQTAIDVGHHLLVAHGLSVRRFRELGTSGQIGIAPNVSWAVPYSTSEEDKAACARTISLHSDWFLQPIYQGSYPQFLVDWFAEQGATVPIQDGDMDIIGEPIDMIGINYYSMSVNRFNPEAGFLQSEEINMGLPVTDIGWPVESRGLYEVLHYLQKYGNIDIYITENGACINDEVVNGKVQDDRRISYMQQHLVQVHRAIHDGLHVKGYMAWSLLDNFEWAEGYSMRFGIIHVDFRTQVRTPKESYYWYRKVVGNNWLETRR'}\n", - "Ligand SMILES: CCOCCOc1ccc(-c2cn(C[C@@H]3[NH2+]C[C@@H](O)[C@H]3O)nn2)cc1\n", - "JSON saved: json_inputs/6qwi.json\n", - "Processing 6npm, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6npm/6npm_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6npm/6npm_ligand.sdf\n", - "Found 1 chains: {'B': 'SNPKFENIAEGLRALLARSHVERTTDEGTWVAGVFVYGGSKTSLYNLRRGTALAIPQCRLTPLSRLPFGMAPGPGPQPGPLRESIVCYFMVFLQTHIFAEVLKDAIKDLVMTKPAPTCNIRVTVCSFDDGVDLP'}\n", - "Ligand SMILES: O=C(O)c1cncc(C#Cc2ccccc2)c1\n", - "JSON saved: json_inputs/6npm.json\n", - "Processing 6i64, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i64/6i64_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6i64/6i64_ligand.sdf\n", - "Found 1 chains: {'A': 'YNKIVSHLLVAEPEKIYAMPDPTVPDSDIKALTTLCDLADRELVVIIGWAKHIPGFSTLSLADQMSLLQSAWMEILILGVVYRSLSFEDELVYADDYIMDEDQSKLAGLLDLNNAILQLVKKYKSMKLEKEEFVTLKAIALANSDSMHIEDVEAVQKLQDVLHEALQDYEAGQHMEDPRRAGKMLMTLPLLRQTSTKAVQHFYNIKLEGKVPMHKLFLEMLEAK'}\n", - "Ligand SMILES: CC(c1ccc(O)cc1)c1ccc(O)cc1\n", - "JSON saved: json_inputs/6i64.json\n", - "Processing 6e3n, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3n/6e3n_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6e3n/6e3n_ligand.sdf\n", - "Found 1 chains: {'A': 'AMEDFVRQCFNPMIVELAEKAMKEYGEDPKIETNKFAAICTHLEVCFMYSDFGLKHRFEIIEGRDRIMAWTVVNSICNTTGVEKPKFLPDLYDYKENRFIEIGVTRREVHIYYLEKANKIEKTHIHIFSFTGEEMATKADYTLDEESRARIKTRLFTIRQEMASRSLWDSFRQSE'}\n", - "Ligand SMILES: Cc1ccccc1C1=CC(=O)[C@H](O)C(C(=O)O)=N1\n", - "JSON saved: json_inputs/6e3n.json\n", - "Processing 6qrg, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrg/6qrg_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qrg/6qrg_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVRQSLPIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: COC(=O)COc1cccc(COC(=O)C2CNNC2)c1\n", - "JSON saved: json_inputs/6qrg.json\n", - "Processing 6nxz, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nxz/6nxz_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nxz/6nxz_ligand.sdf\n", - "Found 4 chains: {'A': 'ATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERI', 'B': 'ATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERI', 'C': 'ATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERI', 'D': 'ATFGMGDRVRKKSGAAWQGQIVGWYCTNLTPEGYAVESEAHPGSVQIYPVAALERI'}\n", - "Ligand SMILES: COCC[C@@H](O)CO\n", - "JSON saved: json_inputs/6nxz.json\n", - "Processing 6iby, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6iby/6iby_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6iby/6iby_ligand.sdf\n", - "Found 1 chains: {'A': 'ELTQSRVQKIWVPNSPTVIVMVGLPARGKTYISKKLTRYLNWIGVPTKVFNVGEYRREAVKQYSSYNFFRPDNEEAMKVRKQCALAALRDVKSYLAKEGGQIAVFDATNTTRERRHMILHFAKENDFKAFFIESVCDDPTVVASNIMEVKISSPDYKDCNSAEAMDDFMKRISCYEASYQPLDPDKCDRDLSLIKVIDVGRRFLVNRVQDHIQSRIVYYLMNIHVQPRTIYLCRHGENEHNLQGRIGGDSGLSSRGKKFASALSKFVEEQNLKDLRVWTSQLKSTIQTAEALRLPYEQWKALNEIDAGVCEELTYEEIRDTYPEEYALREQDKYYYRYPTGESYQDLVQRLEPVIMELERQENVLVICHQAVLRCLLAYFLDKSAEEMPYLKCPLHTVLKLTPVAYGCRVESIYLNVESVCTHRERSE'}\n", - "Ligand SMILES: Cn1ccc2ccc(-c3cc(Nc4cnccc4C(=O)N[C@H]4CC[N@H+](C)C4)cc4nccnc34)cc21\n", - "JSON saved: json_inputs/6iby.json\n", - "Processing 6gj7, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj7/6gj7_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj7/6gj7_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKH'}\n", - "Ligand SMILES: O=C1N[C@H](C2C(C[NH2+]Cc3ccc4ccn(Cc5ccccc5)c4c3)NC3CCCCC32)c2cc(O)ccc21\n", - "JSON saved: json_inputs/6gj7.json\n", - "Processing 6qr3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr3/6qr3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr3/6qr3_ligand.sdf\n", - "Found 2 chains: {'A': 'GSMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPGLVDVAVHDLRRWTSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: C[N@@H+]1CCC[C@H](Cn2ccc3ccc(C4NNC(N)C4C#N)cc32)C1\n", - "JSON saved: json_inputs/6qr3.json\n", - "Processing 6qr1, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr1/6qr1_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6qr1/6qr1_ligand.sdf\n", - "Found 2 chains: {'A': 'SMKIDVVTIFPEYLQPVRQSLPGKAIDAGLVDVAVHDLRRWTHDVHKSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVLGSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLL', 'B': 'SMKIDVVTIFPEYLQPVRGLVDVAVHDLRRWTSVDDSPYGGGPGMVMKPTVWGDALDEICTSETLLVVPTPAGYPFTQETAWQWSTEDHLVIACGRYEGIDQRVADDAATRMRVREVSIGDYVLNGGEAAALVIIEAVLRLVPGVSLLEGPSYTRPPSWRGMDVPPVLLSGDHAKIAAWRAEQSRQRTIERRPDLLGFDSP'}\n", - "Ligand SMILES: N#CC1C(N)NNC1c1ccc2c(Cl)cn(Cc3cccnc3)c2c1\n", - "JSON saved: json_inputs/6qr1.json\n", - "Processing 6s9x, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s9x/6s9x_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6s9x/6s9x_ligand.sdf\n", - "Found 1 chains: {'A': 'DVAIVKEGWLHKRGEYIKTWRPRYFLLKNDGTFIGYKERPQDEAPLNNFSVAQCQLMKTERPRPNTFIIRCLQWTTVIERTFHVETPEEREEWTTAIQTVADGLKRVTMNEFEYLKLLGKGTFGKVILVKEKATGRYYAMKILKKEVIQNSRHPFLTALKYSFQTHDRLCFVMEYANGGELFFHLSRERVFSEDRARFYGAEIVSALDYLHSEKNVVYRDLKLENLMLDKDGHIKITDFGLCKEGIKFCGTPEYLAPEVLEDNDYGRAVDWWGLGVVMYEMMCGRLPFYNQDHEKLFELILMEEIRFPRTLGPEAKSLLSGLLKKDPKQRLGGGSEDAKEIMQHRFFAGIVWQHVYEKKLSPPFKPQVTSETDTRYFDEEFT'}\n", - "Ligand SMILES: CCC(=O)Nc1ccc2[nH]c(=O)n([C@H]3CC[N@H+](Cc4ccc(C5=C(c6ccccc6)NC(=O)/C(=C/c6ccc(O)cc6)N5)cc4)CC3)c2c1\n", - "JSON saved: json_inputs/6s9x.json\n", - "Processing 6q4q, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6q4q/6q4q_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6q4q/6q4q_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPSEYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVK'}\n", - "Ligand SMILES: no ligand\n", - "JSON saved: json_inputs/6q4q.json\n", - "Processing 6hbn, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hbn/6hbn_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6hbn/6hbn_ligand.sdf\n", - "Found 1 chains: {'A': 'GPVPSRARVYTDVNTHRPREYWDYESHVVEWGNQDDYQLVRKLGRGKYSEVFEAINITNNEKVVVKILKPVKKKKIKREIKILENLRGGPNIITLADIVKDPVSRTPALVFEHVNNTDFKQLYQTLTDYDIRFYMYEILKALDYCHSMGIMHRDVKPHNVMIDHEHRKLRLIDWGLAEFYHPGQEYNVRVASRYFKGPELLVDYQMYDYSLDMWSLGCMLASMIFRKEPFFHGHDNYDQLVRIAKVLGTEDLYDYIDKYNIELDPRFNDILGRHSRKRWERFVHSENQHLVSPEALDFLDKLLRYDHQSRLTAREAMEHPYFYTVVKDQARMG'}\n", - "Ligand SMILES: C=CCOc1cccc2c1-c1c(c3c(n1C(C)C)CCCC3=O)C2=O\n", - "JSON saved: json_inputs/6hbn.json\n", - "Processing 6nw3, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nw3/6nw3_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6nw3/6nw3_ligand.sdf\n", - "Found 1 chains: {'A': 'SFVEMVDNLRGKSGQGYYVEMTVGSPPQTLNILVDTGSSNFAVGAAPHPFLHRYYQRQLSSTYRDLRKGVYVPYTQGKWEGELGTDLVSIPHGPNVTVRANIAAITESDKFFINGSNWEGILGLAYAEIARPDDSLEPFFDSLVKQTHVPNLFSLQLCGAASVGGSMIIGGIDHSLYTGSLWYTPIRREWYYEVIIVRVEINGQDLKMDCKEYNYDKSIVDSGTTNLRLPKKVFEAAVKSIKAASSTEKFPDGFWLGEQLVCWQAGTTPWNIFPVISLYLMGEVTNQSFRITILPQQYLRPVDDCYKFAISQSSTGTVMGAVIMEGFYVVFDRARKRIGFAVSACHVHDEFRTAAVEGPFVTLDMEDCGY'}\n", - "Ligand SMILES: CCCC[C@H]([NH2+]C[C@@H]1Cc2cccc(c2)CCCCc2cc(cc(N(CCC)S(C)(=O)=O)c2)C(=O)N1)C(=O)NCC(C)C\n", - "JSON saved: json_inputs/6nw3.json\n", - "Processing 6tel, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6tel/6tel_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6tel/6tel_ligand.sdf\n", - "Found 1 chains: {'A': 'LELRLKSPVGAEPAVYPWPLPVYHDAAHEIIETIRWVCEEIPDLKLAMENYVLIDYDTKSFESMQRLCDKYNRAIDSIHQLWKGNTRPSTGLLRHILQQVYNHSVTDPNNYEPFSPEVYGETSFDLVAQMIDEIKMTDDDLFVDLGSGVGQVVLQVAAATNCKHHYGVEKADIPAKYAETMDREFRKWMKWYGKKHAEYTLERGDFLSEEWRERIANTSVIFVNNFAFGPEVDHQLKERFANMKEGGRIVSSKPFAPLNFRINSRNLSDIGTIMRVVELSPLKSWTGKPVSYYLHTIDRTILENYFSSLKNP'}\n", - "Ligand SMILES: COc1nc(Nc2cc(S(C)(=O)=O)ccc2N[C@@H](c2cccc3c2OC(F)(F)O3)c2ncccc2Cl)nc(N2CC[NH2+]CC2)n1\n", - "JSON saved: json_inputs/6tel.json\n", - "Processing 6p8y, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6p8y/6p8y_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6p8y/6p8y_ligand.sdf\n", - "Found 1 chains: {'A': 'MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETSLLDILDTAGQEEYSAMRDQYMRTGEGFLLVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKSDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKH'}\n", - "Ligand SMILES: CCC(=O)N1CC(NC(=O)Cn2cc(C(=O)N3CCc4c(cccc4OC)C3)c3cc(Br)ccc32)C1\n", - "JSON saved: json_inputs/6p8y.json\n", - "Processing 6d5w, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d5w/6d5w_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d5w/6d5w_ligand.sdf\n", - "Found 2 chains: {'R': 'GMTEYKLVVVGAGGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHQYREQIKRVKDSDDVPMVLVGNKCDLAARTVESRQAQDLARSYGIPYIETSAKTRQGVEDAFYTLVREIRQH', 'S': 'QMRLPSADVYRFAEPDSEENIIFEEGIPIIKAGTVIKLIERLTYHMYADPNFVRTFLTTYRSFCKPQELLSLIIERFEIPEPEPTEADRIAIENGDQPLSAELKRFRKEYIQPVQLRVLNVCRHWVEHHFYDFERDAYLLQRMEEFIGTVRGKAMKKWVESITKIIQRKKIAHNITFQSSPPTVEWHISRPGHIETFDLLTLHPIEIARQLTLLESDLYRAVQPSELVGSVWTKEDKEINSPNLLKMIRHTTNLTLWFEKCIVETENLEERVAVVSRIIEILQVFQELNNFNGVLEVVSAMNSSPVYRLDHTFEQIPSRQKKILEEAHELSEDHYKKYLAKLRSINPPCVPFFGIYLTNILKTEEGNPEVLKRHGKELINFSKRRKVAEITGEIQQYQNQPYCLRVESDIKRFFENLNPMGNSMEKEFTDYLFNKSLEIEPRNPKPLPRFPKKYSYPLKSPGVRPSNPR'}\n", - "Ligand SMILES: Fc1ccc(CN2c3ccccc3N3CCCNC32)cc1\n", - "JSON saved: json_inputs/6d5w.json\n", - "Processing 6t6a, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6t6a/6t6a_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6t6a/6t6a_ligand.sdf\n", - "Found 1 chains: {'A': 'VYNDGYDDDNYDYIVKNGEKWMDRYEIDSLIGKGSFGQVVKAYDRVEQEWVAIKIIKNKKAFLNQAQIEVRLLELMNKHDTEMKYYIVHLKRHFMFRNHLCLVFEMLSYNLYDLLRNTNFRGVSLNLTRKFAQQMCTALLFLATPELSIIHCDLKPENILLCNPKRSAIKIVDFGSSCQLGQRIYQIQSRFYRSPEVLLGMPYDLAIDMWSLGCILVEMHTGEPLFSGANEVDQMNKIVEVLGIPPAHILDQAPKARKFFEKLPDGTWNLKKTKDGKREYKPPGTRKLHNILGVETGGPGGRRAGESGHTVADYLKFKDLILRMLDYDPKTRIQPYYALQHSFFKK'}\n", - "Ligand SMILES: O=C1C=CC=CC2NC3C(Cl)CCCC3C12\n", - "JSON saved: json_inputs/6t6a.json\n", - "Processing 6o5g, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o5g/6o5g_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6o5g/6o5g_ligand.sdf\n", - "Found 1 chains: {'A': 'LTEEQIAEFKEAFSLFDKDGDGTITTKELGTVMRSLGQNPTEAELQDMINEVDADGNGTIDFPEFLTMMARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVMTNLGEKLTDEEVDEMIREADIDGDGQVNYEEFVQMMT'}\n", - "Ligand SMILES: CC1(C)C2NC3CC(Br)C(Cl)CC3C2C[C@@]23C[N@@H+]4CCC[C@]4(C[C@@H]12)C(=O)N3\n", - "JSON saved: json_inputs/6o5g.json\n", - "Processing 6r7d, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6r7d/6r7d_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6r7d/6r7d_ligand.sdf\n", - "Found 2 chains: {'A': 'HHHHHHKDEVALLAAVTLLGVLLQAYFSLQVISARRAFRVSPPLTTGPPEFERVYRAQVNCSEYFPLFLATLWVAGIFFHEGAAALCGLVYLFARLRYFQGYARSAQLRLAPLYASARALWLLVALAALGLLAHFLPAALRAALLGRLR', 'C': 'HHHHHHKDEVALLAAVTLLGVLLQAYFSLQVISARRAFRVSPPLTTGPPEFERVYRAQVNCSEYFPLFLATLWVAGIFFHEGAAALCGLVYLFARLRYFQGYARSAQLRLAPLYASARALWLLVALAALGLLAHFLPAALRAALLGRL'}\n", - "Ligand SMILES: COc1nc(C(=O)[C@H]2C[C@@H]2C(=O)O)ncc1N(CC1CC1)c1cccc2ccccc12\n", - "JSON saved: json_inputs/6r7d.json\n", - "Processing 6pya, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pya/6pya_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6pya/6pya_ligand.sdf\n", - "Found 2 chains: {'A': 'PAVHLSNGPGQEPIAVMTFDLTKITKTSSSFEVRTWDPEGVIFYGDTNPKDDWFMLGLRDGRPEIQLHNHWAQLTVGAGPRLDDGRWHQVEVKMEGDSVLLEVDGEEVLRLRQVSGPLTSKRHPIMRIALGGLLFPASNLRLPLVPALDGCLRRDSWLDKQAKISASAPTSLRSC', 'B': 'PAVHLSNGPGQEPIAVMTFDLTKITKTSSSFEVRTWDPEGVIFYGDTNPKDDWFMLGLRDGRPEIQLHNHWAQLTVGAGPRLDDGRWHQVEVKMEGDSVLLEVDGEEVLRLRQVSGPLTSKRHPIMRIALGGLLFPASNLRLPLVPALDGCLRRDSWLDKQAKISASAPTSLRSC'}\n", - "Ligand SMILES: c1ccc(C2NC3CCCCC3C2Cn2ccnc2)cc1\n", - "JSON saved: json_inputs/6pya.json\n", - "Processing 6ffe, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ffe/6ffe_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6ffe/6ffe_ligand.sdf\n", - "Found 1 chains: {'A': 'MGKLSEQLKHCNGILKELLSKKHAAYAWPFYKPVDASALGLHDYHDIIKHPMDLSTVKRKMENRDYRDAQEFAADVRLMFSNCYKYNPPDHDVVAMARKLQDVFEFRYAKMPD'}\n", - "Ligand SMILES: CC(=O)N1c2ccccc2N(Cc2ccccc2C(=O)O)C[C@@H]1C1C=C1\n", - "JSON saved: json_inputs/6ffe.json\n", - "Processing 6d3x, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d3x/6d3x_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6d3x/6d3x_ligand.sdf\n", - "Found 1 chains: {'A': 'FDCGKPQVEPKKCPVVGGCVAHPHSWPWQVSLRTRFGMHFCGGTLISPEWVLTAAHCLEKSPRPSSYKVILGAHQEVNLEPHVQEIEVSRLFLEPTRKDIALLKLSSPAVITDKVIPACLPSPNYVVADRTECFITGWGETQGTFGAGLLKEAQLPVIENKVCNRYEFLNGRVQSTELCAGHLAGGTDSCQGDSGGPLVCFEKDKYILQGVTSWGLGCARPNKPGVYVRVSRFVTWIEGVMRNN'}\n", - "Ligand SMILES: [H]/N=C(/N)NCCC[C@@H]1NC(=O)[C@@H]2ON2C(=O)[C@H](CC(=O)O)NC(=O)[C@@H]2CCCN2C(=O)[C@H](Cc2ccccc2)NC(=O)[C@@H]2CSSC[C@H](NC1=O)C(=O)N[C@@H](Cc1ccc(O)cc1)C(=O)N[C@@H](CCCC[NH3+])C(=O)N[C@@H](CO)C(=O)N[C@@H](CCCC[NH3+])C(=O)N1CCC[C@H]1C(=O)N1CCC[C@H]1C(=O)N[C@@H]([C@@H](C)CC)C(=O)N2\n", - "JSON saved: json_inputs/6d3x.json\n", - "Processing 6gj8, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj8/6gj8_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6gj8/6gj8_ligand.sdf\n", - "Found 1 chains: {'A': 'GMTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKE'}\n", - "Ligand SMILES: Cn1cnc(Cn2ccc3ccc(C[NH2+]CC4NC5CCCCC5C4[C@H]4NC(=O)c5ccc(O)cc54)cc32)c1\n", - "JSON saved: json_inputs/6gj8.json\n", - "Processing 6mo2, PDB file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo2/6mo2_protein_processed.pdb, SDF file: /mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/6mo2/6mo2_ligand.sdf\n", - "Found 1 chains: {'A': 'MADLELERAADVRWEEQAEISGSSLEDGAYRIKQKGILGYSQIGAGVYKEGTFHTMWHVTRGAVLMHKGKRIEPSWADVKKDLISYGGGWKLEGEWKEGEEVQVLALEPGKNPRAVQTKPGLFKTNTGTIGAVSLDFSPGTSGSPIVDKKGKVVGLYGIANTEK'}\n", - "Ligand SMILES: [NH3+]Cc1ccc(-c2ncc(OCC3CC[NH2+]CC3)nc2-c2ccc(C3CNNC3)cc2)cc1\n", - "JSON saved: json_inputs/6mo2.json\n", - "\n", - "Total processed: 363\n", - "With ligands: 363\n", - "Without ligands: 0\n" - ] - } - ], - "source": [ - "import os\n", - "import json\n", - "from Bio.PDB import PDBParser\n", - "from Bio.Data import IUPACData\n", - "from rdkit import Chem\n", - "import datamol as dm\n", - "from pathlib import Path\n", - "\n", - "dm.disable_rdkit_log()\n", - "\n", - "def extract_all_chains_from_pdb(pdb_path: str):\n", - " parser = PDBParser(QUIET=True)\n", - " structure = parser.get_structure(\"struct\", pdb_path)\n", - " three_to_one = IUPACData.protein_letters_3to1\n", - " chain_dict = {}\n", - " for model in structure:\n", - " for chain in model:\n", - " seq_list = []\n", - " for residue in chain.get_residues():\n", - " if residue.get_id()[0] == \" \":\n", - " r = residue.get_resname().strip().upper()\n", - " aa = three_to_one.get(r.capitalize(), \"X\")\n", - " seq_list.append(aa)\n", - " chain_dict[chain.id] = \"\".join(seq_list)\n", - " break\n", - " return chain_dict\n", - "\n", - "def get_ligand_smiles(sdf_path: str) -> str:\n", - " suppl = Chem.SDMolSupplier(str(sdf_path), sanitize=False)\n", - " for m in suppl:\n", - " if m is None:\n", - " continue\n", - " try:\n", - " Chem.SanitizeMol(m)\n", - " except:\n", - " pass\n", - " raw_smiles = Chem.MolToSmiles(m, isomericSmiles=True)\n", - " mol = dm.to_mol(raw_smiles, ordered=True)\n", - " mol = dm.fix_mol(mol)\n", - " mol = dm.sanitize_mol(mol, sanifix=True, charge_neutral=False)\n", - " if mol is None:\n", - " continue\n", - " try:\n", - " mol = dm.standardize_mol(\n", - " mol,\n", - " disconnect_metals=False,\n", - " normalize=True,\n", - " reionize=True,\n", - " uncharge=False,\n", - " stereo=True,\n", - " )\n", - " except:\n", - " continue\n", - " return dm.to_smiles(mol)\n", - " return \"\"\n", - "\n", - "pdb_list_file = Path(\"/mnt/ligandpro/data/docking_hack/nikolenko_calc/timesplit_test_calc/timesplit_test\")\n", - "base_dir = Path(\"/mnt/ligandpro/data/talgat/flowdock_data/PDBBind_processed/\")\n", - "json_dir = Path(\"json_inputs\")\n", - "os.makedirs(json_dir, exist_ok=True)\n", - "\n", - "with open(pdb_list_file, \"r\") as f:\n", - " pdb_ids = [line.strip() for line in f if line.strip()]\n", - "\n", - "ligand_count = 0\n", - "no_ligand_count = 0\n", - "\n", - "for pdb_id in pdb_ids:\n", - " pdb_dir = base_dir / pdb_id\n", - " pdb_file = pdb_dir / f\"{pdb_id}_protein_processed.pdb\"\n", - " sdf_file = pdb_dir / f\"{pdb_id}_ligand.sdf\"\n", - " print(f\"Processing {pdb_id}, PDB file: {pdb_file}, SDF file: {sdf_file}\")\n", - " if not pdb_file.exists():\n", - " print(f\"PDB file not found: {pdb_file}\")\n", - " continue\n", - " if not sdf_file.exists():\n", - " print(f\"SDF file not found: {sdf_file}\")\n", - " no_ligand_count += 1\n", - " continue\n", - "\n", - " chain_sequences = extract_all_chains_from_pdb(str(pdb_file))\n", - " print(f\"Found {len(chain_sequences)} chains: {chain_sequences}\")\n", - " ligand_smiles = get_ligand_smiles(str(sdf_file))\n", - " print(f\"Ligand SMILES: {ligand_smiles or 'no ligand'}\")\n", - "\n", - " seqs = []\n", - " for chain_id, seq in chain_sequences.items():\n", - " seqs.append({\"protein\": {\"id\": chain_id, \"sequence\": seq}})\n", - " seqs.append({\"ligand\": {\"id\": \"L\", \"smiles\": ligand_smiles}})\n", - "\n", - " data = {\n", - " \"name\": pdb_id,\n", - " \"modelSeeds\": [0],\n", - " \"sequences\": seqs,\n", - " \"dialect\": \"alphafold3\",\n", - " \"version\": 2\n", - " }\n", - "\n", - " out_json = json_dir / f\"{pdb_id}.json\"\n", - " with open(out_json, \"w\") as o:\n", - " json.dump(data, o, indent=2)\n", - " print(f\"JSON saved: {out_json}\")\n", - " ligand_count += 1\n", - "\n", - "print(f\"\\nTotal processed: {len(pdb_ids)}\")\n", - "print(f\"With ligands: {ligand_count}\")\n", - "print(f\"Without ligands: {no_ligand_count}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "docker run -it --gpus all --rm \\\n", - " -e DB_DIR=/root/public_databases \\\n", - " --volume /mnt/ligandpro/soft/protein/alphafold3/infer_input:/root/af_input \\\n", - " --volume /mnt/ligandpro/soft/protein/alphafold3/infer_output:/root/af_output \\\n", - " --volume /mnt/ligandpro/soft/protein/alphafold3/models:/root/models \\\n", - " --volume /mnt/ligandpro/db/AF3:/root/public_databases \\\n", - " alphafold3 \\\n", - " python run_alphafold.py \\\n", - " --json_path=/root/af_input/1hg0_1_SIN_1.json \\\n", - " --model_dir=/root/models \\\n", - " --output_dir=/root/af_output\n", - "\n" - ] - } - ], - "source": [ - "docker run -it --rm \\\n", - " --gpus \"device=3\" \\\n", - " -e DB_DIR=/root/public_databases \\\n", - " --volume /mnt/ligandpro/data/DockGen/json_inputs_template:/root/af_input \\\n", - " --volume /mnt/ligandpro/soft/protein/alphafold3/infer_output:/root/af_output \\\n", - " --volume /mnt/ligandpro/soft/protein/alphafold3/models:/root/models \\\n", - " --volume /mnt/ligandpro/db/AF3:/root/public_databases \\\n", - " alphafold3 \\\n", - " python run_alphafold.py \\\n", - " --json_path=/root/af_input/1hg0_1_SIN_1.json \\\n", - " --model_dir=/root/models \\\n", - " --output_dir=/root/af_output \\\n", - " --jackhmmer_n_cpu=16 \\\n", - " --nhmmer_n_cpu=16\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "lpce", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.15" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scripts/RMSD_2chain.ipynb b/scripts/RMSD_2chain.ipynb deleted file mode 100644 index aeabdf6..0000000 --- a/scripts/RMSD_2chain.ipynb +++ /dev/null @@ -1,569 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "666e1eb2e9e24d328d77dbacfe70d476", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import os\n", - "import subprocess\n", - "import shutil\n", - "import numpy as np\n", - "import pandas as pd\n", - "from rdkit import Chem\n", - "from Bio.PDB import PDBParser, MMCIFParser, PDBIO, Select\n", - "import nglview as nv\n", - "import signal\n", - "from contextlib import contextmanager\n", - "from spyrmsd import graph, molecule, qcp, utils\n", - "from tqdm import tqdm\n", - "from joblib import Parallel, delayed\n", - "import pymol\n", - "from pymol import cmd\n", - "\n", - "import torch\n", - "# Запуск PyMOL в безграфическом режиме\n", - "pymol.finish_launching(['pymol','-qc'])\n", - "cmd.delete(\"all\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Ограничение времени для длительных вычислений\n", - "class TimeoutException(Exception):\n", - " pass\n", - "\n", - "@contextmanager\n", - "def time_limit(seconds):\n", - " def signal_handler(signum, frame):\n", - " raise TimeoutException(\"Timed out!\")\n", - " signal.signal(signal.SIGALRM, signal_handler)\n", - " signal.alarm(seconds)\n", - " try:\n", - " yield\n", - " finally:\n", - " signal.alarm(0)\n", - "\n", - "def compute_rmsd_simple(c1, c2):\n", - " return np.sqrt(np.sum((c1 - c2)**2) / c1.shape[0])\n", - "\n", - "def _rmsd_isomorphic_core(coords1, coords2, aprops1, aprops2, am1, am2):\n", - " assert coords1.shape == coords2.shape\n", - " n = coords1.shape[0]\n", - " G1 = graph.graph_from_adjacency_matrix(am1, aprops1)\n", - " G2 = graph.graph_from_adjacency_matrix(am2, aprops2)\n", - " isoms = graph.match_graphs(G1, G2)\n", - " min_r = np.inf\n", - " for idx1, idx2 in isoms:\n", - " r = np.sum((coords1[idx1] - coords2[idx2])**2)\n", - " if r < min_r:\n", - " min_r = r\n", - " return np.sqrt(min_r / n)\n", - "\n", - "def symmrmsd(coordsref, coords, apropsref, aprops, amref, am, return_permutation=False):\n", - " return _rmsd_isomorphic_core(coordsref, coords, apropsref, aprops, amref, am)\n", - "\n", - "def get_symmetry_rmsd(mol, coords1, coords2, mol2=None, return_permutation=False):\n", - " # Если число атомов не совпадает, используем fallback на compute_rmsd_simple.\n", - " if coords1.shape != coords2.shape:\n", - " print(\"Warning: число атомов в лигандах не совпадает, для расчёта RMSD берётся только пересечение по числу атомов (fallback на compute_rmsd_simple).\")\n", - " n = min(coords1.shape[0], coords2.shape[0])\n", - " return compute_rmsd_simple(coords1[:n], coords2[:n])\n", - " with time_limit(10):\n", - " m1 = molecule.Molecule.from_rdkit(mol)\n", - " if mol2:\n", - " m2 = molecule.Molecule.from_rdkit(mol2)\n", - " return symmrmsd(coords1, coords2, m1.atomicnums, m2.atomicnums,\n", - " m1.adjacency_matrix, m2.adjacency_matrix,\n", - " return_permutation=return_permutation)\n", - " else:\n", - " return symmrmsd(coords1, coords2, m1.atomicnums, m1.atomicnums,\n", - " m1.adjacency_matrix, m1.adjacency_matrix,\n", - " return_permutation=return_permutation)\n", - "\n", - "def parse_protein(file_path):\n", - " if file_path.endswith(\".pdb\"):\n", - " return PDBParser(QUIET=True).get_structure(\"prot\", file_path)\n", - " elif file_path.endswith(\".cif\"):\n", - " return MMCIFParser(QUIET=True).get_structure(\"prot\", file_path)\n", - " else:\n", - " raise ValueError(\"Unsupported protein format\")\n", - "\n", - "def parse_ligand(file_path):\n", - " mol = Chem.MolFromPDBFile(file_path, removeHs=False)\n", - " if mol is None:\n", - " raise ValueError(\"Could not parse ligand file\")\n", - " return mol\n", - "\n", - "def extract_ligand(input_pdb, output_ligand_pdb, ligand_resname=\"LIG\"):\n", - " parser = PDBParser(QUIET=True)\n", - " structure = parser.get_structure(\"aligned\", input_pdb)\n", - " class LigandSelect(Select):\n", - " def accept_residue(self, residue):\n", - " return residue.get_resname().strip() == ligand_resname\n", - " io = PDBIO()\n", - " io.set_structure(structure)\n", - " io.save(output_ligand_pdb, LigandSelect())\n", - "\n", - "def align_proteins_pymol(ref_protein_path, pred_complex_path, aligned_complex_file):\n", - " cmd.delete(\"all\")\n", - " cmd.load(ref_protein_path, \"ref_protein\")\n", - " cmd.load(pred_complex_path, \"predicted_complex\")\n", - " # Выравнивание по атомам CA\n", - " alignment_result = cmd.align(\"predicted_complex and name CA\", \"ref_protein and name CA\")\n", - " cmd.save(aligned_complex_file, \"predicted_complex\")\n", - " return alignment_result[0]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import subprocess\n", - "import shutil\n", - "import torch\n", - "import pandas as pd\n", - "from tqdm import tqdm\n", - "from joblib import Parallel, delayed\n", - "# Импорт модулей для PyMOL, rdkit и других необходимых операций (например, Chem, TimeoutException)\n", - "\n", - "def process_prediction(pred_complex_path, output_base):\n", - " try:\n", - " # Определяем reference файлы по имени папки предсказания (без учёта регистра)\n", - " processed_base = \"/mnt/ligandpro/data/DockGen/processed_files\"\n", - " pred_folder = os.path.basename(os.path.dirname(pred_complex_path))\n", - " target_folder = None\n", - " for d in os.listdir(processed_base):\n", - " if d.lower() == pred_folder.lower():\n", - " target_folder = os.path.join(processed_base, d)\n", - " break\n", - " if target_folder is None:\n", - " raise ValueError(\"Нет matching processed folder для \" + pred_folder)\n", - " protein_file = None\n", - " ligand_file = None\n", - " for f in os.listdir(target_folder):\n", - " lf = f.lower()\n", - " if \"protein\" in lf:\n", - " protein_file = os.path.join(target_folder, f)\n", - " if lf.endswith(\"_ligand.pdb\") and lf == (pred_folder.lower() + \"_ligand.pdb\"):\n", - " ligand_file = os.path.join(target_folder, f)\n", - " if protein_file is None or ligand_file is None:\n", - " raise ValueError(\"Protein или ligand файл не найден в \" + target_folder)\n", - " ref_protein_path = protein_file\n", - " ref_ligand_path = ligand_file\n", - "\n", - " # Если файл предсказанного комплекса в формате CIF, конвертируем в PDB (вывод скрыт)\n", - " if pred_complex_path.endswith(\".cif\"):\n", - " output_folder = os.path.join(output_base, pred_folder)\n", - " os.makedirs(output_folder, exist_ok=True)\n", - " converted_file = os.path.join(output_folder, \"pred_complex_converted.pdb\")\n", - " subprocess.run([\"obabel\", pred_complex_path, \"-O\", converted_file],\n", - " check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n", - " pred_complex_path = converted_file\n", - "\n", - " output_dir = os.path.join(output_base, pred_folder)\n", - " os.makedirs(output_dir, exist_ok=True)\n", - " predicted_complex_file = os.path.join(output_dir, \"predicted_complex.pdb\")\n", - " shutil.copy(pred_complex_path, predicted_complex_file)\n", - "\n", - " # Выравнивание через PyMOL\n", - " aligned_complex_file = os.path.join(output_dir, \"predicted_complex_aligned.pdb\")\n", - " protein_rms = align_proteins_pymol(ref_protein_path, predicted_complex_file, aligned_complex_file)\n", - "\n", - " # Извлечение лиганда\n", - " predicted_ligand_aligned_pdb = os.path.join(output_dir, \"predicted_ligand_aligned.pdb\")\n", - " extract_ligand(aligned_complex_file, predicted_ligand_aligned_pdb, ligand_resname=\"LIG\")\n", - "\n", - " # Расчёт RMSD для лиганда:\n", - " # Удаляем водороды из reference лиганда перед вычислением\n", - " ref_lig_rdkit = parse_ligand(ref_ligand_path)\n", - " ref_lig_rdkit = Chem.RemoveHs(ref_lig_rdkit)\n", - " pred_lig_rdkit = parse_ligand(predicted_ligand_aligned_pdb)\n", - " ref_conf = ref_lig_rdkit.GetConformer()\n", - " pred_conf = pred_lig_rdkit.GetConformer()\n", - " ref_coords = ref_conf.GetPositions()\n", - " pred_coords = pred_conf.GetPositions()\n", - " if ref_coords.shape != pred_coords.shape:\n", - " print(f\"Warning: число атомов в лигандах не совпадает для файла {pred_folder}. Используется fallback compute_rmsd_simple.\")\n", - " try:\n", - " ligand_rmsd = get_symmetry_rmsd(ref_lig_rdkit, ref_coords, pred_coords)\n", - " except TimeoutException:\n", - " ligand_rmsd = compute_rmsd_simple(ref_coords, pred_coords)\n", - "\n", - " # Вычисление ошибки сдвига (translational error)\n", - " tr_error = torch.linalg.norm(\n", - " torch.tensor(ref_coords.mean(axis=0)) - torch.tensor(pred_coords.mean(axis=0))\n", - " ).item()\n", - "\n", - " # Копируем reference файлы в output_dir\n", - " shutil.copy(ref_protein_path, os.path.join(output_dir, \"ref_protein.pdb\"))\n", - " shutil.copy(ref_ligand_path, os.path.join(output_dir, \"ref_ligand.pdb\"))\n", - "\n", - " return {\"id\": pred_folder,\n", - " \"pred_complex\": predicted_complex_file,\n", - " \"ligand_rmsd\": ligand_rmsd,\n", - " \"protein_rms\": protein_rms,\n", - " \"tr_error\": tr_error,\n", - " \"output_dir\": output_dir,\n", - " \"error\": None}\n", - " except Exception as e:\n", - " print(f\"Error processing {pred_complex_path}: {e}\")\n", - " return {\"id\": os.path.basename(os.path.dirname(pred_complex_path)),\n", - " \"pred_complex\": None,\n", - " \"ligand_rmsd\": None,\n", - " \"protein_rms\": None,\n", - " \"tr_error\": None,\n", - " \"output_dir\": None,\n", - " \"error\": str(e)}\n", - "\n", - "def process_all_predictions(output_base):\n", - " infer_base = \"/mnt/ligandpro/data/DockGen/af3_calc/infer_output_2chains\"\n", - " prediction_paths = []\n", - " for d in os.listdir(infer_base):\n", - " pred_dir = os.path.join(infer_base, d)\n", - " if os.path.isdir(pred_dir):\n", - " for f in os.listdir(pred_dir):\n", - " if f.endswith(\"_model.cif\") or f.endswith(\"_model.pdb\"):\n", - " prediction_paths.append(os.path.join(pred_dir, f))\n", - " break\n", - " results = Parallel(n_jobs=16)(\n", - " delayed(process_prediction)(pred_path, output_base)\n", - " for pred_path in tqdm(prediction_paths, desc=\"Processing predictions\")\n", - " )\n", - " return pd.DataFrame(results)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Processing predictions: 0%| | 0/149 [00:00\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idpred_complexligand_rmsdprotein_rmstr_erroroutput_direrror
04o0d_1_gly_3./results_2chains/4o0d_1_gly_3/predicted_compl...1.3652080.2526890.414760./results_2chains/4o0d_1_gly_3None
12vfu_1_mtl_0./results_2chains/2vfu_1_mtl_0/predicted_compl...1.7351950.3563320.772733./results_2chains/2vfu_1_mtl_0None
23ub7_1_acm_1./results_2chains/3ub7_1_acm_1/predicted_compl...1.9324320.2093790.250937./results_2chains/3ub7_1_acm_1None
32wwc_1_cht_2./results_2chains/2wwc_1_cht_2/predicted_compl...28.4575751.27996928.355644./results_2chains/2wwc_1_cht_2None
46a72_1_9ux_0./results_2chains/6a72_1_9ux_0/predicted_compl...9.40417410.7913939.047195./results_2chains/6a72_1_9ux_0None
........................
1445k45_2_glu_1./results_2chains/5k45_2_glu_1/predicted_compl...36.5365420.14845236.424001./results_2chains/5k45_2_glu_1None
1452vdf_1_oct_0./results_2chains/2vdf_1_oct_0/predicted_compl...0.9866440.2668860.490189./results_2chains/2vdf_1_oct_0None
1466uqy_2_at3_0./results_2chains/6uqy_2_at3_0/predicted_compl...2.9859310.1284090.205929./results_2chains/6uqy_2_at3_0None
1471pj2_1_fum_0./results_2chains/1pj2_1_fum_0/predicted_compl...30.5625443.20535630.448212./results_2chains/1pj2_1_fum_0None
1484mo2_2_fda_0./results_2chains/4mo2_2_fda_0/predicted_compl...11.6159420.3203510.126984./results_2chains/4mo2_2_fda_0None
\n", - "

149 rows × 7 columns

\n", - "" - ], - "text/plain": [ - " id pred_complex \\\n", - "0 4o0d_1_gly_3 ./results_2chains/4o0d_1_gly_3/predicted_compl... \n", - "1 2vfu_1_mtl_0 ./results_2chains/2vfu_1_mtl_0/predicted_compl... \n", - "2 3ub7_1_acm_1 ./results_2chains/3ub7_1_acm_1/predicted_compl... \n", - "3 2wwc_1_cht_2 ./results_2chains/2wwc_1_cht_2/predicted_compl... \n", - "4 6a72_1_9ux_0 ./results_2chains/6a72_1_9ux_0/predicted_compl... \n", - ".. ... ... \n", - "144 5k45_2_glu_1 ./results_2chains/5k45_2_glu_1/predicted_compl... \n", - "145 2vdf_1_oct_0 ./results_2chains/2vdf_1_oct_0/predicted_compl... \n", - "146 6uqy_2_at3_0 ./results_2chains/6uqy_2_at3_0/predicted_compl... \n", - "147 1pj2_1_fum_0 ./results_2chains/1pj2_1_fum_0/predicted_compl... \n", - "148 4mo2_2_fda_0 ./results_2chains/4mo2_2_fda_0/predicted_compl... \n", - "\n", - " ligand_rmsd protein_rms tr_error output_dir error \n", - "0 1.365208 0.252689 0.414760 ./results_2chains/4o0d_1_gly_3 None \n", - "1 1.735195 0.356332 0.772733 ./results_2chains/2vfu_1_mtl_0 None \n", - "2 1.932432 0.209379 0.250937 ./results_2chains/3ub7_1_acm_1 None \n", - "3 28.457575 1.279969 28.355644 ./results_2chains/2wwc_1_cht_2 None \n", - "4 9.404174 10.791393 9.047195 ./results_2chains/6a72_1_9ux_0 None \n", - ".. ... ... ... ... ... \n", - "144 36.536542 0.148452 36.424001 ./results_2chains/5k45_2_glu_1 None \n", - "145 0.986644 0.266886 0.490189 ./results_2chains/2vdf_1_oct_0 None \n", - "146 2.985931 0.128409 0.205929 ./results_2chains/6uqy_2_at3_0 None \n", - "147 30.562544 3.205356 30.448212 ./results_2chains/1pj2_1_fum_0 None \n", - "148 11.615942 0.320351 0.126984 ./results_2chains/4mo2_2_fda_0 None \n", - "\n", - "[149 rows x 7 columns]" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "output_base = \"./results_2chains\"\n", - "os.makedirs(output_base, exist_ok=True)\n", - "\n", - "df = process_all_predictions(output_base)\n", - "df.to_csv(os.path.join(output_base, \"results.csv\"), index=False)\n", - "display(df)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Percentage of ligand_rmsd values less than 2 Angstrom: 6.08%\n", - "Percentage of ligand_rmsd values less than 2 (for protein_rms <= 2): 7.03%\n", - "Mean translational error: 11.59\n", - "Median translational error: 1.20\n" - ] - } - ], - "source": [ - "# Calculate the percentage of ligand_rmsd values that are less than 2 Angstrom\n", - "valid_values = df['ligand_rmsd'].dropna()\n", - "percentage = (valid_values < 2).mean() * 100\n", - "print(f\"Percentage of ligand_rmsd values less than 2 Angstrom: {percentage:.2f}%\")\n", - "\n", - "# Filter the DataFrame for records with protein_rms <= 2\n", - "df_filtered = df[df['protein_rms'] <= 2]\n", - "\n", - "# Calculate the percentage of ligand_rmsd values less than 2 Angstrom among the filtered records\n", - "valid_values_filtered = df_filtered['ligand_rmsd'].dropna()\n", - "percentage_filtered = (valid_values_filtered < 2).mean() * 100\n", - "print(f\"Percentage of ligand_rmsd values less than 2 (for protein_rms <= 2): {percentage_filtered:.2f}%\")\n", - "\n", - "# Calculate the mean and median translational error with two decimal places formatting\n", - "mean_tr_error = df['tr_error'].mean()\n", - "median_tr_error = df['tr_error'].median()\n", - "print(f\"Mean translational error: {mean_tr_error:.2f}\")\n", - "print(f\"Median translational error: {median_tr_error:.2f}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pymol", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.16" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scripts/RMSD_boltz.ipynb b/scripts/RMSD_boltz.ipynb deleted file mode 100644 index bc71cc9..0000000 --- a/scripts/RMSD_boltz.ipynb +++ /dev/null @@ -1,576 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d87fcf7dc3244f2ca7e3e6968734d37e", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import os\n", - "import subprocess\n", - "import shutil\n", - "import numpy as np\n", - "import pandas as pd\n", - "from rdkit import Chem\n", - "from Bio.PDB import PDBParser, MMCIFParser, PDBIO, Select\n", - "import nglview as nv\n", - "import signal\n", - "from contextlib import contextmanager\n", - "from spyrmsd import graph, molecule, qcp, utils\n", - "from tqdm import tqdm\n", - "from joblib import Parallel, delayed\n", - "import pymol\n", - "from pymol import cmd\n", - "\n", - "import torch\n", - "# Запуск PyMOL в безграфическом режиме\n", - "\n", - "pymol.finish_launching(['pymol','-qc'])\n", - "cmd.delete(\"all\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Ограничение времени для длительных вычислений\n", - "class TimeoutException(Exception):\n", - " pass\n", - "\n", - "@contextmanager\n", - "def time_limit(seconds):\n", - " def signal_handler(signum, frame):\n", - " raise TimeoutException(\"Timed out!\")\n", - " signal.signal(signal.SIGALRM, signal_handler)\n", - " signal.alarm(seconds)\n", - " try:\n", - " yield\n", - " finally:\n", - " signal.alarm(0)\n", - "\n", - "def compute_rmsd_simple(c1, c2):\n", - " return np.sqrt(np.sum((c1 - c2)**2) / c1.shape[0])\n", - "\n", - "def _rmsd_isomorphic_core(coords1, coords2, aprops1, aprops2, am1, am2):\n", - " assert coords1.shape == coords2.shape\n", - " n = coords1.shape[0]\n", - " G1 = graph.graph_from_adjacency_matrix(am1, aprops1)\n", - " G2 = graph.graph_from_adjacency_matrix(am2, aprops2)\n", - " isoms = graph.match_graphs(G1, G2)\n", - " min_r = np.inf\n", - " for idx1, idx2 in isoms:\n", - " r = np.sum((coords1[idx1] - coords2[idx2])**2)\n", - " if r < min_r:\n", - " min_r = r\n", - " return np.sqrt(min_r / n)\n", - "\n", - "def symmrmsd(coordsref, coords, apropsref, aprops, amref, am, return_permutation=False):\n", - " return _rmsd_isomorphic_core(coordsref, coords, apropsref, aprops, amref, am)\n", - "\n", - "def get_symmetry_rmsd(mol, coords1, coords2, mol2=None, return_permutation=False):\n", - " # Если число атомов не совпадает, используем fallback на compute_rmsd_simple.\n", - " if coords1.shape != coords2.shape:\n", - " print(\"Warning: число атомов в лигандах не совпадает, для расчёта RMSD берётся только пересечение по числу атомов (fallback на compute_rmsd_simple).\")\n", - " n = min(coords1.shape[0], coords2.shape[0])\n", - " return compute_rmsd_simple(coords1[:n], coords2[:n])\n", - " with time_limit(10):\n", - " m1 = molecule.Molecule.from_rdkit(mol)\n", - " if mol2:\n", - " m2 = molecule.Molecule.from_rdkit(mol2)\n", - " return symmrmsd(coords1, coords2, m1.atomicnums, m2.atomicnums,\n", - " m1.adjacency_matrix, m2.adjacency_matrix,\n", - " return_permutation=return_permutation)\n", - " else:\n", - " return symmrmsd(coords1, coords2, m1.atomicnums, m1.atomicnums,\n", - " m1.adjacency_matrix, m1.adjacency_matrix,\n", - " return_permutation=return_permutation)\n", - "\n", - "def parse_protein(file_path):\n", - " if file_path.endswith(\".pdb\"):\n", - " return PDBParser(QUIET=True).get_structure(\"prot\", file_path)\n", - " elif file_path.endswith(\".cif\"):\n", - " return MMCIFParser(QUIET=True).get_structure(\"prot\", file_path)\n", - " else:\n", - " raise ValueError(\"Unsupported protein format\")\n", - "\n", - "def parse_ligand(file_path):\n", - " mol = Chem.MolFromPDBFile(file_path, removeHs=False)\n", - " if mol is None:\n", - " raise ValueError(\"Could not parse ligand file\")\n", - " return mol\n", - "\n", - "def extract_ligand(input_pdb, output_ligand_pdb, ligand_resname=\"LIG\"):\n", - " parser = PDBParser(QUIET=True)\n", - " structure = parser.get_structure(\"aligned\", input_pdb)\n", - " class LigandSelect(Select):\n", - " def accept_residue(self, residue):\n", - " return residue.get_resname().strip() == ligand_resname\n", - " io = PDBIO()\n", - " io.set_structure(structure)\n", - " io.save(output_ligand_pdb, LigandSelect())\n", - "\n", - "def align_proteins_pymol(ref_protein_path, pred_complex_path, aligned_complex_file):\n", - " cmd.delete(\"all\")\n", - " cmd.load(ref_protein_path, \"ref_protein\")\n", - " cmd.load(pred_complex_path, \"predicted_complex\")\n", - " # Выравнивание по атомам CA\n", - " alignment_result = cmd.align(\"predicted_complex and name CA\", \"ref_protein and name CA\")\n", - " cmd.save(aligned_complex_file, \"predicted_complex\")\n", - " return alignment_result[0]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "def process_prediction(pred_complex_path, output_base):\n", - " try:\n", - " # Определяем reference файлы по имени папки предсказания (без учёта регистра)\n", - " processed_base = \"/mnt/ligandpro/data/DockGen/processed_files\"\n", - " pred_folder = os.path.basename(os.path.dirname(pred_complex_path))\n", - " target_folder = None\n", - " for d in os.listdir(processed_base):\n", - " if d.lower() == pred_folder.lower():\n", - " target_folder = os.path.join(processed_base, d)\n", - " break\n", - " if target_folder is None:\n", - " raise ValueError(\"Нет matching processed folder для \" + pred_folder)\n", - " protein_file = None\n", - " ligand_file = None\n", - " for f in os.listdir(target_folder):\n", - " lf = f.lower()\n", - " if \"protein\" in lf:\n", - " protein_file = os.path.join(target_folder, f)\n", - " if lf.endswith(\"_ligand.pdb\") and lf == (pred_folder.lower() + \"_ligand.pdb\"):\n", - " ligand_file = os.path.join(target_folder, f)\n", - " if protein_file is None or ligand_file is None:\n", - " raise ValueError(\"Protein или ligand файл не найден в \" + target_folder)\n", - " ref_protein_path = protein_file\n", - " ref_ligand_path = ligand_file\n", - "\n", - " # Если файл предсказанного комплекса в формате CIF, конвертируем в PDB (вывод скрыт)\n", - " if pred_complex_path.endswith(\".cif\"):\n", - " output_folder = os.path.join(output_base, pred_folder)\n", - " os.makedirs(output_folder, exist_ok=True)\n", - " converted_file = os.path.join(output_folder, \"pred_complex_converted.pdb\")\n", - " subprocess.run([\"obabel\", pred_complex_path, \"-O\", converted_file],\n", - " check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n", - " pred_complex_path = converted_file\n", - "\n", - " output_dir = os.path.join(output_base, pred_folder)\n", - " os.makedirs(output_dir, exist_ok=True)\n", - " predicted_complex_file = os.path.join(output_dir, \"predicted_complex.pdb\")\n", - " shutil.copy(pred_complex_path, predicted_complex_file)\n", - "\n", - " # Выравнивание через PyMOL\n", - " aligned_complex_file = os.path.join(output_dir, \"predicted_complex_aligned.pdb\")\n", - " protein_rms = align_proteins_pymol(ref_protein_path, predicted_complex_file, aligned_complex_file)\n", - "\n", - " # Извлечение лиганда\n", - " predicted_ligand_aligned_pdb = os.path.join(output_dir, \"predicted_ligand_aligned.pdb\")\n", - " extract_ligand(aligned_complex_file, predicted_ligand_aligned_pdb, ligand_resname=\"LIG\")\n", - "\n", - " # Расчёт RMSD для лиганда:\n", - " # Удаляем водороды из reference лиганда перед вычислением\n", - " ref_lig_rdkit = parse_ligand(ref_ligand_path)\n", - " ref_lig_rdkit = Chem.RemoveHs(ref_lig_rdkit)\n", - " pred_lig_rdkit = parse_ligand(predicted_ligand_aligned_pdb)\n", - " ref_conf = ref_lig_rdkit.GetConformer()\n", - " pred_conf = pred_lig_rdkit.GetConformer()\n", - " ref_coords = ref_conf.GetPositions()\n", - " pred_coords = pred_conf.GetPositions()\n", - " if ref_coords.shape != pred_coords.shape:\n", - " print(f\"Warning: число атомов в лигандах не совпадает для файла {pred_folder}. Используется fallback compute_rmsd_simple.\")\n", - " try:\n", - " ligand_rmsd = get_symmetry_rmsd(ref_lig_rdkit, ref_coords, pred_coords)\n", - " except TimeoutException:\n", - " ligand_rmsd = compute_rmsd_simple(ref_coords, pred_coords)\n", - "\n", - " # Вычисление ошибки сдвига (translational error)\n", - " tr_error = torch.linalg.norm(\n", - " torch.tensor(ref_coords.mean(axis=0)) - torch.tensor(pred_coords.mean(axis=0))\n", - " ).item()\n", - "\n", - " # Копируем reference файлы в output_dir\n", - " shutil.copy(ref_protein_path, os.path.join(output_dir, \"ref_protein.pdb\"))\n", - " shutil.copy(ref_ligand_path, os.path.join(output_dir, \"ref_ligand.pdb\"))\n", - "\n", - " return {\"id\": pred_folder,\n", - " \"pred_complex\": predicted_complex_file,\n", - " \"ligand_rmsd\": ligand_rmsd,\n", - " \"protein_rms\": protein_rms,\n", - " \"tr_error\": tr_error,\n", - " \"output_dir\": output_dir,\n", - " \"error\": None}\n", - " except Exception as e:\n", - " print(f\"Error processing {pred_complex_path}: {e}\")\n", - " return {\"id\": os.path.basename(os.path.dirname(pred_complex_path)),\n", - " \"pred_complex\": None,\n", - " \"ligand_rmsd\": None,\n", - " \"protein_rms\": None,\n", - " \"tr_error\": None,\n", - " \"output_dir\": None,\n", - " \"error\": str(e)}\n", - "\n", - "def process_all_predictions(output_base):\n", - " infer_base = \"/home/nikolenko/work/ligandpro/data/DockGen/boltz_calc/boltz_results_boltz_yaml_inputs/predictions\"\n", - " prediction_paths = []\n", - " for d in os.listdir(infer_base):\n", - " pred_dir = os.path.join(infer_base, d)\n", - " if os.path.isdir(pred_dir):\n", - " for f in os.listdir(pred_dir):\n", - " if \"_model_\" in f and (f.endswith(\".cif\") or f.endswith(\".pdb\")):\n", - " prediction_paths.append(os.path.join(pred_dir, f))\n", - " break\n", - "\n", - " results = Parallel(n_jobs=16)(\n", - " delayed(process_prediction)(pred_path, output_base)\n", - " for pred_path in tqdm(prediction_paths, desc=\"Processing predictions\")\n", - " )\n", - " return pd.DataFrame(results)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Processing predictions: 0%| | 0/187 [00:00 -1\n", - "----------\n", - "Stacktrace:\n", - "----------\n", - "****\n", - "\n", - "Processing predictions: 26%|██▌ | 48/187 [00:01<00:05, 26.95it/s]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Error processing ./results/6a72_1_9UX_0/pred_complex_converted.pdb: Could not parse ligand file\n", - "Error processing ./results/6a71_1_9UX_0/pred_complex_converted.pdb: Could not parse ligand file\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[03:30:21] \n", - "\n", - "****\n", - "Post-condition Violation\n", - "Element 'X' not found\n", - "Violation occurred on line 93 in file /project/build/temp.linux-x86_64-cpython-310/rdkit/Code/GraphMol/PeriodicTable.h\n", - "Failed Expression: anum > -1\n", - "----------\n", - "Stacktrace:\n", - "----------\n", - "****\n", - "\n", - "Processing predictions: 100%|██████████| 187/187 [00:03<00:00, 53.86it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ExecutiveAlign: invalid selections for alignment.\n", - "Error processing ./results/6o6y_1_ACK_0/pred_complex_converted.pdb: Error: \n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idpred_complexligand_rmsdprotein_rmstr_erroroutput_direrror
01i8t_1_FAD_1./results/1i8t_1_FAD_1/predicted_complex.pdb9.9780260.6613750.327603./results/1i8t_1_FAD_1None
11uf7_1_CDV_0./results/1uf7_1_CDV_0/predicted_complex.pdb2.6743610.3177900.555286./results/1uf7_1_CDV_0None
22hs3_1_FGR_0./results/2hs3_1_FGR_0/predicted_complex.pdb24.5599730.56964424.085094./results/2hs3_1_FGR_0None
32wao_1_BGC-BGC-BGC-BGC-BGC_0./results/2wao_1_BGC-BGC-BGC-BGC-BGC_0/predict...10.6684920.3113671.896751./results/2wao_1_BGC-BGC-BGC-BGC-BGC_0None
43o7j_1_2AL_0./results/3o7j_1_2AL_0/predicted_complex.pdb3.3779930.2449270.076064./results/3o7j_1_2AL_0None
........................
1826ep5_1_ADP_1./results/6ep5_1_ADP_1/predicted_complex.pdb12.73988416.48599811.461635./results/6ep5_1_ADP_1None
1836etf_1_AMP_0./results/6etf_1_AMP_0/predicted_complex.pdb4.7413931.0876360.610967./results/6etf_1_AMP_0None
1843o01_2_DXC_0./results/3o01_2_DXC_0/predicted_complex.pdb18.0638361.11008317.292835./results/3o01_2_DXC_0None
1854bc9_1_CNV-FAD_0./results/4bc9_1_CNV-FAD_0/predicted_complex.pdb39.0116740.48259037.878525./results/4bc9_1_CNV-FAD_0None
1863k8l_1_GLC-GLC-GLC-GLC-GLC_0./results/3k8l_1_GLC-GLC-GLC-GLC-GLC_0/predict...36.0249200.55086434.772615./results/3k8l_1_GLC-GLC-GLC-GLC-GLC_0None
\n", - "

187 rows × 7 columns

\n", - "
" - ], - "text/plain": [ - " id \\\n", - "0 1i8t_1_FAD_1 \n", - "1 1uf7_1_CDV_0 \n", - "2 2hs3_1_FGR_0 \n", - "3 2wao_1_BGC-BGC-BGC-BGC-BGC_0 \n", - "4 3o7j_1_2AL_0 \n", - ".. ... \n", - "182 6ep5_1_ADP_1 \n", - "183 6etf_1_AMP_0 \n", - "184 3o01_2_DXC_0 \n", - "185 4bc9_1_CNV-FAD_0 \n", - "186 3k8l_1_GLC-GLC-GLC-GLC-GLC_0 \n", - "\n", - " pred_complex ligand_rmsd \\\n", - "0 ./results/1i8t_1_FAD_1/predicted_complex.pdb 9.978026 \n", - "1 ./results/1uf7_1_CDV_0/predicted_complex.pdb 2.674361 \n", - "2 ./results/2hs3_1_FGR_0/predicted_complex.pdb 24.559973 \n", - "3 ./results/2wao_1_BGC-BGC-BGC-BGC-BGC_0/predict... 10.668492 \n", - "4 ./results/3o7j_1_2AL_0/predicted_complex.pdb 3.377993 \n", - ".. ... ... \n", - "182 ./results/6ep5_1_ADP_1/predicted_complex.pdb 12.739884 \n", - "183 ./results/6etf_1_AMP_0/predicted_complex.pdb 4.741393 \n", - "184 ./results/3o01_2_DXC_0/predicted_complex.pdb 18.063836 \n", - "185 ./results/4bc9_1_CNV-FAD_0/predicted_complex.pdb 39.011674 \n", - "186 ./results/3k8l_1_GLC-GLC-GLC-GLC-GLC_0/predict... 36.024920 \n", - "\n", - " protein_rms tr_error output_dir error \n", - "0 0.661375 0.327603 ./results/1i8t_1_FAD_1 None \n", - "1 0.317790 0.555286 ./results/1uf7_1_CDV_0 None \n", - "2 0.569644 24.085094 ./results/2hs3_1_FGR_0 None \n", - "3 0.311367 1.896751 ./results/2wao_1_BGC-BGC-BGC-BGC-BGC_0 None \n", - "4 0.244927 0.076064 ./results/3o7j_1_2AL_0 None \n", - ".. ... ... ... ... \n", - "182 16.485998 11.461635 ./results/6ep5_1_ADP_1 None \n", - "183 1.087636 0.610967 ./results/6etf_1_AMP_0 None \n", - "184 1.110083 17.292835 ./results/3o01_2_DXC_0 None \n", - "185 0.482590 37.878525 ./results/4bc9_1_CNV-FAD_0 None \n", - "186 0.550864 34.772615 ./results/3k8l_1_GLC-GLC-GLC-GLC-GLC_0 None \n", - "\n", - "[187 rows x 7 columns]" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "output_base = \"./results\"\n", - "os.makedirs(output_base, exist_ok=True)\n", - "\n", - "df = process_all_predictions(output_base)\n", - "df.to_csv(os.path.join(output_base, \"results.csv\"), index=False)\n", - "display(df)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Percentage of ligand_rmsd values less than 2 Angstrom: 1.09%\n", - "Percentage of ligand_rmsd values less than 2 (for protein_rms <= 2): 1.30%\n" - ] - } - ], - "source": [ - "# Calculate the percentage of ligand_rmsd values that are less than 2 Angstrom\n", - "valid_values = df['ligand_rmsd'].dropna()\n", - "percentage = (valid_values < 2).mean() * 100\n", - "print(f\"Percentage of ligand_rmsd values less than 2 Angstrom: {percentage:.2f}%\")\n", - "\n", - "# Filter the DataFrame for records with protein_rms <= 2\n", - "df_filtered = df[df['protein_rms'] <= 2]\n", - "\n", - "# Calculate the percentage of ligand_rmsd values less than 2 Angstrom among the filtered records\n", - "valid_values_filtered = df_filtered['ligand_rmsd'].dropna()\n", - "percentage_filtered = (valid_values_filtered < 2).mean() * 100\n", - "print(f\"Percentage of ligand_rmsd values less than 2 (for protein_rms <= 2): {percentage_filtered:.2f}%\")\n", - "\n", - "# Calculate the mean and median translational error with two decimal places formatting\n", - "mean_tr_error = df['tr_error'].mean()\n", - "median_tr_error = df['tr_error'].median()\n", - "print(f\"Mean translational error: {mean_tr_error:.2f}\")\n", - "print(f\"Median translational error: {median_tr_error:.2f}\")\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pymol", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.16" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scripts/RMSD_chai.ipynb b/scripts/RMSD_chai.ipynb deleted file mode 100644 index 7988667..0000000 --- a/scripts/RMSD_chai.ipynb +++ /dev/null @@ -1,569 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "3eaf7abf22b645178a22f260082962ec", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import os\n", - "import subprocess\n", - "import shutil\n", - "import numpy as np\n", - "import pandas as pd\n", - "from rdkit import Chem\n", - "from Bio.PDB import PDBParser, MMCIFParser, PDBIO, Select\n", - "import nglview as nv\n", - "import signal\n", - "from contextlib import contextmanager\n", - "from spyrmsd import graph, molecule, qcp, utils\n", - "from tqdm import tqdm\n", - "from joblib import Parallel, delayed\n", - "import pymol\n", - "from pymol import cmd\n", - "\n", - "import torch \n", - "\n", - "# Запуск PyMOL в безграфическом режиме\n", - "pymol.finish_launching(['pymol','-qc'])\n", - "cmd.delete(\"all\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Ограничение времени для длительных вычислений\n", - "class TimeoutException(Exception):\n", - " pass\n", - "\n", - "@contextmanager\n", - "def time_limit(seconds):\n", - " def signal_handler(signum, frame):\n", - " raise TimeoutException(\"Timed out!\")\n", - " signal.signal(signal.SIGALRM, signal_handler)\n", - " signal.alarm(seconds)\n", - " try:\n", - " yield\n", - " finally:\n", - " signal.alarm(0)\n", - "\n", - "def compute_rmsd_simple(c1, c2):\n", - " return np.sqrt(np.sum((c1 - c2)**2) / c1.shape[0])\n", - "\n", - "def _rmsd_isomorphic_core(coords1, coords2, aprops1, aprops2, am1, am2):\n", - " assert coords1.shape == coords2.shape\n", - " n = coords1.shape[0]\n", - " G1 = graph.graph_from_adjacency_matrix(am1, aprops1)\n", - " G2 = graph.graph_from_adjacency_matrix(am2, aprops2)\n", - " isoms = graph.match_graphs(G1, G2)\n", - " min_r = np.inf\n", - " for idx1, idx2 in isoms:\n", - " r = np.sum((coords1[idx1] - coords2[idx2])**2)\n", - " if r < min_r:\n", - " min_r = r\n", - " return np.sqrt(min_r / n)\n", - "\n", - "def symmrmsd(coordsref, coords, apropsref, aprops, amref, am, return_permutation=False):\n", - " return _rmsd_isomorphic_core(coordsref, coords, apropsref, aprops, amref, am)\n", - "\n", - "def get_symmetry_rmsd(mol, coords1, coords2, mol2=None, return_permutation=False):\n", - " # Если число атомов не совпадает, используем fallback на compute_rmsd_simple.\n", - " if coords1.shape != coords2.shape:\n", - " print(\"Warning: число атомов в лигандах не совпадает, для расчёта RMSD берётся только пересечение по числу атомов (fallback на compute_rmsd_simple).\")\n", - " n = min(coords1.shape[0], coords2.shape[0])\n", - " return compute_rmsd_simple(coords1[:n], coords2[:n])\n", - " with time_limit(10):\n", - " m1 = molecule.Molecule.from_rdkit(mol)\n", - " if mol2:\n", - " m2 = molecule.Molecule.from_rdkit(mol2)\n", - " return symmrmsd(coords1, coords2, m1.atomicnums, m2.atomicnums,\n", - " m1.adjacency_matrix, m2.adjacency_matrix,\n", - " return_permutation=return_permutation)\n", - " else:\n", - " return symmrmsd(coords1, coords2, m1.atomicnums, m1.atomicnums,\n", - " m1.adjacency_matrix, m1.adjacency_matrix,\n", - " return_permutation=return_permutation)\n", - "\n", - "def parse_protein(file_path):\n", - " if file_path.endswith(\".pdb\"):\n", - " return PDBParser(QUIET=True).get_structure(\"prot\", file_path)\n", - " elif file_path.endswith(\".cif\"):\n", - " return MMCIFParser(QUIET=True).get_structure(\"prot\", file_path)\n", - " else:\n", - " raise ValueError(\"Unsupported protein format\")\n", - "\n", - "def parse_ligand(file_path):\n", - " mol = Chem.MolFromPDBFile(file_path, removeHs=False)\n", - " if mol is None:\n", - " raise ValueError(\"Could not parse ligand file\")\n", - " return mol\n", - "\n", - "def extract_ligand(input_pdb, output_ligand_pdb, ligand_resname=\"LIG\"):\n", - " parser = PDBParser(QUIET=True)\n", - " structure = parser.get_structure(\"aligned\", input_pdb)\n", - " class LigandSelect(Select):\n", - " def accept_residue(self, residue):\n", - " return residue.get_resname().strip() == ligand_resname\n", - " io = PDBIO()\n", - " io.set_structure(structure)\n", - " io.save(output_ligand_pdb, LigandSelect())\n", - "\n", - "def align_proteins_pymol(ref_protein_path, pred_complex_path, aligned_complex_file):\n", - " cmd.delete(\"all\")\n", - " cmd.load(ref_protein_path, \"ref_protein\")\n", - " cmd.load(pred_complex_path, \"predicted_complex\")\n", - " # Выравнивание по атомам CA\n", - " alignment_result = cmd.align(\"predicted_complex and name CA\", \"ref_protein and name CA\")\n", - " cmd.save(aligned_complex_file, \"predicted_complex\")\n", - " return alignment_result[0]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "def process_prediction(pred_complex_path, output_base):\n", - " try:\n", - " # Определяем reference файлы по имени папки предсказания (без учёта регистра)\n", - " processed_base = \"/mnt/ligandpro/data/DockGen/processed_files\"\n", - " pred_folder = os.path.basename(os.path.dirname(pred_complex_path))\n", - " target_folder = None\n", - " for d in os.listdir(processed_base):\n", - " if d.lower() == pred_folder.lower():\n", - " target_folder = os.path.join(processed_base, d)\n", - " break\n", - " if target_folder is None:\n", - " raise ValueError(\"Нет matching processed folder для \" + pred_folder)\n", - " protein_file = None\n", - " ligand_file = None\n", - " for f in os.listdir(target_folder):\n", - " lf = f.lower()\n", - " if \"protein\" in lf:\n", - " protein_file = os.path.join(target_folder, f)\n", - " if lf.endswith(\"_ligand.pdb\") and lf == (pred_folder.lower() + \"_ligand.pdb\"):\n", - " ligand_file = os.path.join(target_folder, f)\n", - " if protein_file is None or ligand_file is None:\n", - " raise ValueError(\"Protein или ligand файл не найден в \" + target_folder)\n", - " ref_protein_path = protein_file\n", - " ref_ligand_path = ligand_file\n", - "\n", - " # Если файл предсказанного комплекса в формате CIF, конвертируем в PDB (вывод скрыт)\n", - " if pred_complex_path.endswith(\".cif\"):\n", - " output_folder = os.path.join(output_base, pred_folder)\n", - " os.makedirs(output_folder, exist_ok=True)\n", - " converted_file = os.path.join(output_folder, \"pred_complex_converted.pdb\")\n", - " subprocess.run([\"obabel\", pred_complex_path, \"-O\", converted_file],\n", - " check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n", - " pred_complex_path = converted_file\n", - "\n", - " output_dir = os.path.join(output_base, pred_folder)\n", - " os.makedirs(output_dir, exist_ok=True)\n", - " predicted_complex_file = os.path.join(output_dir, \"predicted_complex.pdb\")\n", - " shutil.copy(pred_complex_path, predicted_complex_file)\n", - "\n", - " # Выравнивание через PyMOL\n", - " aligned_complex_file = os.path.join(output_dir, \"predicted_complex_aligned.pdb\")\n", - " protein_rms = align_proteins_pymol(ref_protein_path, predicted_complex_file, aligned_complex_file)\n", - "\n", - " # Извлечение лиганда\n", - " predicted_ligand_aligned_pdb = os.path.join(output_dir, \"predicted_ligand_aligned.pdb\")\n", - " extract_ligand(aligned_complex_file, predicted_ligand_aligned_pdb, ligand_resname=\"LIG\")\n", - "\n", - " # Расчёт RMSD для лиганда:\n", - " # Удаляем водороды из reference лиганда перед вычислением\n", - " ref_lig_rdkit = parse_ligand(ref_ligand_path)\n", - " ref_lig_rdkit = Chem.RemoveHs(ref_lig_rdkit)\n", - " pred_lig_rdkit = parse_ligand(predicted_ligand_aligned_pdb)\n", - " ref_conf = ref_lig_rdkit.GetConformer()\n", - " pred_conf = pred_lig_rdkit.GetConformer()\n", - " ref_coords = ref_conf.GetPositions()\n", - " pred_coords = pred_conf.GetPositions()\n", - " if ref_coords.shape != pred_coords.shape:\n", - " print(f\"Warning: число атомов в лигандах не совпадает для файла {pred_folder}. Используется fallback compute_rmsd_simple.\")\n", - " try:\n", - " ligand_rmsd = get_symmetry_rmsd(ref_lig_rdkit, ref_coords, pred_coords)\n", - " except TimeoutException:\n", - " ligand_rmsd = compute_rmsd_simple(ref_coords, pred_coords)\n", - "\n", - " # Вычисление ошибки сдвига (translational error)\n", - " tr_error = torch.linalg.norm(\n", - " torch.tensor(ref_coords.mean(axis=0)) - torch.tensor(pred_coords.mean(axis=0))\n", - " ).item()\n", - "\n", - " # Копируем reference файлы в output_dir\n", - " shutil.copy(ref_protein_path, os.path.join(output_dir, \"ref_protein.pdb\"))\n", - " shutil.copy(ref_ligand_path, os.path.join(output_dir, \"ref_ligand.pdb\"))\n", - "\n", - " return {\"id\": pred_folder,\n", - " \"pred_complex\": predicted_complex_file,\n", - " \"ligand_rmsd\": ligand_rmsd,\n", - " \"protein_rms\": protein_rms,\n", - " \"tr_error\": tr_error,\n", - " \"output_dir\": output_dir,\n", - " \"error\": None}\n", - " except Exception as e:\n", - " print(f\"Error processing {pred_complex_path}: {e}\")\n", - " return {\"id\": os.path.basename(os.path.dirname(pred_complex_path)),\n", - " \"pred_complex\": None,\n", - " \"ligand_rmsd\": None,\n", - " \"protein_rms\": None,\n", - " \"tr_error\": None,\n", - " \"output_dir\": None,\n", - " \"error\": str(e)}\n", - "\n", - "def process_all_predictions(output_base):\n", - " infer_base = \"/home/nikolenko/work/ligandpro/data/DockGen/chai_calc/chai_out\"\n", - " prediction_paths = []\n", - " for d in os.listdir(infer_base):\n", - " pred_dir = os.path.join(infer_base, d)\n", - " if os.path.isdir(pred_dir):\n", - " zero_model_file = None\n", - " for f in os.listdir(pred_dir):\n", - " if f == \"pred.model_idx_0.cif\":\n", - " zero_model_file = f\n", - " break\n", - " if zero_model_file:\n", - " prediction_paths.append(os.path.join(pred_dir, zero_model_file))\n", - " else:\n", - " print(f\"Warning: Zero model not found in {pred_dir}\")\n", - " results = Parallel(n_jobs=16)(\n", - " delayed(process_prediction)(pred_path, output_base)\n", - " for pred_path in tqdm(prediction_paths, desc=\"Processing predictions\")\n", - " )\n", - " df = pd.DataFrame(results)\n", - " \n", - " # Пример вычисления среднего и медианного значения ошибки сдвига\n", - " mean_tr_error = df['tr_error'].mean()\n", - " median_tr_error = df['tr_error'].median()\n", - " print(f\"Средняя ошибка сдвига: {mean_tr_error}\")\n", - " print(f\"Медианная ошибка сдвига: {median_tr_error}\")\n", - "\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Processing predictions: 0%| | 0/189 [00:00\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idpred_complexligand_rmsdprotein_rmstr_erroroutput_direrror
01i8t_1_FAD_1./results_chai/1i8t_1_FAD_1/predicted_complex.pdb12.7357110.5205450.277703./results_chai/1i8t_1_FAD_1None
11uf7_1_CDV_0./results_chai/1uf7_1_CDV_0/predicted_complex.pdb33.4369500.30431833.322008./results_chai/1uf7_1_CDV_0None
22hs3_1_FGR_0./results_chai/2hs3_1_FGR_0/predicted_complex.pdb24.0264200.59421623.633439./results_chai/2hs3_1_FGR_0None
32wao_1_BGC-BGC-BGC-BGC-BGC_0./results_chai/2wao_1_BGC-BGC-BGC-BGC-BGC_0/pr...10.4044150.3136731.090571./results_chai/2wao_1_BGC-BGC-BGC-BGC-BGC_0None
43o7j_1_2AL_0./results_chai/3o7j_1_2AL_0/predicted_complex.pdb3.5917340.3307720.323042./results_chai/3o7j_1_2AL_0None
........................
1846ep5_1_ADP_1./results_chai/6ep5_1_ADP_1/predicted_complex.pdb17.0104790.96635415.536222./results_chai/6ep5_1_ADP_1None
1856etf_1_AMP_0./results_chai/6etf_1_AMP_0/predicted_complex.pdb5.7091580.6109700.610307./results_chai/6etf_1_AMP_0None
1863o01_2_DXC_0./results_chai/3o01_2_DXC_0/predicted_complex.pdb23.0145111.02105022.180796./results_chai/3o01_2_DXC_0None
1874bc9_1_CNV-FAD_0./results_chai/4bc9_1_CNV-FAD_0/predicted_comp...39.5634030.43602238.200383./results_chai/4bc9_1_CNV-FAD_0None
1883k8l_1_GLC-GLC-GLC-GLC-GLC_0./results_chai/3k8l_1_GLC-GLC-GLC-GLC-GLC_0/pr...42.8179390.48310341.606935./results_chai/3k8l_1_GLC-GLC-GLC-GLC-GLC_0None
\n", - "

189 rows × 7 columns

\n", - "" - ], - "text/plain": [ - " id \\\n", - "0 1i8t_1_FAD_1 \n", - "1 1uf7_1_CDV_0 \n", - "2 2hs3_1_FGR_0 \n", - "3 2wao_1_BGC-BGC-BGC-BGC-BGC_0 \n", - "4 3o7j_1_2AL_0 \n", - ".. ... \n", - "184 6ep5_1_ADP_1 \n", - "185 6etf_1_AMP_0 \n", - "186 3o01_2_DXC_0 \n", - "187 4bc9_1_CNV-FAD_0 \n", - "188 3k8l_1_GLC-GLC-GLC-GLC-GLC_0 \n", - "\n", - " pred_complex ligand_rmsd \\\n", - "0 ./results_chai/1i8t_1_FAD_1/predicted_complex.pdb 12.735711 \n", - "1 ./results_chai/1uf7_1_CDV_0/predicted_complex.pdb 33.436950 \n", - "2 ./results_chai/2hs3_1_FGR_0/predicted_complex.pdb 24.026420 \n", - "3 ./results_chai/2wao_1_BGC-BGC-BGC-BGC-BGC_0/pr... 10.404415 \n", - "4 ./results_chai/3o7j_1_2AL_0/predicted_complex.pdb 3.591734 \n", - ".. ... ... \n", - "184 ./results_chai/6ep5_1_ADP_1/predicted_complex.pdb 17.010479 \n", - "185 ./results_chai/6etf_1_AMP_0/predicted_complex.pdb 5.709158 \n", - "186 ./results_chai/3o01_2_DXC_0/predicted_complex.pdb 23.014511 \n", - "187 ./results_chai/4bc9_1_CNV-FAD_0/predicted_comp... 39.563403 \n", - "188 ./results_chai/3k8l_1_GLC-GLC-GLC-GLC-GLC_0/pr... 42.817939 \n", - "\n", - " protein_rms tr_error output_dir error \n", - "0 0.520545 0.277703 ./results_chai/1i8t_1_FAD_1 None \n", - "1 0.304318 33.322008 ./results_chai/1uf7_1_CDV_0 None \n", - "2 0.594216 23.633439 ./results_chai/2hs3_1_FGR_0 None \n", - "3 0.313673 1.090571 ./results_chai/2wao_1_BGC-BGC-BGC-BGC-BGC_0 None \n", - "4 0.330772 0.323042 ./results_chai/3o7j_1_2AL_0 None \n", - ".. ... ... ... ... \n", - "184 0.966354 15.536222 ./results_chai/6ep5_1_ADP_1 None \n", - "185 0.610970 0.610307 ./results_chai/6etf_1_AMP_0 None \n", - "186 1.021050 22.180796 ./results_chai/3o01_2_DXC_0 None \n", - "187 0.436022 38.200383 ./results_chai/4bc9_1_CNV-FAD_0 None \n", - "188 0.483103 41.606935 ./results_chai/3k8l_1_GLC-GLC-GLC-GLC-GLC_0 None \n", - "\n", - "[189 rows x 7 columns]" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "output_base = \"./results_chai\"\n", - "os.makedirs(output_base, exist_ok=True)\n", - "\n", - "df = process_all_predictions(output_base)\n", - "df.to_csv(os.path.join(output_base, \"results.csv\"), index=False)\n", - "display(df)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Percentage of ligand_rmsd values less than 2 Angstrom: 2.70%\n", - "Percentage of ligand_rmsd values less than 2 (for protein_rms <= 2): 3.11%\n", - "Mean translational error: 11.58\n", - "Median translational error: 1.47\n" - ] - } - ], - "source": [ - "# Calculate the percentage of ligand_rmsd values that are less than 2 Angstrom\n", - "valid_values = df['ligand_rmsd'].dropna()\n", - "percentage = (valid_values < 2).mean() * 100\n", - "print(f\"Percentage of ligand_rmsd values less than 2 Angstrom: {percentage:.2f}%\")\n", - "\n", - "# Filter the DataFrame for records with protein_rms <= 2\n", - "df_filtered = df[df['protein_rms'] <= 2]\n", - "\n", - "# Calculate the percentage of ligand_rmsd values less than 2 Angstrom among the filtered records\n", - "valid_values_filtered = df_filtered['ligand_rmsd'].dropna()\n", - "percentage_filtered = (valid_values_filtered < 2).mean() * 100\n", - "print(f\"Percentage of ligand_rmsd values less than 2 (for protein_rms <= 2): {percentage_filtered:.2f}%\")\n", - "\n", - "# Calculate the mean and median translational error with two decimal places formatting\n", - "mean_tr_error = df['tr_error'].mean()\n", - "median_tr_error = df['tr_error'].median()\n", - "print(f\"Mean translational error: {mean_tr_error:.2f}\")\n", - "print(f\"Median translational error: {median_tr_error:.2f}\")\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pymol", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.16" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scripts/command b/scripts/command deleted file mode 100644 index 27d3361..0000000 --- a/scripts/command +++ /dev/null @@ -1,2 +0,0 @@ -abcfold 6np4.json ./out_fast -abc --gpus 6 --mmseqs2 --override --number_of_models 5 --no_server - diff --git a/scripts/err.ipynb b/scripts/err.ipynb deleted file mode 100644 index 3785a03..0000000 --- a/scripts/err.ipynb +++ /dev/null @@ -1,103 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Statistics for /mnt/ligandpro/data/docking_hack/nikolenko_calc/abc_calc/astex_calc/outputs:\n", - "Successful runs:\n", - "af3: 0\n", - "boltz: 65\n", - "chai: 73\n", - "Failed runs:\n", - "af3: 2\n", - "boltz: 11\n", - "chai: 3\n", - "\n", - "Statistics for /mnt/ligandpro/data/docking_hack/nikolenko_calc/abc_calc/posebusters_calc/outputs:\n", - "Successful runs:\n", - "af3: 0\n", - "boltz: 96\n", - "chai: 120\n", - "Failed runs:\n", - "af3: 4\n", - "boltz: 33\n", - "chai: 8\n", - "\n", - "Statistics for /mnt/ligandpro/data/docking_hack/nikolenko_calc/abc_calc/timesplit_test_calc/outputs:\n", - "Successful runs:\n", - "af3: 0\n", - "boltz: 165\n", - "chai: 205\n", - "Failed runs:\n", - "af3: 5\n", - "boltz: 43\n", - "chai: 2\n" - ] - } - ], - "source": [ - "from pathlib import Path\n", - "\n", - "roots = [\n", - " '/mnt/ligandpro/data/docking_hack/nikolenko_calc/abc_calc/astex_calc/outputs',\n", - " '/mnt/ligandpro/data/docking_hack/nikolenko_calc/abc_calc/posebusters_calc/outputs',\n", - " '/mnt/ligandpro/data/docking_hack/nikolenko_calc/abc_calc/timesplit_test_calc/outputs'\n", - "]\n", - "\n", - "methods = ['af3', 'boltz', 'chai']\n", - "\n", - "for root in roots:\n", - " success_counts = {m: 0 for m in methods}\n", - " failure_counts = {m: 0 for m in methods}\n", - " \n", - " print(f\"\\nStatistics for {root}:\")\n", - " \n", - " for entry in Path(root).iterdir():\n", - " if not entry.is_dir():\n", - " continue\n", - " items = [f.name for f in entry.iterdir()]\n", - " for m in methods:\n", - " if f\"{m}_error.log\" in items:\n", - " failure_counts[m] += 1\n", - " elif any(name.startswith(m) for name in items):\n", - " success_counts[m] += 1\n", - "\n", - " print(\"Successful runs:\")\n", - " for m, c in success_counts.items():\n", - " print(f\"{m}: {c}\")\n", - "\n", - " print(\"Failed runs:\")\n", - " for m, c in failure_counts.items():\n", - " print(f\"{m}: {c}\")\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "abcfold", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.12" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scripts/jackhmmer_msa_prepare.py b/scripts/jackhmmer_msa_prepare.py deleted file mode 100755 index a7b4835..0000000 --- a/scripts/jackhmmer_msa_prepare.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import subprocess -import shutil -from pathlib import Path -from concurrent.futures import ThreadPoolExecutor, as_completed -from tqdm import tqdm -from loguru import logger - -JSON_INPUT_DIR = Path("/mnt/ligandpro/soft/protein/alphafold3/af3_calc_bindingDB/json_inputs") -CPU_OUTPUT_DIR = Path("/mnt/ligandpro/soft/protein/alphafold3/af3_calc_bindingDB/MSA") -GPU_OUTPUT_DIR = Path("/mnt/ligandpro/soft/protein/alphafold3/af3_calc_bindingDB/inference") -MODELS_DIR = Path("/mnt/ligandpro/soft/protein/alphafold3/models") -DB_DIR = Path("/mnt/ligandpro/db/AF3") -IMAGE = "alphafold3" - -CPU_LOG = "cpu_stage.log" - -logger.remove() -logger.add(CPU_LOG, format="{time:YYYY-MM-DD HH:mm:ss} {message}", level="INFO") - -def run_cmd(cmd): - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) - if not p.stdout: - rc = p.wait() - if rc != 0: - raise RuntimeError(f"Error {rc}: {cmd}") - return - for line in p.stdout: - logger.info(line.rstrip("\n")) - rc = p.wait() - if rc != 0: - raise RuntimeError(f"Error {rc}: {cmd}") - -def cpu_task(json_file: Path): - base = json_file.stem - out_dir_name = base.lower() - - cmd = f""" -docker run -i --rm \ ---volume {JSON_INPUT_DIR}:/root/af_input \ ---volume {GPU_OUTPUT_DIR}:/root/af_output \ ---volume {MODELS_DIR}:/root/models \ ---volume {DB_DIR}:/root/public_databases \ --e DB_DIR=/root/public_databases \ -{IMAGE} \ -python run_alphafold.py \ - --json_path=/root/af_input/{json_file.name} \ - --model_dir=/root/models \ - --output_dir=/root/af_input \ - --jackhmmer_n_cpu=8 \ - --nhmmer_n_cpu=8 \ - --run_inference=false -""" - run_cmd(cmd) - - subdir = JSON_INPUT_DIR / out_dir_name - data_json = subdir / f"{out_dir_name}_data.json" - if not data_json.is_file(): - raise FileNotFoundError(f"Enriched JSON not found: {data_json}") - - CPU_OUTPUT_DIR.mkdir(parents=True, exist_ok=True) - target_subdir = CPU_OUTPUT_DIR / out_dir_name - if target_subdir.exists(): - shutil.rmtree(target_subdir) - shutil.move(str(subdir), str(CPU_OUTPUT_DIR)) - -def main(): - if not JSON_INPUT_DIR.is_dir(): - logger.error(f"No directory {JSON_INPUT_DIR}") - return - json_files = list(JSON_INPUT_DIR.glob("*.json")) - if not json_files: - logger.info("No JSON files in input directory.") - return - - to_process = [] - for jf in json_files: - out_dir_name = jf.stem.lower() - data_json = CPU_OUTPUT_DIR / out_dir_name / f"{out_dir_name}_data.json" - if data_json.is_file(): - logger.info(f"Already processed: {jf.name}, skipping...") - continue - to_process.append(jf) - - if not to_process: - logger.info("No new JSON files to process.") - return - - with ThreadPoolExecutor(max_workers=4) as pool: - futs = {pool.submit(cpu_task, jf): jf for jf in to_process} - for _ in tqdm(as_completed(futs), total=len(futs), desc="CPU stage"): - pass - -if __name__ == "__main__": - main() diff --git a/scripts/run_abcfold.py b/scripts/run_abcfold.py deleted file mode 100644 index 00c0d00..0000000 --- a/scripts/run_abcfold.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python3 -from pathlib import Path -import subprocess, os, queue, threading, time, argparse, logging -import torch -import typer -from rich.console import Console -from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn -from rich.table import Table -from rich.logging import RichHandler - -app = typer.Typer() -console = Console() - -logging.basicConfig( - level=logging.INFO, - format="%(message)s", - datefmt="[%X]", - handlers=[RichHandler(rich_tracebacks=True)] -) - -input_dir = Path("json_inputs") -output_root = Path("outputs") -log_file = Path("run.log") -if log_file.exists(): - log_file.unlink() - -methods = [ - {"name": "af3", "prefix": "alphafold3", "log": "af3_error.log"}, - {"name": "boltz", "prefix": "boltz", "log": "boltz_error.log"}, - {"name": "chai", "prefix": "chai", "log": "chai_error.log"}, -] - -def status(jf: Path): - od = output_root / jf.stem - if not od.is_dir(): - return {m["name"]: "missing" for m in methods} - names = {p.name for p in od.iterdir()} - r = {} - for m in methods: - if m["log"] in names: - r[m["name"]] = "failed" - elif any(n.startswith(m["prefix"]) and not n.endswith("_error.log") for n in names): - r[m["name"]] = "success" - else: - r[m["name"]] = "missing" - return r - -def print_stats(files, title): - tot = len(files) - agg = {m["name"]: {"success": 0, "failed": 0, "missing": 0} for m in methods} - for f in files: - s = status(f) - for k, v in s.items(): - agg[k][v] += 1 - table = Table(title=f"{title} (total {tot})") - table.add_column("Method", style="cyan") - table.add_column("Success", style="green") - table.add_column("Failed", style="red") - table.add_column("Missing", style="yellow") - for k, c in agg.items(): - table.add_row(k, str(c["success"]), str(c["failed"]), str(c["missing"])) - console.print(table) - -def run_job(jf: Path, gpu: str): - env = os.environ.copy() - env["CUDA_VISIBLE_DEVICES"] = "" if gpu == "cpu" else gpu - od = output_root / jf.stem - od.mkdir(parents=True, exist_ok=True) - cmd = [ - "abcfold", - str(jf), - str(od), - "-abc", - "--gpus", gpu, - "--mmseqs2", - "--override", - "--number_of_models", "5", - "--no_visuals", - ] - with log_file.open("a") as lg: - ret = subprocess.call(cmd, stdout=lg, stderr=lg, env=env) - if ret != 0: - logging.error(f"Failed to process {jf.name}") - return ret == 0 - -def expand(arg): - if arg.lower() == "cpu": - return ["cpu"] - if arg.lower() == "all": - n = torch.cuda.device_count() - return [str(i) for i in range(n)] or ["cpu"] - return [x.strip() for x in arg.split(",") if x.strip()] - -def worker(gpu, q: queue.Queue, progress, task): - while True: - try: - jf = q.get_nowait() - except queue.Empty: - break - run_job(jf, gpu) - progress.update(task, advance=1) - q.task_done() - -@app.command() -def main( - gpus: str = typer.Option("0", help="all | cpu | 0,1,3 …"), - input_path: Path = typer.Option(input_dir, help="Input directory with JSON files"), - output_path: Path = typer.Option(output_root, help="Output directory for results") -): - global input_dir, output_root - input_dir = input_path - output_root = output_path - gpus = expand(gpus) - files = sorted(input_dir.glob("*.json")) - print_stats(files, "BEFORE") - q = queue.Queue() - for jf in files: - if any(status(jf)[m["name"]] != "success" for m in methods): - q.put(jf) - total_jobs = q.qsize() - logging.info(f"Queued {total_jobs} jobs on GPUs {gpus}") - with Progress( - SpinnerColumn(), - TextColumn("Processing files:"), - BarColumn(bar_width=None), - TaskProgressColumn("{task.completed}/{task.total}"), - TimeElapsedColumn(), - TimeRemainingColumn(), - console=console, - ) as progress: - task = progress.add_task(f"ABCFold Calculation [{total_jobs} jobs]", total=total_jobs) - threads = [threading.Thread(target=worker, args=(g, q, progress, task), daemon=True) for g in gpus] - for t in threads: - t.start() - for t in threads: - t.join() - print_stats(files, "AFTER") - -if __name__ == "__main__": - app() diff --git a/setup.py b/setup.py deleted file mode 100644 index ded751d..0000000 --- a/setup.py +++ /dev/null @@ -1,37 +0,0 @@ -from distutils.command.build import build # type: ignore - -from setuptools import setup - -script_python_path: str | None = None - - -class BuildCommand(build): - user_options = build.user_options + [ - ( - "script-python-path=", - None, - "Path to Python interpreter to be included in the scripts", - ) - ] - - def initialize_options(self): - build.initialize_options(self) - self.script_python_path = None - - def finalize_options(self): - build.finalize_options(self) - - def run(self): - global script_python_path - script_python_path = self.script_python_path - build.run(self) - - -with open("README.md", "r") as fh: - long_description = fh.read() - -setup( - cmdclass={"build": BuildCommand}, - long_description=long_description, - long_description_content_type="text/markdown", -) diff --git a/abcfold/LICENCE b/src/abcfold/LICENCE similarity index 100% rename from abcfold/LICENCE rename to src/abcfold/LICENCE diff --git a/abcfold/__init__.py b/src/abcfold/__init__.py similarity index 100% rename from abcfold/__init__.py rename to src/abcfold/__init__.py diff --git a/src/abcfold/abcfold.py b/src/abcfold/abcfold.py new file mode 100644 index 0000000..585dad3 --- /dev/null +++ b/src/abcfold/abcfold.py @@ -0,0 +1,744 @@ +import json +import logging +import os +import shutil +import socketserver +import sys +import tempfile +import time +import traceback +import webbrowser +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Callable, Dict, List, Optional, Tuple, Union + +from abcfold.argparse_utils import (alphafold_argparse_util, + boltz_argparse_util, chai_argparse_util, + custom_template_argpase_util, + main_argpase_util, mmseqs2_argparse_util, + msa_argparse_util, openfold_argparse_util, + prediction_argparse_util, + protenix_argparse_util, + raise_argument_errors, + rosettafold_argparse_util, + visuals_argparse_util) +from abcfold.output.alphafold3 import AlphafoldOutput +from abcfold.output.boltz import BoltzOutput +from abcfold.output.chai import ChaiOutput +from abcfold.output.openfold3 import OpenfoldOutput +from abcfold.output.protenix import ProtenixOutput +from abcfold.output.rosettafold3 import RosettafoldOutput +from abcfold.report import (EngineRecord, build_report, samples_from_output, + write_report) +from abcfold.scripts.abc_script_utils import (check_input_json, make_dir, + make_dummy_af3_db, setup_logger) +from abcfold.settings import Settings, load_settings + +logger = setup_logger() + +HTML_DIR = Path(__file__).parent / "html" +HTML_TEMPLATE = HTML_DIR.joinpath("abcfold.html.jinja2") +PLOTS_DIR = ".plots" + +ENGINE_ORDER = ("alphafold3", "boltz", "chai1", "protenix", "openfold3", + "rosettafold3") +DISPLAY_NAMES = { + "alphafold3": "AlphaFold3", + "boltz": "Boltz", + "chai1": "Chai-1", + "protenix": "Protenix", + "openfold3": "OpenFold3", + "rosettafold3": "RosettaFold3", +} +MODEL_PREFIX = { + "alphafold3": "af3", + "boltz": "boltz", + "chai1": "chai", + "protenix": "protenix", + "openfold3": "openfold", + "rosettafold3": "rosettafold", +} +EXIT_OK, EXIT_FAILED, EXIT_PARTIAL = 0, 1, 2 + +ModelOutput = Union[ + AlphafoldOutput, + BoltzOutput, + ChaiOutput, + ProtenixOutput, + OpenfoldOutput, + RosettafoldOutput, +] + + +def abcfold_version() -> Optional[str]: + try: + from importlib.metadata import version + + return version("abcfold") + except Exception: # pragma: no cover - not installed + return None + + +# Command line flag -> settings key. CLI values win over config/env values. +CLI_SETTINGS = { + "model_params": "model_params", + "database_dir": "database_dir", + "af3_sif_path": "af3_sif_path", + "msa_cache_dir": "msa_cache_dir", + "msa_server_url": "msa_server_url", + "af3_runner": "af3_runner", + "af3_image": "af3_image", + "af3_command": "af3_command", + "template_mirror_dir": "template_mirror_dir", + "boltz_preprocessing_threads": "boltz_preprocessing_threads", + "boltz_num_workers": "boltz_num_workers", + "boltz_max_parallel_samples": "boltz_max_parallel_samples", + "min_msa_rows": "min_msa_rows", +} + + +def resolve_settings(args, settings: Optional[Settings] = None) -> Settings: + """Merge CLI flags into the (read-only) settings and back-fill ``args``.""" + if settings is None: + settings = load_settings(getattr(args, "config_file", None)) + overrides = { + key: getattr(args, flag, None) + for flag, key in CLI_SETTINGS.items() + if getattr(args, flag, None) not in (None, "", "None") + } + settings = settings.apply_overrides(overrides) + if getattr(args, "protenix_model", None): + settings.backends["protenix"]["model"] = args.protenix_model + if getattr(args, "allow_version_mismatch", False): + settings.values["allow_version_mismatch"] = True + for flag, key in CLI_SETTINGS.items(): + if getattr(args, flag, None) in (None, "", "None"): + setattr(args, flag, settings.get(key)) + return settings + + +@dataclass +class EngineOutcome: + ok: bool + output: Optional[ModelOutput] = None + error: Optional[str] = None + + +def _error_from_logs(output_dir: Path, since: float = 0.0) -> Optional[str]: + """Last lines of the newest backend error log written after ``since``.""" + logs = [p for p in output_dir.glob("**/*error*.log") if p.is_file()] + logs = sorted( + (p for p in logs if p.stat().st_mtime >= since), + key=lambda p: p.stat().st_mtime, + reverse=True, + ) + for log in logs: + try: + text = log.read_text().strip() + except OSError: + continue + if text: + return f"{log.name}: {text[-1500:]}" + return None + + +def _proteins_have_msas(params: dict) -> bool: + proteins = [s["protein"] for s in params.get("sequences", []) if "protein" in s] + return bool(proteins) and all( + p.get("unpairedMsa") is not None or p.get("unpairedMsaPath") for p in proteins + ) + + +def _merge_af3_msas(params: dict, data_json: Path) -> dict: + """Copy MSAs/templates from an AF3 *_data.json into ``params``.""" + from abcfold.msa.resolve import MsaOptions, resolve_msas + + result = resolve_msas( + params, MsaOptions(source="af3", af3_data_json=str(data_json)) + ) + return result.params + + +def _write_json(path: Path, data: dict) -> None: + tmp = path.with_suffix(path.suffix + ".tmp") + tmp.write_text(json.dumps(data, indent=4)) + os.replace(tmp, path) + + +def run(args, settings: Optional[Settings] = None) -> int: + """Run ABCFold and return the exit code (0 ok, 2 partial, 1 failed).""" + args.output_dir = Path(args.output_dir) + settings = resolve_settings(args, settings) + rt_config = settings.runtime_config() + args = raise_argument_errors(args) + + if args.mmseqs2: + logger.info("MMSeqs2 Selected, all other MSAs will be ignored") + + make_dir(args.output_dir, overwrite=args.override) + make_dir(args.output_dir.joinpath(PLOTS_DIR)) + + # abc_.json in the output directory is the single source of truth for + # every backend; it keeps the MSAs so that a later run can reuse them. + args.input_json = check_input_json( + args.input_json, + output_dir=args.output_dir, + use_af3_templates=args.use_af3_template_search, + ) + run_json = Path(args.input_json) + input_params = json.loads(run_json.read_text()) + + name = input_params.get("name") + if name is None: + logger.error("Input JSON must contain a 'name' field") + sys.exit(1) + + msa_section: Dict[str, Any] = {"source": None, "seconds": 0.0, "chains": {}} + engines = [e for e in ENGINE_ORDER if getattr(args, e, False)] + records = {e: EngineRecord(engine=e) for e in ENGINE_ORDER} + outputs: List[Tuple[str, ModelOutput]] = [] + + with tempfile.TemporaryDirectory() as temp_dir_str: + temp_dir = Path(temp_dir_str) + + if args.mmseqs2: + from abcfold.scripts.add_mmseqs_msa import add_msa_to_json + + input_params = add_msa_to_json( + input_json=run_json, + mmseqs_db=args.mmseqs_database, + templates=args.templates, + num_templates=args.num_templates, + chai_template_output=temp_dir.joinpath("all_chains.m8"), + input_params=input_params, + output_json=run_json, + to_file=True, + ) + msa_section["source"] = "mmseqs2" + else: + input_params, msa_section = resolve_input_msas( + input_params, args, settings + ) + _write_json(run_json, input_params) + + if args.custom_template is not None: + from abcfold.scripts.add_custom_template import add_custom_template + + add_custom_template( + run_json, + args.target_id, + args.custom_template, + args.custom_template_chain, + output_json=run_json, + to_file=True, + ) + input_params = json.loads(run_json.read_text()) + + # An MSA that was requested but came back (nearly) empty would let every + # backend fold single-sequence without noticing. + from abcfold.msa.guard import (ShallowMsaError, check_input_msa_depth, + min_msa_rows) + + precheck_error = None + try: + check_input_msa_depth(input_params, min_msa_rows(rt_config), + context=str(run_json.name)) + except ShallowMsaError as exc: + logger.error(str(exc)) + precheck_error = str(exc) + + runners: Dict[str, Callable[[], EngineOutcome]] = { + "alphafold3": lambda: _run_alphafold3( + args, rt_config, run_json, input_params, temp_dir, name + ), + "boltz": lambda: _run_boltz(args, rt_config, run_json, input_params, + name), + "chai1": lambda: _run_chai(args, rt_config, run_json, input_params, + temp_dir, name), + "protenix": lambda: _run_protenix(args, rt_config, run_json, + input_params, name), + "openfold3": lambda: _run_openfold(args, rt_config, run_json, + input_params, temp_dir, name), + "rosettafold3": lambda: _run_rosettafold(args, rt_config, run_json, + input_params, name), + } + + for engine in engines: + record = records[engine] + record.version = settings.backend(engine).get("version") + logger.info("Running %s", DISPLAY_NAMES[engine]) + start = time.monotonic() + wall_start = time.time() - 1 + if precheck_error is not None: + record.status = "failed" + record.error = precheck_error + record.seconds = 0.0 + continue + try: + outcome = runners[engine]() + except SystemExit as exc: + outcome = EngineOutcome(False, error=f"exited with {exc.code}") + except Exception as exc: # one backend must not stop the others + logger.error("%s failed: %s", DISPLAY_NAMES[engine], exc) + logger.debug(traceback.format_exc()) + outcome = EngineOutcome(False, error=f"{type(exc).__name__}: {exc}") + record.seconds = time.monotonic() - start + if outcome.ok: + record.status = "ok" + if outcome.output is not None: + outputs.append((engine, outcome.output)) + try: + n = sum( + 1 for models in outcome.output.output.values() + for idx in models if not (isinstance(idx, int) and idx < 0) + ) + record.samples = samples_from_output( + engine, record.version, outcome.output.output, + args.output_dir, + seconds_per_sample=(record.seconds / n) if n else None, + ) + except Exception as exc: + logger.warning("Could not summarise %s samples: %s", + engine, exc) + else: + record.status = "failed" + record.error = ( + outcome.error + or _error_from_logs(args.output_dir, wall_start) + or "backend produced no structures" + ) + logger.error("%s failed: %s", DISPLAY_NAMES[engine], + record.error.splitlines()[0] if record.error else "") + if engine == "alphafold3" and outcome.ok: + # AF3 may have produced MSAs that the other backends can reuse + input_params = json.loads(run_json.read_text()) + + report = build_report( + name=name, + engines=[records[e] for e in ENGINE_ORDER], + msa=msa_section, + input_json=str(run_json), + output_dir=str(args.output_dir.resolve()), + abcfold_version=abcfold_version(), + ) + report_path = write_report(report, args.output_dir / "report.json") + logger.info("Report written to %s (status: %s)", report_path, + report["status"]) + + ok = [e for e in engines if records[e].status == "ok"] + exit_code = ( + EXIT_OK if len(ok) == len(engines) + else EXIT_PARTIAL if ok else EXIT_FAILED + ) + + if args.output_json: + shutil.copy(run_json, args.output_json) + + if args.no_visuals: + logger.info("Visuals disabled") + return exit_code + if not outputs: + logger.error("No models were generated") + return exit_code + try: + render_html(outputs, args.output_dir, no_server=args.no_server) + except Exception as exc: + logger.error("Could not build the HTML report: %s", exc) + logger.debug(traceback.format_exc()) + return exit_code + + +def resolve_input_msas(input_params: dict, args, settings: Settings): + """Apply ``--msa`` and return (params, msa report section).""" + from abcfold.msa.resolve import MsaOptions, parse_chain_paths, resolve_msas + from abcfold.msa.stats import write_msa_stats + + options = MsaOptions( + source=getattr(args, "msa", "auto") or "auto", + cache_dir=settings.get("msa_cache_dir"), + server_url=settings.get("msa_server_url", "https://api.colabfold.com"), + user_agent=settings.get("msa_user_agent", "abcfold"), + paired=not getattr(args, "no_paired_msa", False), + custom_a3m=parse_chain_paths(getattr(args, "msa_a3m", None)), + custom_paired_a3m=parse_chain_paths(getattr(args, "msa_paired_a3m", None)), + af3_data_json=getattr(args, "af3_data_json", None), + ) + result = resolve_msas(input_params, options) + section = {"source": result.source, "seconds": round(result.seconds, 3), + "chains": result.chains} + if result.chains: + write_msa_stats(args.output_dir / "msa_stats.json", result.chains, + result.source, result.seconds) + return result.params, section + + +def _run_alphafold3(args, rt_config, run_json: Path, input_params: dict, + temp_dir: Path, name: str) -> EngineOutcome: + runner = rt_config.get("af3_runner") or "docker" + sif = args.af3_sif_path + if runner == "alphafast" or (sif not in (None, "", "None") and runner == "docker"): + return _run_alphafold3_legacy(args, rt_config, run_json, input_params, + temp_dir, name) + + from abcfold.alphafold3.af3_adapter import Af3Config, run_af3 + + image = rt_config.get("af3_image") + if runner in ("apptainer", "singularity") and sif not in (None, "", "None"): + image = sif + cfg = Af3Config.from_runtime_config( + rt_config, + runner=runner, + image=image, + gpus=args.gpus, + num_diffusion_samples=args.number_of_models, + num_recycles=args.num_recycles, + save_distogram=args.save_distogram, + ) + if args.af3_data_pipeline_only: + mode = "data_pipeline" + elif args.af3_inference_only or ( + _proteins_have_msas(input_params) and not cfg.db_dir + ): + mode = "inference" + else: + mode = "full" + result = run_af3(input_params, args.output_dir / "af3_run", cfg, mode=mode) + + if result.data_json is not None and not _proteins_have_msas(input_params): + merged = _merge_af3_msas(input_params, result.data_json) + _write_json(run_json, merged) + if mode == "data_pipeline": + logger.info("AlphaFold 3 data pipeline written to %s", result.data_json) + return EngineOutcome(True) + target = args.output_dir / f"alphafold3_{name}" + if target.exists(): + shutil.rmtree(target) + shutil.move(str(result.job_dir), target) + return EngineOutcome(True, AlphafoldOutput(target, input_params, name)) + + +def _run_alphafold3_legacy(args, rt_config, run_json: Path, input_params: dict, + temp_dir: Path, name: str) -> EngineOutcome: + from abcfold.alphafold3.run_alphafold3 import run_alphafold3 + + af3_database = args.database_dir + use_precomputed_msas = args.mmseqs2 or _proteins_have_msas(input_params) + if use_precomputed_msas: + af3_database = make_dummy_af3_db(temp_dir) + af3_output_dir = run_alphafold3( + input_json=run_json, + output_dir=args.output_dir, + model_params=args.model_params, + database_dir=af3_database, + number_of_models=args.number_of_models, + num_recycles=args.num_recycles, + sif_path=args.af3_sif_path, + save_distogram=args.save_distogram, + gpus=args.gpus, + config=rt_config, + use_precomputed_msas=use_precomputed_msas, + ) + if af3_output_dir is None: + return EngineOutcome(False) + ao = AlphafoldOutput(af3_output_dir, input_params, name) + if not use_precomputed_msas: + _write_json(run_json, _merge_af3_msas(input_params, ao.input_json)) + return EngineOutcome(True, ao) + + +def _run_boltz(args, rt_config, run_json, input_params, name) -> EngineOutcome: + from abcfold.boltz.run_boltz import run_boltz + + ok = run_boltz( + input_json=run_json, + output_dir=args.output_dir, + save_input=args.save_input, + number_of_models=args.number_of_models, + num_recycles=args.num_recycles, + gpus=args.gpus, + config=rt_config, + boltz_mode=args.boltz_mode, + boltz_crystal_structure=args.boltz_crystal_structure, + boltz_ligand_chain=args.boltz_ligand_chain, + boltz_template_chain_id=args.boltz_template_chain_id, + boltz_template_id=args.boltz_template_id, + boltz_template_force=args.boltz_template_force, + boltz_template_threshold=args.boltz_template_threshold, + boltz_pocket_radius=args.boltz_pocket_radius, + boltz_pocket_max_distance=args.boltz_pocket_max_distance, + boltz_pocket_force=args.boltz_pocket_force, + preprocessing_threads=args.boltz_preprocessing_threads, + num_workers=args.boltz_num_workers, + max_parallel_samples=args.boltz_max_parallel_samples, + sampling_steps=args.diffusion_steps or 200, + ) + if not ok: + return EngineOutcome(False) + dirs = list(args.output_dir.glob("boltz_results*")) + return EngineOutcome(True, BoltzOutput(dirs, input_params, name, args.save_input)) + + +def _run_chai(args, rt_config, run_json, input_params, temp_dir, name): + from abcfold.chai1.run_chai1_fast import run_chai_fast + from abcfold.output.utils import make_dummy_m8_file + + template_hits_path = None + if args.templates and args.mmseqs2: + template_hits_path = temp_dir.joinpath("all_chains.m8") + elif args.templates: + template_hits_path = make_dummy_m8_file(run_json, temp_dir) + ok = run_chai_fast( + input_json=run_json, + output_dir=args.output_dir, + save_input=args.save_input, + number_of_models=args.number_of_models, + num_recycles=args.num_recycles, + template_hits_path=template_hits_path, + device=args.gpus, + config=rt_config, + diffusion_steps=args.diffusion_steps or 200, + ) + if not ok: + return EngineOutcome(False) + dirs = list(args.output_dir.glob("chai_output*")) + return EngineOutcome( + True, ChaiOutput(dirs, input_params, name, rt_config, args.save_input) + ) + + +def _run_protenix(args, rt_config, run_json, input_params, name): + from abcfold.protenix.run_protenix import run_protenix + + ok = run_protenix( + input_json=run_json, + output_dir=args.output_dir, + save_input=args.save_input, + number_of_models=args.number_of_models, + num_recycles=args.num_recycles, + diffusion_steps=args.diffusion_steps, + gpus=args.gpus, + config=rt_config, + ) + if not ok: + return EngineOutcome(False) + dirs = list(args.output_dir.glob("protenix_results*")) + return EngineOutcome( + True, ProtenixOutput(dirs, input_params, name, args.save_input) + ) + + +def _run_openfold(args, rt_config, run_json, input_params, temp_dir, name): + from abcfold.openfold3.run_openfold3 import run_openfold + + template_hits_path = None + if args.templates and args.mmseqs2: + template_hits_path = temp_dir.joinpath("all_chains.m8") + ok = run_openfold( + input_json=run_json, + output_dir=args.output_dir, + save_input=args.save_input, + number_of_models=args.number_of_models, + template_hits_path=template_hits_path, + input_ckpt=args.inference_ckpt_path, + num_recycles=args.num_recycles, + diffusion_steps=args.diffusion_steps, + fetch_templates=args.openfold_fetch_templates, + template_mirror_dir=args.template_mirror_dir, + gpus=args.gpus, + config=rt_config, + ) + if not ok: + return EngineOutcome(False) + dirs = list(args.output_dir.glob("openfold_results*")) + return EngineOutcome( + True, OpenfoldOutput(dirs, input_params, name, args.save_input) + ) + + +def _run_rosettafold(args, rt_config, run_json, input_params, name): + from abcfold.rosettafold3.run_rosettafold3 import run_rosettafold + + ok = run_rosettafold( + input_json=run_json, + output_dir=args.output_dir, + save_input=args.save_input, + number_of_models=args.number_of_models, + config=rt_config, + ) + if not ok: + return EngineOutcome(False) + dirs = list(args.output_dir.glob("rosettafold_results*")) + return EngineOutcome( + True, RosettafoldOutput(dirs, input_params, name, args.save_input) + ) + + +def render_html(outputs: List[Tuple[str, ModelOutput]], output_dir: Path, + no_server: bool = False) -> None: + """Build the interactive HTML page (and optionally serve it).""" + from abcfold.html.html_utils import (PORT, NoCacheHTTPRequestHandler, + get_all_cif_files, get_model_data, + get_model_sequence_data, + output_open_html_script, plots, + render_template) + from abcfold.output.file_handlers import superpose_models + from abcfold.output.utils import get_gap_indicies, insert_none_by_minus_one + + model_outputs = [out for _, out in outputs] + plot_dict = plots(model_outputs, output_dir.joinpath(PLOTS_DIR)) + cif_models = [ + cif_file + for cif_list in get_all_cif_files(model_outputs).values() + for cif_file in cif_list + ] + indicies = get_gap_indicies(*cif_models) + index_counter = 0 + + programs_run: List[str] = [] + combined_models: List[Dict[str, Any]] = [] + for engine, out in outputs: + programs_run.append(DISPLAY_NAMES[engine]) + for seed in out.output.keys(): + for idx in out.output[seed].keys(): + if isinstance(idx, int) and idx < 0: + continue + files = out.output[seed][idx] + model = files["cif"] + model.check_clashes() + score_file = next( + (files[k] for k in ("summary", "json", "scores", "score") + if files.get(k) is not None), + None, + ) + plddt = model.residue_plddts + if len(indicies) > 0: + plddt = insert_none_by_minus_one(indicies[index_counter], plddt) + index_counter += 1 + combined_models.append(get_model_data( + model, plot_dict, DISPLAY_NAMES[engine], plddt, + files["af3_pae"], score_file, output_dir, + )) + + prefix_by_display = {DISPLAY_NAMES[e]: MODEL_PREFIX[e] for e in DISPLAY_NAMES} + models_dir = output_dir.joinpath("output_models") + models_dir.mkdir(parents=True, exist_ok=True) + output_models = [] + for model in combined_models: + cif_file = output_dir.joinpath(model["model_path"]) + out_name = (f"{prefix_by_display[model['model_source']]}_model_" + f"{model['model_id'][-1]}.cif") + shutil.copy(cif_file, models_dir / out_name) + output_models.append(models_dir / out_name) + if len(output_models) > 1: + superpose_models(output_models) + + sequence_data = get_model_sequence_data(cif_models) + sequence = "".join(sequence_data.values()) + chain_data = {} + ref = 0 + for key, seq in sequence_data.items(): + chain_data["Chain " + key] = (ref, len(seq) + ref - 1) + ref += len(seq) + results_json = json.dumps({ + "sequence": sequence, + "models": combined_models, + "plotly_path": Path(plot_dict["plddt"]) + .relative_to(output_dir.resolve()) + .as_posix(), + "chain_data": chain_data, + }) + + if not output_dir.joinpath(".feature_viewer").exists(): + shutil.copytree(HTML_DIR, output_dir / ".feature_viewer") + + if len(programs_run) > 1: + programs = ("Structure predictions for: " + ", ".join(programs_run[:-1]) + + " and " + programs_run[-1]) + else: + programs = "Structure predictions for: " + programs_run[0] + + html_out = output_dir.joinpath("index.html").resolve() + render_template( + HTML_TEMPLATE, + html_out, + abcfold_html_dir=".feature_viewer", + programs=programs, + results_json=results_json, + version=abcfold_version() or "2", + ) + logger.info(f"Output page written to {html_out}") + output_open_html_script(str(output_dir / "open_output.py"), port=PORT) + + if no_server: + logger.info("Server disabled") + logger.info("Run 'python open_output.py' in the output directory to " + "view the output pages") + return + + os.chdir(output_dir) + try: + with socketserver.TCPServer(("", PORT), NoCacheHTTPRequestHandler) as httpd: + logger.info(f"Serving at port {PORT}: http://localhost:{PORT}/index.html") + logger.info("Press Ctrl+C to stop the server") + webbrowser.open(f"http://localhost:{PORT}/index.html") + httpd.serve_forever() + except KeyboardInterrupt: + logger.info("Server stopped") + + +def build_run_parser(parser=None): + import argparse + + if parser is None: + parser = argparse.ArgumentParser( + description=( + "Run AlphaFold3 / Boltz / Chai-1 / OpenFold3 / Protenix / " + "RosettaFold3" + ), + ) + parser.add_argument( + "--config-file", + dest="config_file", + default=None, + help=dedent_help( + "[optional] TOML (or legacy INI) config file. Read only; defaults come " + "from the packaged data/defaults.toml and backends.toml. Can also be " + "set with ABCFOLD_CONFIG." + ), + ) + parser.add_argument( + "-v", "--verbose", action="store_true", help="[optional] Debug logging" + ) + for util in ( + main_argpase_util, + msa_argparse_util, + alphafold_argparse_util, + boltz_argparse_util, + chai_argparse_util, + openfold_argparse_util, + protenix_argparse_util, + rosettafold_argparse_util, + mmseqs2_argparse_util, + custom_template_argpase_util, + prediction_argparse_util, + visuals_argparse_util, + ): + parser = util(parser) + return parser + + +def dedent_help(text: str) -> str: + return " ".join(text.split()) + + +def main(argv: Optional[List[str]] = None) -> int: + """Run AlphaFold3 / Boltz / Chai-1 / OpenFold3 / Protenix / RosettaFold3.""" + parser = build_run_parser() + args = parser.parse_args(argv) + if getattr(args, "verbose", False): + logger.setLevel(logging.DEBUG) + return run(args) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/abcfold/alphafold3/af3_adapter.py b/src/abcfold/alphafold3/af3_adapter.py new file mode 100644 index 0000000..b13853a --- /dev/null +++ b/src/abcfold/alphafold3/af3_adapter.py @@ -0,0 +1,389 @@ +"""AlphaFold 3 adapter. + +Runs the official AlphaFold 3 ``run_alphafold.py`` through Docker, Apptainer / +Singularity, or an arbitrary site wrapper command, and parses its output +directory. The data pipeline (MSA/template search) and the inference stage can +be run separately: ``data_pipeline`` writes ``/_data.json``, which +``inference`` consumes without touching the databases. +""" + +from __future__ import annotations + +from abcfold.gpus import docker_gpu_flags, to_physical +import copy +import csv +import json +import logging +import os +import shlex +import string +import subprocess +import time +from dataclasses import dataclass, field +from pathlib import Path +from typing import Dict, List, Mapping, Optional, Sequence + +logger = logging.getLogger("logger") + +RUNNERS = ("docker", "apptainer", "singularity", "command") +MODES = ("full", "data_pipeline", "inference") + +CONTAINER_INPUT_DIR = "/root/af_input" +CONTAINER_OUTPUT_DIR = "/root/af_output" +CONTAINER_MODEL_DIR = "/root/models" +CONTAINER_DB_DIR = "/root/public_databases" +CONTAINER_APP_DIR = "/app/alphafold" + + +def sanitised_name(name: str) -> str: + """Output directory name used by AlphaFold 3 (lower case, [a-z0-9_-.]).""" + lower_spaceless = name.lower().replace(" ", "_") + allowed = set(string.ascii_lowercase + string.digits + "_-.") + return "".join(c for c in lower_spaceless if c in allowed) + + +@dataclass +class Af3Config: + runner: str = "docker" + image: str = "alphafold3" + model_dir: Optional[str] = None + db_dir: Optional[str] = None + command: Optional[str] = None + append_flags: bool = True + run_script: str = "run_alphafold.py" + gpus: str = "all" + num_diffusion_samples: int = 5 + num_recycles: Optional[int] = None + num_seeds: Optional[int] = None + save_distogram: bool = False + extra_flags: List[str] = field(default_factory=list) + + @classmethod + def from_runtime_config(cls, config: Mapping, **overrides) -> "Af3Config": + def pick(key, default=None): + value = config.get(key) + return default if value in (None, "", "None") else value + + cfg = cls( + runner=str(pick("af3_runner", "docker")), + image=str(pick("af3_image", "alphafold3")), + model_dir=pick("model_params"), + db_dir=pick("database_dir"), + command=pick("af3_command"), + append_flags=str(pick("af3_append_flags", True)).lower() + not in ("false", "0", "no"), + run_script=str(pick("af3_run_script", "run_alphafold.py")), + ) + for key, value in overrides.items(): + if value is not None: + setattr(cfg, key, value) + return cfg + + +def _gpu_docker_flags(gpus: str) -> List[str]: + return docker_gpu_flags(gpus) + + +def af3_flags( + cfg: Af3Config, + mode: str, + json_path: Optional[str] = None, + output_dir: Optional[str] = None, + model_dir: Optional[str] = None, + db_dir: Optional[str] = None, +) -> List[str]: + """Flags for ``run_alphafold.py``; path flags only when paths are given.""" + if mode not in MODES: + raise ValueError(f"Unknown AF3 mode {mode!r}, expected one of {MODES}") + flags: List[str] = [] + if json_path: + flags.append(f"--json_path={json_path}") + if model_dir and mode != "data_pipeline": + flags.append(f"--model_dir={model_dir}") + if db_dir and mode != "inference": + flags.append(f"--db_dir={db_dir}") + if output_dir: + flags.append(f"--output_dir={output_dir}") + if mode == "data_pipeline": + flags.append("--run_inference=false") + elif mode == "inference": + flags.append("--run_data_pipeline=false") + if mode != "data_pipeline": + flags.append(f"--num_diffusion_samples={int(cfg.num_diffusion_samples)}") + if cfg.num_recycles is not None: + flags.append(f"--num_recycles={int(cfg.num_recycles)}") + if cfg.num_seeds is not None: + flags.append(f"--num_seeds={int(cfg.num_seeds)}") + if cfg.save_distogram: + flags.append("--save_distogram=true") + flags.extend(cfg.extra_flags) + return flags + + +def build_af3_command( + input_json: Path | str, + output_dir: Path | str, + cfg: Af3Config, + mode: str = "full", +) -> List[str]: + """Build the argv for one AlphaFold 3 invocation (no shell).""" + input_json = Path(input_json).resolve() + output_dir = Path(output_dir).resolve() + needs_models = mode != "data_pipeline" + needs_dbs = mode != "inference" + + if cfg.runner == "command": + if not cfg.command: + raise ValueError("af3_runner=command needs af3_command") + placeholders = { + "input_json": str(input_json), + "input_dir": str(input_json.parent), + "json_name": input_json.name, + "output_dir": str(output_dir), + "model_dir": str(cfg.model_dir or ""), + "db_dir": str(cfg.db_dir or ""), + "gpus": "" if str(cfg.gpus) == "all" else str(cfg.gpus), + } + argv = [ + os.path.expanduser(part.format(**placeholders)) + for part in shlex.split(cfg.command) + ] + argv = [a for a in argv if a != ""] + if cfg.append_flags: + # Paths are the wrapper's business; only pass stage/sampling flags. + argv += af3_flags(cfg, mode) + return argv + + if needs_models and not cfg.model_dir: + raise ValueError("AlphaFold 3 inference needs a model directory (--model_params)") + if needs_dbs and not cfg.db_dir: + raise ValueError( + "The AlphaFold 3 data pipeline needs a database directory (--database)" + ) + + mounts = [ + (str(input_json.parent), CONTAINER_INPUT_DIR, True), + (str(output_dir), CONTAINER_OUTPUT_DIR, False), + ] + if needs_models: + mounts.append((str(Path(cfg.model_dir).expanduser().resolve()), + CONTAINER_MODEL_DIR, True)) + if needs_dbs: + mounts.append((str(Path(cfg.db_dir).expanduser().resolve()), + CONTAINER_DB_DIR, True)) + + flags = af3_flags( + cfg, + mode, + json_path=f"{CONTAINER_INPUT_DIR}/{input_json.name}", + output_dir=CONTAINER_OUTPUT_DIR, + model_dir=CONTAINER_MODEL_DIR if needs_models else None, + db_dir=CONTAINER_DB_DIR if needs_dbs else None, + ) + + if cfg.runner == "docker": + argv = ["docker", "run", "--rm"] + if mode != "data_pipeline": + argv += _gpu_docker_flags(cfg.gpus) + for src, dst, ro in mounts: + argv += ["--volume", f"{src}:{dst}" + (":ro" if ro else "")] + argv += [cfg.image, "python", cfg.run_script] + return argv + flags + + if cfg.runner in ("apptainer", "singularity"): + script = cfg.run_script + if not script.startswith("/"): + script = f"{CONTAINER_APP_DIR}/{script}" + argv = [cfg.runner, "exec"] + if mode != "data_pipeline" and str(cfg.gpus).lower() != "cpu": + argv.append("--nv") + for src, dst, ro in mounts: + argv += ["--bind", f"{src}:{dst}" + (":ro" if ro else "")] + argv += [str(Path(cfg.image).expanduser()), "python", script] + return argv + flags + + raise ValueError(f"Unknown af3_runner {cfg.runner!r}, expected one of {RUNNERS}") + + +def af3_subprocess_env(cfg: Af3Config, environ: Optional[Mapping] = None) -> Dict: + env = dict(os.environ if environ is None else environ) + env.pop("LD_PRELOAD", None) + gpus = str(cfg.gpus) + if cfg.runner in ("apptainer", "singularity", "command") and gpus.lower() not in ( + "all", "cpu" + ): + physical = to_physical(gpus, environ=env) + env["CUDA_VISIBLE_DEVICES"] = physical + env["APPTAINERENV_CUDA_VISIBLE_DEVICES"] = physical + env["SINGULARITYENV_CUDA_VISIBLE_DEVICES"] = physical + return env + + +def prepare_inference_input(params: dict) -> dict: + """Make an input valid for ``--run_data_pipeline=false``. + + AlphaFold 3 refuses protein/RNA chains without explicit MSA fields when the + data pipeline is skipped; missing fields become empty (single sequence). + """ + params = copy.deepcopy(params) + for entry in params.get("sequences", []): + if "protein" in entry: + protein = entry["protein"] + if protein.get("unpairedMsa") is None and not protein.get("unpairedMsaPath"): + logger.warning( + "AF3 inference-only: chain %s has no MSA, using single sequence", + protein.get("id"), + ) + protein["unpairedMsa"] = "" + if protein.get("pairedMsa") is None and not protein.get("pairedMsaPath"): + protein["pairedMsa"] = "" + if protein.get("templates") is None: + protein["templates"] = [] + elif "rna" in entry: + rna = entry["rna"] + if rna.get("unpairedMsa") is None and not rna.get("unpairedMsaPath"): + rna["unpairedMsa"] = "" + return params + + +@dataclass +class Af3Sample: + seed: int + sample: int + cif: Path + summary: Optional[Path] + confidences: Optional[Path] + ranking_score: Optional[float] = None + + +@dataclass +class Af3Result: + job_dir: Path + name: str + data_json: Optional[Path] + top_model: Optional[Path] + top_summary: Optional[Path] + top_confidences: Optional[Path] + samples: List[Af3Sample] + + @property + def ok(self) -> bool: + return self.top_model is not None or bool(self.samples) + + +def find_af3_job_dir(output_dir: Path | str, name: str) -> Optional[Path]: + """Locate ``/`` or AF3's timestamped ``_YYYYMMDD_HHMMSS``.""" + output_dir = Path(output_dir) + base = sanitised_name(name) + candidates = [p for p in output_dir.glob(f"{base}*") if p.is_dir() and ( + p.name == base or p.name[len(base):].lstrip("_").replace("_", "").isdigit() + )] + if not candidates: + return None + return max(candidates, key=lambda p: p.stat().st_mtime) + + +def _first(paths: Sequence[Path]) -> Optional[Path]: + return sorted(paths)[0] if paths else None + + +def _read_ranking(job_dir: Path) -> Dict[tuple, float]: + scores: Dict[tuple, float] = {} + for csv_path in job_dir.glob("*ranking_scores.csv"): + with csv_path.open() as handle: + for row in csv.DictReader(handle): + try: + scores[(int(row["seed"]), int(row["sample"]))] = float( + row["ranking_score"] + ) + except (KeyError, ValueError): + continue + return scores + + +def parse_af3_output(output_dir: Path | str, name: str) -> Optional[Af3Result]: + job_dir = find_af3_job_dir(output_dir, name) + if job_dir is None: + return None + ranking = _read_ranking(job_dir) + samples: List[Af3Sample] = [] + for sample_dir in sorted(job_dir.glob("seed-*_sample-*")): + if not sample_dir.is_dir(): + continue + try: + seed_part, sample_part = sample_dir.name.split("_sample-") + seed = int(seed_part.split("seed-")[1]) + sample = int(sample_part) + except (IndexError, ValueError): + continue + cif = _first(list(sample_dir.glob("*model.cif"))) + if cif is None: + continue + summary = _first(list(sample_dir.glob("*summary_confidences.json"))) + confidences = _first([ + p for p in sample_dir.glob("*confidences.json") + if "summary" not in p.name + ]) + score = ranking.get((seed, sample)) + if score is None and summary is not None: + score = json.loads(summary.read_text()).get("ranking_score") + samples.append(Af3Sample(seed, sample, cif, summary, confidences, score)) + + top_model = _first([p for p in job_dir.glob("*_model.cif")]) + top_summary = _first(list(job_dir.glob("*_summary_confidences.json"))) + top_conf = _first([ + p for p in job_dir.glob("*_confidences.json") if "summary" not in p.name + ]) + data_json = _first(list(job_dir.glob("*_data.json"))) + return Af3Result(job_dir, name, data_json, top_model, top_summary, top_conf, + samples) + + +def run_af3( + input_params: dict, + output_dir: Path | str, + cfg: Af3Config, + mode: str = "full", + log_file: Optional[Path] = None, +) -> Af3Result: + """Run AlphaFold 3 for ``input_params`` and return the parsed result. + + Raises ``RuntimeError`` if the process fails or produces no output. + """ + output_dir = Path(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + name = input_params.get("name") + if not name: + raise ValueError("Input JSON must contain a non-empty 'name' field") + + params = prepare_inference_input(input_params) if mode == "inference" else \ + input_params + input_dir = output_dir / "af3_input" + input_dir.mkdir(exist_ok=True) + json_path = input_dir / f"{sanitised_name(name) or 'input'}.json" + json_path.write_text(json.dumps(params, indent=2)) + + argv = build_af3_command(json_path, output_dir, cfg, mode) + logger.info("Running AlphaFold 3 (%s): %s", mode, shlex.join(argv)) + log_file = log_file or output_dir / "af3.log" + start = time.monotonic() + with log_file.open("w") as log: + proc = subprocess.run(argv, stdout=log, stderr=subprocess.STDOUT, + env=af3_subprocess_env(cfg), check=False) + seconds = time.monotonic() - start + if proc.returncode != 0: + tail = log_file.read_text()[-2000:] + raise RuntimeError( + f"AlphaFold 3 exited with {proc.returncode} after {seconds:.0f}s; " + f"log {log_file}\n{tail}" + ) + result = parse_af3_output(output_dir, name) + if result is None: + raise RuntimeError(f"AlphaFold 3 produced no job directory in {output_dir}") + if mode == "data_pipeline": + if result.data_json is None: + raise RuntimeError(f"AlphaFold 3 data pipeline wrote no *_data.json in " + f"{result.job_dir}") + elif not result.ok: + raise RuntimeError(f"AlphaFold 3 wrote no model in {result.job_dir}") + return result diff --git a/abcfold/alphafold3/ccd_one_letter.py b/src/abcfold/alphafold3/ccd_one_letter.py similarity index 100% rename from abcfold/alphafold3/ccd_one_letter.py rename to src/abcfold/alphafold3/ccd_one_letter.py diff --git a/abcfold/alphafold3/check_install.py b/src/abcfold/alphafold3/check_install.py similarity index 100% rename from abcfold/alphafold3/check_install.py rename to src/abcfold/alphafold3/check_install.py diff --git a/abcfold/alphafold3/run_alphafold3.py b/src/abcfold/alphafold3/run_alphafold3.py similarity index 98% rename from abcfold/alphafold3/run_alphafold3.py rename to src/abcfold/alphafold3/run_alphafold3.py index 7a272ef..e8f817e 100644 --- a/abcfold/alphafold3/run_alphafold3.py +++ b/src/abcfold/alphafold3/run_alphafold3.py @@ -6,6 +6,7 @@ from pathlib import Path from typing import Union +from abcfold.gpus import docker_gpu_flags from abcfold.alphafold3.ccd_one_letter import CCD_NAME_TO_ONE_LETTER from abcfold.alphafold3.check_install import check_af3_install @@ -38,11 +39,7 @@ def _resolve_job_output_dir(input_json: Path) -> Path: def _gpu_flags(gpus: str) -> list[str]: - if gpus.lower() == "cpu": - return [] - if gpus.lower() == "all": - return ["--gpus", "all"] - return ["--gpus", f"device={gpus}"] + return docker_gpu_flags(gpus) def _build_alphafast_docker_cmd( diff --git a/abcfold/argparse_utils.py b/src/abcfold/argparse_utils.py similarity index 72% rename from abcfold/argparse_utils.py rename to src/abcfold/argparse_utils.py index 78fe50d..84b77a9 100644 --- a/abcfold/argparse_utils.py +++ b/src/abcfold/argparse_utils.py @@ -44,7 +44,63 @@ def main_argpase_util(parser): default="all", help="GPU device(s) to use, e.g. 'all', '0', '0,1', 'cpu'", ) + parser.add_argument( + "--allow_version_mismatch", + action="store_true", + help=dedent("[optional] Run a backend even if its env has a different \ + version than the pin in backends.toml (a warning is logged)"), + ) + + return parser + +def msa_argparse_util(parser): + parser.add_argument( + "--msa", + choices=["auto", "server", "custom", "af3", "none"], + default="auto", + help=dedent("[optional] MSA source shared by all backends. 'auto' reuses \ + MSAs present in the input JSON and otherwise leaves MSA generation to each \ + backend; 'server' queries the ColabFold MMseqs2 API (cached); 'custom' \ + reads --msa_a3m files; 'af3' reuses an AlphaFold 3 *_data.json; 'none' \ + runs single-sequence (default: auto)"), + ) + parser.add_argument( + "--msa_a3m", + nargs="+", + help=dedent("[optional] A3M file(s) for --msa custom, as CHAIN=path \ + (several chains: A,B=path) or a single path for every protein chain"), + ) + parser.add_argument( + "--msa_paired_a3m", + nargs="+", + help="[optional] Paired A3M file(s) for --msa custom, as CHAIN=path", + ) + parser.add_argument( + "--af3_data_json", + help=dedent("[optional] AlphaFold 3 data-pipeline output (*_data.json or \ + its directory) for --msa af3"), + ) + parser.add_argument( + "--msa_cache_dir", + help="[optional] MSA cache directory (default: ~/.cache/abcfold/msa)", + ) + parser.add_argument( + "--msa_server_url", + help="[optional] ColabFold MMseqs2 API URL (default: https://api.colabfold.com)", + ) + parser.add_argument( + "--min_msa_rows", + type=int, + default=None, + help=dedent("[optional] Fail when an MSA was requested but a chain (or a \ + backend's featurised input) has fewer rows; 0 disables (default: 10)"), + ) + parser.add_argument( + "--no_paired_msa", + action="store_true", + help="[optional] Do not request paired MSAs for heteromeric complexes", + ) return parser @@ -115,6 +171,15 @@ def prediction_argparse_util(parser): default=10, help="[optional] Number of recycles to use during inference (default: 10)", ) + parser.add_argument( + "--diffusion_steps", + "--sampling_steps", + dest="diffusion_steps", + type=int, + default=None, + help=dedent("[optional] Diffusion sampling steps for Boltz, Chai-1, \ + Protenix and OpenFold3 (default: each backend's own default, 200)"), + ) return parser @@ -208,16 +273,16 @@ def boltz_argparse_util(parser): parser.add_argument( "--boltz_preprocessing_threads", type=int, - default=2, + default=None, help=( "[optional] Boltz preprocessing threads for input preparation " - "(default: 2)." + "(default: from config, 2)." ), ) parser.add_argument( "--boltz_num_workers", type=int, - default=2, + default=None, help="[optional] Boltz dataloader workers during prediction (default: 2).", ) parser.add_argument( @@ -248,6 +313,10 @@ def protenix_argparse_util(parser): action="store_true", help="Run Protenix", ) + parser.add_argument( + "--protenix_model", + help="[optional] Protenix model name (default: pinned in backends.toml)", + ) return parser @@ -264,6 +333,17 @@ def openfold_argparse_util(parser): If not specified, will attempt to find or download parameters to \ ~/.openfold3/"), ) + parser.add_argument( + "--openfold_fetch_templates", + action="store_true", + help=dedent("[optional] Allow OpenFold3 to download template structures \ + from RCSB (off by default)"), + ) + parser.add_argument( + "--template_mirror_dir", + help=dedent("[optional] Local mmCIF mirror used for OpenFold3 templates \ + instead of downloading from RCSB"), + ) return parser @@ -319,6 +399,38 @@ def alphafold_argparse_util(parser): help="[optional] store AlphaFold3 distograms", ) + parser.add_argument( + "--af3_runner", + choices=["docker", "apptainer", "singularity", "command", "alphafast"], + help=dedent("[optional] How to run AlphaFold 3: official image via docker \ + or apptainer/singularity, a site wrapper (--af3_command), or the legacy \ + AlphaFast container (default: from config, docker)"), + ) + parser.add_argument( + "--af3_image", + help="[optional] Docker image name or .sif path for AlphaFold 3", + ) + parser.add_argument( + "--af3_command", + help=dedent("[optional] Wrapper command template for --af3_runner command, \ + e.g. '~/bin/alphafold3 {input_json} {output_dir} {gpus}'. Placeholders: \ + input_json, input_dir, json_name, output_dir, model_dir, db_dir, gpus"), + ) + stage = parser.add_mutually_exclusive_group() + stage.add_argument( + "--af3-data-pipeline-only", + dest="af3_data_pipeline_only", + action="store_true", + help="[optional] Only run the AlphaFold 3 data pipeline (MSA/templates)", + ) + stage.add_argument( + "--af3-inference-only", + dest="af3_inference_only", + action="store_true", + help=dedent("[optional] Skip the AlphaFold 3 data pipeline and reuse the \ + MSAs in the input (or from --msa)"), + ) + return parser @@ -356,6 +468,8 @@ def raise_argument_errors(args): if ( args.alphafold3 + and not getattr(args, "af3_data_pipeline_only", False) + and getattr(args, "af3_runner", None) != "command" and (not args.model_params or not Path(args.model_params).exists()) and not args.mmseqs2 ): @@ -393,6 +507,23 @@ def raise_argument_errors(args): logger.error("Number of recycles must be greater than 0") sys.exit(1) + diffusion_steps = getattr(args, "diffusion_steps", None) + if diffusion_steps is not None and diffusion_steps < 1: + logger.error("--diffusion_steps must be greater than 0") + sys.exit(1) + + if getattr(args, "mmseqs2", False) and getattr(args, "msa", "auto") != "auto": + logger.error("--mmseqs2 cannot be combined with --msa %s", args.msa) + sys.exit(1) + + if getattr(args, "msa", "auto") == "custom" and not getattr(args, "msa_a3m", None): + logger.error("--msa custom requires --msa_a3m") + sys.exit(1) + + if getattr(args, "msa", "auto") == "af3" and not getattr(args, "af3_data_json", None): + logger.error("--msa af3 requires --af3_data_json") + sys.exit(1) + if args.number_of_models < 1: logger.error("Number of models must be greater than 0") sys.exit(1) diff --git a/src/abcfold/backend_envs.py b/src/abcfold/backend_envs.py new file mode 100644 index 0000000..4b89d6d --- /dev/null +++ b/src/abcfold/backend_envs.py @@ -0,0 +1,362 @@ +"""Isolated backend environments. + +Environments are created and populated only by ``abcfold envs build``. During a +prediction ABCFold only *verifies* that the environment exists and carries the +pinned backend version; it never upgrades or downgrades packages in place. +""" + +from __future__ import annotations + +import json +import logging +import os +import shutil +import subprocess +import sys +import tempfile +import threading +from dataclasses import dataclass, field +from pathlib import Path +from typing import Dict, List, Mapping, Optional + +logger = logging.getLogger("logger") + +CURRENT_ENV = "@current" +FORBIDDEN_PACKAGES = ("rdkit-pypi",) + + +class BackendEnvError(RuntimeError): + """Raised when a backend environment is missing or does not match its pin.""" + + +def supports_cuda_wheels() -> bool: + return sys.platform.startswith("linux") + + +def _clean_env(extra: Optional[Mapping[str, str]] = None) -> Dict[str, str]: + env = dict(os.environ) + # Never leak an LD_PRELOAD shim (e.g. proxychains) into GPU workloads + env.pop("LD_PRELOAD", None) + if extra: + env.update({k: str(v) for k, v in extra.items() if v is not None}) + return env + + +class MicromambaEnv: + """A micromamba environment addressed by name, by prefix path, or the + current interpreter (``@current``, e.g. inside a backend container).""" + + def __init__(self, env_name: str): + self.env_name = env_name + self.is_current = env_name == CURRENT_ENV + self.is_prefix = not self.is_current and ( + os.sep in env_name or env_name.startswith("~") + ) + self.micromamba = None if self.is_current else self._find_micromamba() + + @staticmethod + def _find_micromamba() -> str: + for candidate in [ + os.environ.get("MAMBA_EXE"), + shutil.which("micromamba"), + os.path.expanduser("~/micromamba/bin/micromamba"), + os.path.expanduser("~/.local/bin/micromamba"), + ]: + if candidate and os.path.exists(candidate): + return candidate + raise BackendEnvError( + "micromamba binary not found. Install micromamba or set the backend " + "env to '@current' when running inside a backend image." + ) + + def _target(self) -> List[str]: + if self.is_prefix: + return ["-p", os.path.expanduser(self.env_name)] + return ["-n", self.env_name] + + def prefix_command(self, command: List[str]) -> List[str]: + if self.is_current: + if command and command[0] == "python": + return [sys.executable, *command[1:]] + return list(command) + assert self.micromamba is not None + return [self.micromamba, "run", *self._target(), *command] + + def get_installed_version(self, package: str) -> Optional[str]: + code = ( + "from importlib.metadata import version, PackageNotFoundError\n" + "import sys\n" + f"pkg={package!r}\n" + "try:\n" + " print(version(pkg))\n" + "except PackageNotFoundError:\n" + " sys.exit(3)" + ) + try: + out = subprocess.check_output( + self.prefix_command(["python", "-c", code]), + text=True, + env=_clean_env(), + stderr=subprocess.DEVNULL, + ) + return out.strip() or None + except (subprocess.CalledProcessError, FileNotFoundError): + return None + + def python_prefix(self) -> Optional[str]: + try: + out = subprocess.check_output( + self.prefix_command( + ["python", "-c", "import sys; print(sys.prefix)"] + ), + text=True, + env=_clean_env(), + stderr=subprocess.DEVNULL, + ) + return out.strip() + except (subprocess.CalledProcessError, FileNotFoundError): + return None + + def env_exists(self) -> bool: + if self.is_current: + return True + if self.is_prefix: + return Path(os.path.expanduser(self.env_name), "bin", "python").exists() + assert self.micromamba is not None + try: + out = subprocess.check_output( + [self.micromamba, "env", "list", "--json"], text=True, + env=_clean_env(), + ) + prefixes = json.loads(out).get("envs", []) + return any(Path(p).name == self.env_name for p in prefixes) + except (subprocess.CalledProcessError, ValueError): + return False + + def has_executable(self, name: str) -> bool: + code = f"import shutil,sys; sys.exit(0 if shutil.which({name!r}) else 1)" + try: + subprocess.check_call( + self.prefix_command(["python", "-c", code]), + env=_clean_env(), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + return True + except (subprocess.CalledProcessError, FileNotFoundError): + return False + + def run( + self, + command: List[str], + capture_output: bool = False, + quiet: bool = False, + extra_env: Optional[Mapping[str, str]] = None, + log_file: Optional[Path] = None, + ) -> Optional[str]: + """Run a command inside the env. + + stdout is streamed (and returned when ``capture_output``); stderr is + captured so that a failure carries the backend's error message. + """ + cmd = self.prefix_command(command) + env = _clean_env(extra_env) + stdout_lines: List[str] = [] + stderr_lines: List[str] = [] + + def pump(stream, sink, buffer): + for line in stream: + buffer.append(line) + if not quiet: + sink.write(line) + sink.flush() + + with subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + errors="replace", + env=env, + ) as proc: + assert proc.stdout is not None and proc.stderr is not None + err_thread = threading.Thread( + target=pump, args=(proc.stderr, sys.stderr, stderr_lines), + daemon=True, + ) + err_thread.start() + pump(proc.stdout, sys.stdout, stdout_lines) + proc.wait() + err_thread.join() + stdout, stderr = "".join(stdout_lines), "".join(stderr_lines) + if log_file is not None: + Path(log_file).write_text(stdout + "\n" + stderr) + if proc.returncode != 0: + raise subprocess.CalledProcessError( + proc.returncode, cmd, output=stdout, stderr=stderr + ) + return stdout if capture_output else None + + +@dataclass +class BackendEnvSpec: + name: str + package: str + version: str + env: str + python: str = "3.11" + pip: List[str] = field(default_factory=list) + conda: List[str] = field(default_factory=list) + overrides: List[str] = field(default_factory=list) + torch_backend: Optional[str] = None + + @classmethod + def from_settings(cls, name: str, pins: Mapping) -> "BackendEnvSpec": + return cls( + name=name, + package=pins["package"], + version=str(pins["version"]), + env=pins.get("env", f"abcfold2-{name}"), + python=str(pins.get("python", "3.11")), + pip=list(pins.get("pip", [])), + conda=list(pins.get("conda", [])), + overrides=list(pins.get("overrides", [])), + torch_backend=pins.get("torch_backend"), + ) + + +def build_commands( + spec: BackendEnvSpec, + micromamba: str = "micromamba", + uv: Optional[str] = "uv", + python_path: Optional[str] = None, + overrides_file: Optional[str] = None, +) -> List[List[str]]: + """Commands that create and populate a backend env (pure, for testing).""" + target = ["-p", spec.env] if os.sep in spec.env else ["-n", spec.env] + channels = ["-c", "conda-forge", "-c", "bioconda"] + cmds = [[micromamba, "create", "-y", *target, *channels, f"python={spec.python}", + *spec.conda]] + py = python_path or f"<{spec.env}>/bin/python" + if uv: + install = [uv, "pip", "install", "--python", py] + if spec.torch_backend: + install += ["--torch-backend", spec.torch_backend] + if spec.overrides: + install += ["--override", overrides_file or ""] + cmds.append([*install, *spec.pip]) + cmds.append([uv, "pip", "uninstall", "--python", py, *FORBIDDEN_PACKAGES]) + else: + install = [micromamba, "run", *target, "python", "-m", "pip", "install"] + if spec.torch_backend: + install += [ + "--extra-index-url", + f"https://download.pytorch.org/whl/{spec.torch_backend}", + ] + cmds.append([*install, *spec.pip, *spec.overrides]) + cmds.append([micromamba, "run", *target, "python", "-m", "pip", + "uninstall", "-y", *FORBIDDEN_PACKAGES]) + return cmds + + +def build_env(spec: BackendEnvSpec, dry_run: bool = False) -> List[List[str]]: + """Create the env and install the pinned packages. Refuses to touch an + existing env whose backend version differs from the pin.""" + env = MicromambaEnv(spec.env) + if env.is_current: + raise BackendEnvError("Cannot build the '@current' environment") + uv = shutil.which("uv") + if env.env_exists(): + installed = env.get_installed_version(spec.package) + if installed == spec.version: + logger.info("%s env %s already has %s==%s", spec.name, spec.env, + spec.package, installed) + return [] + if installed is not None: + raise BackendEnvError( + f"Env {spec.env} has {spec.package}=={installed}, pin is " + f"{spec.version}. ABCFold does not upgrade existing envs; build a " + f"new env (set [backends.{spec.name}] env = ...) instead." + ) + with tempfile.TemporaryDirectory() as tmp: + overrides_file = None + if spec.overrides: + overrides_file = str(Path(tmp, "overrides.txt")) + Path(overrides_file).write_text("\n".join(spec.overrides) + "\n") + assert env.micromamba is not None + cmds = build_commands(spec, micromamba=env.micromamba, uv=uv, + overrides_file=overrides_file) + if dry_run: + return cmds + create, *rest = cmds + if not env.env_exists(): + subprocess.check_call(create, env=_clean_env()) + prefix = env.python_prefix() + if prefix is None: + raise BackendEnvError(f"Could not locate the python of env {spec.env}") + cmds = build_commands(spec, micromamba=env.micromamba, uv=uv, + python_path=str(Path(prefix, "bin", "python")), + overrides_file=overrides_file) + subprocess.check_call(cmds[1], env=_clean_env()) + subprocess.call(cmds[2], env=_clean_env()) + return cmds + + +def verify_env(spec: BackendEnvSpec, allow_mismatch: bool = False) -> str: + """Check (never modify) a backend env. Returns the installed version.""" + env = MicromambaEnv(spec.env) + if not env.env_exists(): + raise BackendEnvError( + f"{spec.name} env '{spec.env}' does not exist. Build it with " + f"`abcfold envs build {spec.name}`." + ) + installed = env.get_installed_version(spec.package) + if installed is None: + raise BackendEnvError( + f"{spec.package} is not installed in env '{spec.env}'. Build it with " + f"`abcfold envs build {spec.name}` (or point the backend at another env)." + ) + if installed != spec.version: + msg = ( + f"{spec.package}=={installed} in env '{spec.env}' does not match the " + f"pinned version {spec.version}" + ) + if not allow_mismatch: + raise BackendEnvError( + msg + ". ABCFold does not upgrade envs at run time; build a new env " + "or override the pin in your config file." + ) + logger.warning(msg) + for forbidden in FORBIDDEN_PACKAGES: + if env.get_installed_version(forbidden) is not None: + raise BackendEnvError( + f"Env '{spec.env}' contains {forbidden}, which shadows rdkit. " + f"Remove it: micromamba run -n {spec.env} pip uninstall -y {forbidden}" + ) + return installed + + +def ensure_backend_env(name: str, config: Mapping) -> MicromambaEnv: + """Verify the env of ``name`` using the runtime config and return it.""" + settings = config.get("_settings") + if settings is None: + from abcfold.settings import load_settings + + settings = load_settings() + spec = BackendEnvSpec.from_settings(name, settings.backend(name)) + env = MicromambaEnv(spec.env) + if ( + not env.is_current + and not env.env_exists() + and settings.get("build_missing_envs", False) + ): + logger.info("Building missing %s env %s", name, spec.env) + build_env(spec) + allow = bool(config.get("allow_version_mismatch", False)) + if env.is_current: + installed = env.get_installed_version(spec.package) or "unknown" + else: + installed = verify_env(spec, allow_mismatch=allow) + env.installed_version = installed # type: ignore[attr-defined] + logger.info("%s %s (env %s)", name, installed, spec.env) + return env diff --git a/src/abcfold/backends.toml b/src/abcfold/backends.toml new file mode 100644 index 0000000..435e39f --- /dev/null +++ b/src/abcfold/backends.toml @@ -0,0 +1,69 @@ +# Read-only backend pins shipped with ABCFold. +# +# ABCFold never edits this file and never upgrades a backend environment while a +# prediction runs. Environments are built explicitly with `abcfold envs build` +# and verified (not modified) by `abcfold run`. A user config file +# (`--config-file` / ABCFOLD_CONFIG) may override `version`, `env` or `pip` per +# backend; the override is then used for both the build and the verification. +# +# Versions checked against PyPI and GitHub releases on 2026-10-16. + +schema = 1 + +[boltz] +package = "boltz" +version = "2.2.1" +python = "3.11" +env = "abcfold2-boltz" +pip = ["boltz[cuda]==2.2.1"] +torch_backend = "cu128" + +[chai1] +package = "chai_lab" +version = "0.6.1" +python = "3.11" +env = "abcfold2-chai" +# pyarrow: chai_lab reads MSAs as parquet but does not declare it +pip = ["chai_lab==0.6.1", "pandera==0.24.0", "pyarrow==21.0.0"] +conda = ["kalign2"] +torch_backend = "cu128" +# chai_lab 0.6.1 declares torch<2.7, but no torch<2.7 wheel supports Blackwell +# (sm_120). Chai-1 runs correctly on torch 2.11 (validated on the KRAS fixture). +overrides = ["torch==2.11.0"] + +[protenix] +package = "protenix" +version = "2.0.0" +python = "3.11" +env = "abcfold2-protenix" +# protenix 2.0.0 pins torch 2.7.1 and rdkit 2025.9.3; keep rdkit pinned and +# never install rdkit-pypi next to it (the older wheel shadows the new one). +pip = ["protenix==2.0.0", "rdkit==2025.9.3"] +torch_backend = "cu128" +# protenix-v2 weights are not public (the official URL returns 403); v1.0.0 is +# the newest public checkpoint and runs on the 2.0.0 code. +model = "protenix_base_default_v1.0.0" + +[openfold3] +package = "openfold3" +version = "0.5.0" +python = "3.11" +env = "abcfold2-openfold3" +pip = ["openfold3[cuequivariance]==0.5.0"] +conda = ["kalign2"] +torch_backend = "cu128" +checkpoint = "openbind-2025-06-30-174k" + +[rosettafold3] +package = "rc-foundry" +version = "0.1.12" +python = "3.12" +env = "abcfold2-rosettafold3" +pip = ["rc-foundry[rf3]==0.1.12"] + +[alphafold3] +# AlphaFold 3 runs through an external container/command (see `abcfold run +# --af3_runner`); the version is informational and reported in report.json. +package = "alphafold3" +version = "3.0.4" +image = "alphafold3" diff --git a/src/abcfold/batch.py b/src/abcfold/batch.py new file mode 100644 index 0000000..08e475a --- /dev/null +++ b/src/abcfold/batch.py @@ -0,0 +1,379 @@ +"""Batch mode: run many co-folding jobs from a CSV/JSON manifest. + +Manifest rows (CSV header or JSON object keys): + + id job id (required, unique; used as the job name) + protein protein sequence(s); several chains separated by ':' or ';' + af3_json path to an AlphaFold 3 input JSON (instead of protein/ligands) + smiles ligand SMILES; several separated by ';' + ccd ligand/ion CCD codes; several separated by ';' (e.g. "MG;GDP") + models engines, separated by ';', ',' or ' ' (default: boltz) + n_models samples per engine (optional) + seeds model seeds separated by ';' (optional, default 1) + +JSON manifests are a list of such objects or ``{"defaults": {...}, "jobs": +[...]}``; list values may be JSON arrays instead of separated strings. + +MSAs for all unique protein sequences are fetched once before the jobs start +(``--msa server``) and shared through the MSA cache. Each job runs ``abcfold +run`` in its own process; ``batch_status.json`` records per-job state and a +re-run skips completed jobs. +""" + +from __future__ import annotations + +import csv +import json +import logging +import os +import queue +import shlex +import string +import subprocess +import sys +import tempfile +import threading +import time +from concurrent.futures import ThreadPoolExecutor +from dataclasses import dataclass, field +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Dict, List, Mapping, Optional, Sequence + +logger = logging.getLogger("logger") + +STATUS_SCHEMA = "abcfold-batch-status-v1" +ENGINE_ALIASES = { + "alphafold3": "alphafold3", "af3": "alphafold3", "alphafold": "alphafold3", + "boltz": "boltz", "boltz2": "boltz", "boltz-2": "boltz", + "chai": "chai1", "chai1": "chai1", "chai-1": "chai1", + "protenix": "protenix", + "openfold3": "openfold3", "openfold": "openfold3", "of3": "openfold3", + "rosettafold3": "rosettafold3", "rf3": "rosettafold3", +} +ALL_ENGINES = ("alphafold3", "boltz", "chai1", "protenix", "openfold3", + "rosettafold3") +DONE_STATES = ("ok",) + + +class ManifestError(ValueError): + pass + + +@dataclass +class BatchJob: + id: str + params: dict + models: List[str] + n_models: Optional[int] = None + extra: Dict[str, Any] = field(default_factory=dict) + + @property + def protein_sequences(self) -> List[str]: + return [ + s["protein"]["sequence"] for s in self.params.get("sequences", []) + if "protein" in s + ] + + +def _split(value: Any, seps: str = ";") -> List[str]: + if value is None: + return [] + if isinstance(value, (list, tuple)): + return [str(v).strip() for v in value if str(v).strip()] + text = str(value) + for sep in seps[1:]: + text = text.replace(sep, seps[0]) + return [part.strip() for part in text.split(seps[0]) if part.strip()] + + +def parse_models(value: Any) -> List[str]: + names = _split(value, "; ,") or ["boltz"] + if len(names) == 1 and names[0].lower() == "all": + return list(ALL_ENGINES) + models = [] + for name in names: + key = ENGINE_ALIASES.get(name.lower()) + if key is None: + raise ManifestError(f"Unknown model {name!r}") + if key not in models: + models.append(key) + return models + + +def _chain_ids(): + letters = string.ascii_uppercase + for letter in letters: + yield letter + for first in letters: + for second in letters: + yield first + second + + +def build_job_params(row: Mapping[str, Any], base_dir: Path) -> dict: + job_id = str(row["id"]) + if row.get("af3_json"): + path = Path(str(row["af3_json"])).expanduser() + if not path.is_absolute(): + path = base_dir / path + params = json.loads(path.read_text()) + params["name"] = job_id + return params + + proteins = _split(row.get("protein") or row.get("proteins"), ";:") + smiles = _split(row.get("smiles") or row.get("ligand_smiles")) + ccds = _split(row.get("ccd") or row.get("ligand_ccd")) + if not proteins and not row.get("sequences"): + raise ManifestError(f"Job {job_id}: needs 'protein' or 'af3_json'") + ids = _chain_ids() + sequences: List[dict] = [] + for seq in proteins: + sequences.append({"protein": {"id": next(ids), "sequence": seq.upper()}}) + for smi in smiles: + sequences.append({"ligand": {"id": next(ids), "smiles": smi}}) + for ccd in ccds: + sequences.append({"ligand": {"id": next(ids), "ccdCodes": [ccd.upper()]}}) + seeds = [int(s) for s in _split(row.get("seeds"))] or [1] + return { + "name": job_id, + "modelSeeds": seeds, + "sequences": sequences, + "dialect": "alphafold3", + "version": 2, + } + + +def _rows_from_csv(path: Path) -> List[Dict[str, Any]]: + with path.open(newline="") as handle: + sample = handle.read(4096) + handle.seek(0) + dialect = csv.Sniffer().sniff(sample, delimiters=",\t") if sample else "excel" + reader = csv.DictReader(handle, dialect=dialect) + return [ + {k.strip().lower(): (v.strip() if isinstance(v, str) else v) + for k, v in row.items() if k} + for row in reader + if any((v or "").strip() for v in row.values() if isinstance(v, str)) + ] + + +def _rows_from_json(path: Path) -> List[Dict[str, Any]]: + data = json.loads(path.read_text()) + defaults: Dict[str, Any] = {} + if isinstance(data, dict): + defaults = data.get("defaults", {}) + data = data.get("jobs", []) + if not isinstance(data, list): + raise ManifestError("JSON manifest must be a list or {'jobs': [...]} ") + return [{**defaults, **{k.lower(): v for k, v in row.items()}} for row in data] + + +def parse_manifest(path: Path | str) -> List[BatchJob]: + path = Path(path) + if path.suffix.lower() == ".json": + rows = _rows_from_json(path) + elif path.suffix.lower() in (".csv", ".tsv"): + rows = _rows_from_csv(path) + else: + raise ManifestError(f"Manifest must be .csv, .tsv or .json: {path}") + jobs: List[BatchJob] = [] + seen = set() + for i, row in enumerate(rows, start=1): + job_id = str(row.get("id") or "").strip() + if not job_id: + raise ManifestError(f"Row {i}: missing 'id'") + if any(c in job_id for c in "/\\") or job_id in (".", ".."): + raise ManifestError(f"Row {i}: invalid id {job_id!r}") + if job_id in seen: + raise ManifestError(f"Duplicate job id {job_id!r}") + seen.add(job_id) + n_models = row.get("n_models") or row.get("number_of_models") + jobs.append(BatchJob( + id=job_id, + params=build_job_params({**row, "id": job_id}, path.parent), + models=parse_models(row.get("models")), + n_models=int(n_models) if n_models not in (None, "") else None, + )) + if not jobs: + raise ManifestError(f"No jobs in {path}") + return jobs + + +class BatchStatus: + """Thread-safe, atomically written ``batch_status.json``.""" + + def __init__(self, path: Path, manifest: Optional[Path] = None): + self.path = Path(path) + self.lock = threading.Lock() + if self.path.exists(): + self.data = json.loads(self.path.read_text()) + else: + self.data = {"schema": STATUS_SCHEMA, "manifest": None, "jobs": {}} + if manifest is not None: + self.data["manifest"] = str(manifest) + + def job(self, job_id: str) -> Dict[str, Any]: + return self.data["jobs"].get(job_id, {}) + + def is_done(self, job_id: str) -> bool: + return self.job(job_id).get("status") in DONE_STATES + + def update(self, job_id: str, **fields: Any) -> None: + with self.lock: + entry = self.data["jobs"].setdefault(job_id, {}) + entry.update(fields) + self.data["updated"] = datetime.now(timezone.utc).isoformat( + timespec="seconds" + ) + counts: Dict[str, int] = {} + for job in self.data["jobs"].values(): + counts[job.get("status", "pending")] = counts.get( + job.get("status", "pending"), 0) + 1 + self.data["counts"] = counts + self.path.parent.mkdir(parents=True, exist_ok=True) + fd, tmp = tempfile.mkstemp(dir=self.path.parent, prefix=".status.") + with os.fdopen(fd, "w") as handle: + json.dump(self.data, handle, indent=2) + os.replace(tmp, self.path) + + +def job_command( + job: BatchJob, + input_json: Path, + output_dir: Path, + gpu: Optional[str], + msa: str, + run_args: Sequence[str] = (), +) -> List[str]: + cmd = [sys.executable, "-m", "abcfold.cli", "run", str(input_json), + str(output_dir), "--override", "--no_visuals", "--msa", msa] + cmd += [f"--{engine}" for engine in job.models] + if job.n_models is not None: + cmd += ["--number_of_models", str(job.n_models)] + if gpu is not None: + cmd += ["--gpus", gpu] + return cmd + list(run_args) + + +def exit_status(code: int) -> str: + return {0: "ok", 2: "partial"}.get(code, "failed") + + +def prefetch_msas(jobs: Sequence[BatchJob], options) -> Dict[str, int]: + from abcfold.msa.resolve import prefetch_unique_sequences + + sequences = [s for job in jobs for s in job.protein_sequences] + if not sequences: + return {"fetched": 0, "cached": 0} + fetched, cached = prefetch_unique_sequences(sequences, options) + logger.info("MSA prefetch: %d fetched, %d already cached (%d unique)", + fetched, cached, fetched + cached) + return {"fetched": fetched, "cached": cached} + + +def run_batch( + manifest: Path | str, + output_dir: Path | str, + max_parallel: int = 1, + gpus: Optional[str] = None, + msa: str = "server", + msa_options=None, + run_args: Sequence[str] = (), + force: bool = False, + runner=None, +) -> Dict[str, Any]: + """Run every job of ``manifest``; returns the final status mapping. + + ``runner(cmd, log_path, env) -> int`` is injectable for tests. + """ + manifest = Path(manifest) + output_dir = Path(output_dir) + jobs = parse_manifest(manifest) + status = BatchStatus(output_dir / "batch_status.json", manifest) + inputs_dir = output_dir / "inputs" + logs_dir = output_dir / "logs" + jobs_dir = output_dir / "jobs" + for d in (inputs_dir, logs_dir, jobs_dir): + d.mkdir(parents=True, exist_ok=True) + + todo = [j for j in jobs if force or not status.is_done(j.id)] + for job in jobs: + if job not in todo: + logger.info("Skipping completed job %s", job.id) + elif status.job(job.id).get("status") != "pending": + status.update(job.id, status="pending", models=job.models) + + if msa == "server" and todo: + if msa_options is None: + from abcfold.msa.resolve import MsaOptions + + msa_options = MsaOptions(source="server") + try: + prefetch_msas(todo, msa_options) + except Exception as exc: # jobs will retry per complex + logger.error("MSA prefetch failed: %s", exc) + + gpu_list = _split(gpus, ",") if gpus and gpus.lower() not in ("all",) else [] + slots: "queue.Queue[Optional[str]]" = queue.Queue() + for i in range(max(1, max_parallel)): + slots.put(gpu_list[i % len(gpu_list)] if gpu_list else gpus) + + runner = runner or _subprocess_runner + + def execute(job: BatchJob) -> None: + gpu = slots.get() + try: + input_json = inputs_dir / f"{job.id}.json" + input_json.write_text(json.dumps(job.params, indent=2)) + job_out = jobs_dir / job.id + log_path = logs_dir / f"{job.id}.log" + cmd = job_command(job, input_json, job_out, gpu, msa, run_args) + started = time.monotonic() + status.update(job.id, status="running", gpu=gpu, + started=datetime.now(timezone.utc).isoformat( + timespec="seconds"), + output_dir=str(job_out), log=str(log_path), + command=shlex.join(cmd)) + try: + code = runner(cmd, log_path, None) + except Exception as exc: + code = 1 + log_path.write_text(f"{type(exc).__name__}: {exc}\n") + report = job_out / "report.json" + fields: Dict[str, Any] = { + "status": exit_status(code), + "exit_code": code, + "seconds": round(time.monotonic() - started, 2), + "finished": datetime.now(timezone.utc).isoformat(timespec="seconds"), + "report": str(report) if report.exists() else None, + } + if report.exists(): + try: + data = json.loads(report.read_text()) + fields["engines"] = { + e["engine"]: e["status"] for e in data.get("engines", []) + if e.get("status") != "skipped" + } + except (OSError, ValueError): + pass + status.update(job.id, **fields) + logger.info("Job %s: %s (%.0fs)", job.id, fields["status"], + fields["seconds"]) + finally: + slots.put(gpu) + + if max_parallel <= 1: + for job in todo: + execute(job) + else: + with ThreadPoolExecutor(max_workers=max_parallel) as pool: + list(pool.map(execute, todo)) + return status.data + + +def _subprocess_runner(cmd: List[str], log_path: Path, env) -> int: + env = dict(os.environ if env is None else env) + env.pop("LD_PRELOAD", None) + with log_path.open("w") as log: + return subprocess.run(cmd, stdout=log, stderr=subprocess.STDOUT, + env=env, check=False).returncode diff --git a/abcfold/boltz/__init__.py b/src/abcfold/boltz/__init__.py similarity index 100% rename from abcfold/boltz/__init__.py rename to src/abcfold/boltz/__init__.py diff --git a/abcfold/boltz/af3_to_boltz.py b/src/abcfold/boltz/af3_to_boltz.py similarity index 94% rename from abcfold/boltz/af3_to_boltz.py rename to src/abcfold/boltz/af3_to_boltz.py index 32f14f2..53a6ed4 100644 --- a/abcfold/boltz/af3_to_boltz.py +++ b/src/abcfold/boltz/af3_to_boltz.py @@ -451,9 +451,19 @@ def add_sequence_information(self, sequence_dict: dict): self.__non_ligands.extend(id_) - if self.msa_file is not None: + if self.msa_file == "empty": + # Explicit single-sequence mode (MSA source "none") + yaml_string += f"{DELIM}{DELIM}msa: empty\n" + elif self.msa_file is not None: + paired = sequence_dict.get("pairedMsa") + if paired: + from abcfold.msa.formats import a3m_to_boltz_csv + + msa_text = a3m_to_boltz_csv(sequence_dict.get("unpairedMsa"), paired) + else: + msa_text = sequence_dict["unpairedMsa"] ( - self.msa_to_file(sequence_dict["unpairedMsa"], self.msa_file) + self.msa_to_file(msa_text, self.msa_file) if self.__create_files else None ) @@ -489,14 +499,18 @@ def sequence_to_yaml(self, sequence_dict: dict, yaml_string: str = ""): """ for sequence_type, sequence_info_dict in sequence_dict.items(): yaml_string += self.add_title(sequence_type) - self.msa_file = ( - ( - Path(self.working_dir) - / f"{''.join(random.choices(string.ascii_letters, k=5))}.a3m" - ) - if "unpairedMsa" in sequence_info_dict - else None - ) + self.msa_file = None + if sequence_type == "protein" and ( + "unpairedMsa" in sequence_info_dict or "pairedMsa" in sequence_info_dict + ): + unpaired = sequence_info_dict.get("unpairedMsa") + paired = sequence_info_dict.get("pairedMsa") + if not unpaired and not paired: + self.msa_file = "empty" + else: + suffix = ".csv" if paired else ".a3m" + name = "".join(random.choices(string.ascii_letters, k=5)) + self.msa_file = Path(self.working_dir) / f"{name}{suffix}" yaml_string += self.add_sequence_information(sequence_info_dict) diff --git a/src/abcfold/boltz/check_install.py b/src/abcfold/boltz/check_install.py new file mode 100644 index 0000000..af87390 --- /dev/null +++ b/src/abcfold/boltz/check_install.py @@ -0,0 +1,10 @@ +import logging + +from abcfold.backend_envs import MicromambaEnv, ensure_backend_env + +logger = logging.getLogger("logger") + + +def ensure_boltz_env(config: dict) -> MicromambaEnv: + """Verify (never modify) the pinned boltz environment.""" + return ensure_backend_env("boltz", config) diff --git a/abcfold/boltz/crystal_modes.py b/src/abcfold/boltz/crystal_modes.py similarity index 100% rename from abcfold/boltz/crystal_modes.py rename to src/abcfold/boltz/crystal_modes.py diff --git a/abcfold/boltz/dock_crystal.py b/src/abcfold/boltz/dock_crystal.py similarity index 95% rename from abcfold/boltz/dock_crystal.py rename to src/abcfold/boltz/dock_crystal.py index 0163e7f..f0c6163 100644 --- a/abcfold/boltz/dock_crystal.py +++ b/src/abcfold/boltz/dock_crystal.py @@ -15,7 +15,6 @@ from Bio.PDB.PDBParser import PDBParser from abcfold.boltz.check_install import ensure_boltz_env -from abcfold.output.utils import verify_config_file @dataclass(frozen=True) @@ -197,8 +196,9 @@ def _parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument( "--config-file", type=Path, - default=Path.home() / ".abcfold_config.ini", - help="ABCFold config used when --runner abcfold-env is selected.", + default=None, + help="Optional read-only ABCFold config (TOML or legacy INI) used when " + "--runner abcfold-env is selected.", ) parser.add_argument( "--dry_run", @@ -481,20 +481,10 @@ def generate_boltz_crystal_dock_command( return cmd -def _load_config(config_file: Path) -> dict[str, str]: - default_config_file = Path(__file__).parents[1] / "data" / "config.ini" - config_file = config_file.expanduser() - if not config_file.exists(): - shutil.copy(default_config_file, config_file) - else: - verify_config_file(config_file, default_config_file) - - config = configparser.ConfigParser() - config.read(str(config_file)) - runtime_config = {} - for section in config.sections(): - runtime_config.update(dict(config.items(section))) - return runtime_config +def _load_config(config_file: Path | None) -> dict: + from abcfold.settings import load_settings + + return load_settings(config_file).runtime_config() def prepare_crystal_docking_input(args: argparse.Namespace) -> DockingInput: diff --git a/abcfold/boltz/run_boltz.py b/src/abcfold/boltz/run_boltz.py similarity index 94% rename from abcfold/boltz/run_boltz.py rename to src/abcfold/boltz/run_boltz.py index f50aa4a..1254f21 100644 --- a/abcfold/boltz/run_boltz.py +++ b/src/abcfold/boltz/run_boltz.py @@ -7,6 +7,7 @@ from pathlib import Path from typing import Iterable, Union +from abcfold.gpus import to_physical from abcfold.boltz.af3_to_boltz import BoltzYaml from abcfold.boltz.check_install import ensure_boltz_env from abcfold.boltz.crystal_modes import apply_crystal_mode @@ -48,6 +49,8 @@ def _boltz_cache_path(config: dict) -> str: def _apply_cuda_visible_devices(cmd: list[str], cuda_devices: str | None) -> list[str]: if cuda_devices is None: return cmd + if cuda_devices != "": + cuda_devices = to_physical(cuda_devices) return ["env", f"CUDA_VISIBLE_DEVICES={cuda_devices}", *cmd] @@ -70,6 +73,11 @@ def _run_command(env, cmd: list[str], output_dir: Path) -> str | None: raise +def _has_boltz_structures(output_dir: Path, input_stem: str) -> bool: + results = output_dir / f"boltz_results_{input_stem}" + return any(results.rglob("*_model_*.cif")) if results.exists() else False + + def _load_boltz_input( input_json: Path, boltz_mode: str, @@ -158,6 +166,7 @@ def run_boltz( preprocessing_threads: int | str | None = None, num_workers: int | str | None = None, max_parallel_samples: int | str | None = None, + sampling_steps: int = 200, ) -> bool: """ Run Boltz using the input JSON file @@ -235,6 +244,7 @@ def run_boltz( preprocessing_threads=preprocessing_threads, num_workers=num_workers, max_parallel_samples=max_parallel_samples, + sampling_steps=sampling_steps, ) if not test else generate_boltz_test_command() @@ -249,6 +259,11 @@ def run_boltz( stdout = _run_command(env, cmd, output_dir) if stdout is None: return False + if not _has_boltz_structures(output_dir, out_file.stem): + logger.error( + "Boltz exited without writing a structure for seed %s", seed + ) + return False except ValueError as e: logger.error("Invalid GPU configuration: %s", e) @@ -284,6 +299,7 @@ def run_boltz_batch( num_workers: int | str | None = 2, max_parallel_samples: int | str | None = None, parallel_seeds: bool = True, + sampling_steps: int = 200, ) -> bool: """ Run Boltz over many AlphaFold3 JSON files using one Boltz invocation per seed. @@ -354,6 +370,7 @@ def run_boltz_batch( preprocessing_threads=preprocessing_threads, num_workers=num_workers, max_parallel_samples=max_parallel_samples, + sampling_steps=sampling_steps, ) if not test else generate_boltz_test_command() @@ -413,6 +430,7 @@ def generate_boltz_command( preprocessing_threads: int | str | None = None, num_workers: int | str | None = None, max_parallel_samples: int | str | None = None, + sampling_steps: int = 200, ) -> list: """ Generate the Boltz command @@ -451,10 +469,10 @@ def generate_boltz_command( str(number_of_models), "--recycling_steps", str(num_recycles), - # Do not lower this without full validation: - # 5 sampling steps produced physically invalid structures. + # Default 200. Do not lower without validation: 5 sampling steps + # produced physically invalid structures. "--sampling_steps", - "200", + str(int(sampling_steps)), "--seed", str(seed), "--cache", diff --git a/abcfold/boltz/score_existing.py b/src/abcfold/boltz/score_existing.py similarity index 100% rename from abcfold/boltz/score_existing.py rename to src/abcfold/boltz/score_existing.py diff --git a/abcfold/chai1/af3_to_chai.py b/src/abcfold/chai1/af3_to_chai.py similarity index 90% rename from abcfold/chai1/af3_to_chai.py rename to src/abcfold/chai1/af3_to_chai.py index fe2c80b..87212e2 100644 --- a/abcfold/chai1/af3_to_chai.py +++ b/src/abcfold/chai1/af3_to_chai.py @@ -131,41 +131,23 @@ def bonded_pairs_to_file(self, bonded_pairs, fasta_data: dict): if not df.empty and self.__create_files: df.to_csv(self.constraints, sep=",", index=False) - def msa_to_file(self, msa: str, file_path: Union[str, Path]): - from abcfold.chai1.check_install import ensure_chai_env - chai_env = ensure_chai_env(self.config) - file_path = Path(file_path).absolute() - - code = textwrap.dedent(f""" - from pathlib import Path - from tempfile import NamedTemporaryFile - from chai_lab.data.parsing.msas.aligned_pqt import merge_multi_a3m_to_aligned_dataframe - from chai_lab.data.parsing.msas.data_source import MSADataSource - - msa_string = {msa!r} - output_file = Path({str(file_path)!r}) - - with NamedTemporaryFile(suffix='.a3m', mode='w') as f: - f.write(msa_string) - f.flush() - df = merge_multi_a3m_to_aligned_dataframe( - msa_a3m_files={{Path(f.name): MSADataSource.UNIPROT}}, - insert_keys_for_sources='uniprot' - ) - - if not df.empty: - df.to_parquet(output_file) - """) # noqa E501 - - with NamedTemporaryFile("w", suffix=".py", delete=False) as f: - script_path = Path(f.name) - f.write(code) + def msa_to_file( + self, + msa: str, + file_path: Union[str, Path], + paired_msa: Optional[str] = None, + ): + """Write an A3M (plus optional paired A3M) as Chai's aligned parquet. + + Paired rows carry their row index as pairing key so Chai pairs them + across chains; the conversion runs in-process (no backend env needed). + """ + from abcfold.msa.formats import chai_msa_frame - try: - chai_env.run(["python", str(script_path)], quiet=True) - logger.debug("Successfully wrote PQT file to %s", file_path) - finally: - script_path.unlink() + df = chai_msa_frame(msa, paired_msa) + if not df.empty: + df.to_parquet(Path(file_path).absolute()) + logger.debug("Wrote Chai MSA parquet to %s", file_path) def json_to_fasta(self, json_file_or_dict: Union[dict, str, Path]): """ @@ -250,11 +232,12 @@ def _add_protein(self, seq: dict, prot_id: str, fasta_data: dict): seq_hash = hashlib.sha256(sequence.upper().encode()).hexdigest() pqt_path = Path(self.working_dir) / f"{seq_hash}.aligned.pqt" - ( - self.msa_to_file(msa=msa, file_path=pqt_path) - if self.__create_files - else None - ) + if self.__create_files and (msa or seq["protein"].get("pairedMsa")): + self.msa_to_file( + msa=msa, + file_path=pqt_path, + paired_msa=seq["protein"].get("pairedMsa"), + ) fasta_data[prot_id] = sequence if "modifications" in seq["protein"]: diff --git a/abcfold/chai1/chai.py b/src/abcfold/chai1/chai.py similarity index 100% rename from abcfold/chai1/chai.py rename to src/abcfold/chai1/chai.py diff --git a/src/abcfold/chai1/check_install.py b/src/abcfold/chai1/check_install.py new file mode 100644 index 0000000..72e0030 --- /dev/null +++ b/src/abcfold/chai1/check_install.py @@ -0,0 +1,10 @@ +import logging + +from abcfold.backend_envs import MicromambaEnv, ensure_backend_env + +logger = logging.getLogger("logger") + + +def ensure_chai_env(config: dict) -> MicromambaEnv: + """Verify (never modify) the pinned chai1 environment.""" + return ensure_backend_env("chai1", config) diff --git a/abcfold/chai1/run_chai1_fast.py b/src/abcfold/chai1/run_chai1_fast.py similarity index 92% rename from abcfold/chai1/run_chai1_fast.py rename to src/abcfold/chai1/run_chai1_fast.py index 6598207..15fbf85 100644 --- a/abcfold/chai1/run_chai1_fast.py +++ b/src/abcfold/chai1/run_chai1_fast.py @@ -56,6 +56,7 @@ def run_chai_fast( use_templates_server: bool = False, template_hits_path: Path | None = None, device: str | None = None, + diffusion_steps: int = 200, ) -> bool: return run_chai_batch( [input_json], @@ -74,6 +75,7 @@ def run_chai_fast( devices=device, nested_outputs=False, postprocess=False, + diffusion_steps=diffusion_steps, ) @@ -90,6 +92,7 @@ def run_chai_batch( devices: str | None = None, nested_outputs: bool = True, postprocess: bool = True, + diffusion_steps: int = 200, ) -> bool: input_paths = [Path(path) for path in input_jsons] if not input_paths: @@ -127,6 +130,7 @@ def run_chai_batch( work_root=temp_dir, number_of_models=number_of_models, num_recycles=num_recycles, + diffusion_steps=diffusion_steps, ) worker_script = _write_worker_script(temp_dir) repo_root = Path(__file__).resolve().parents[2] @@ -141,8 +145,12 @@ def run_manifest(manifest_path: Path) -> bool: "--repo-root", str(repo_root), ] + extra_env = {} + downloads = config.get("chai_downloads_dir") + if downloads: + extra_env["CHAI_DOWNLOADS_DIR"] = str(Path(str(downloads)).expanduser()) try: - env.run(cmd) + env.run(cmd, extra_env=extra_env) except subprocess.CalledProcessError as e: _write_error_log(Path(output_dir), e) return False @@ -159,6 +167,15 @@ def run_manifest(manifest_path: Path) -> bool: if not run_manifest(manifests[0]): return False + missing = [ + task["output_dir"] + for task in tasks + if not list(Path(task["output_dir"]).glob("pred.model_idx_*.cif")) + ] + if missing: + logger.error("Chai-1 exited without writing structures in %s", missing) + return False + if postprocess: _postprocess_cases(tasks, config=config, save_input=save_input) @@ -224,6 +241,7 @@ def _write_device_manifests( work_root: Path, number_of_models: int, num_recycles: int, + diffusion_steps: int = 200, ) -> list[Path]: per_device: list[list[dict]] = [[] for _ in devices] for index, task in enumerate(tasks): @@ -232,6 +250,7 @@ def _write_device_manifests( task["device"] = devices[device_index] task["number_of_models"] = number_of_models task["num_recycles"] = num_recycles + task["diffusion_steps"] = diffusion_steps per_device[device_index].append(task) manifests = [] @@ -279,7 +298,7 @@ def _write_worker_script(work_root: Path) -> Path: use_templates_server=task["use_templates_server"], template_hits_path=template_hits_path, num_trunk_recycles=task["num_recycles"], - num_diffn_timesteps=200, + num_diffn_timesteps=task.get("diffusion_steps", 200), num_diffn_samples=task["number_of_models"], seed=task["seed"], device=task["device"], diff --git a/src/abcfold/cli.py b/src/abcfold/cli.py new file mode 100644 index 0000000..6c26197 --- /dev/null +++ b/src/abcfold/cli.py @@ -0,0 +1,209 @@ +"""``abcfold`` command line: run, msa, batch and envs subcommands. + +``abcfold input.json out_dir [flags]`` (no subcommand) is the same as +``abcfold run input.json out_dir [flags]``. +""" + +from __future__ import annotations + +import argparse +import json +import logging +import sys +from pathlib import Path +from typing import List, Optional + +SUBCOMMANDS = ("run", "msa", "batch", "envs") + +logger = logging.getLogger("logger") + + +def _msa_main(argv: List[str]) -> int: + from abcfold.msa.export import FORMATS, export_msas + from abcfold.msa.resolve import (SOURCES, MsaOptions, parse_chain_paths, + resolve_msas) + from abcfold.msa.stats import write_msa_stats + from abcfold.scripts.abc_script_utils import setup_logger + from abcfold.settings import load_settings + + setup_logger() + parser = argparse.ArgumentParser( + prog="abcfold msa", + description="Compute or collect MSAs for an AlphaFold 3 input JSON and " + "write them back into the JSON (plus msa_stats.json and optional " + "backend-specific files).", + ) + parser.add_argument("input_json") + parser.add_argument("output_dir") + parser.add_argument("--source", choices=[s for s in SOURCES if s != "auto"], + default="server") + parser.add_argument("--msa_a3m", nargs="+") + parser.add_argument("--msa_paired_a3m", nargs="+") + parser.add_argument("--af3_data_json") + parser.add_argument("--msa_cache_dir") + parser.add_argument("--msa_server_url") + parser.add_argument("--no_paired_msa", action="store_true") + parser.add_argument("--no_env", action="store_true", + help="Do not search the ColabFold environmental databases") + parser.add_argument("--format", nargs="+", default=[], + choices=list(FORMATS) + ["all"], + help="Also write backend-native MSA files") + parser.add_argument("--config-file", dest="config_file") + args = parser.parse_args(argv) + + settings = load_settings(args.config_file).apply_overrides({ + "msa_cache_dir": args.msa_cache_dir, + "msa_server_url": args.msa_server_url, + }) + options = MsaOptions( + source=args.source, + cache_dir=settings.get("msa_cache_dir"), + server_url=settings.get("msa_server_url"), + user_agent=settings.get("msa_user_agent", "abcfold"), + paired=not args.no_paired_msa, + use_env=not args.no_env, + custom_a3m=parse_chain_paths(args.msa_a3m), + custom_paired_a3m=parse_chain_paths(args.msa_paired_a3m), + af3_data_json=args.af3_data_json, + ) + params = json.loads(Path(args.input_json).read_text()) + result = resolve_msas(params, options) + out = Path(args.output_dir) + out.mkdir(parents=True, exist_ok=True) + out_json = out / f"{Path(args.input_json).stem}_msa.json" + out_json.write_text(json.dumps(result.params, indent=2)) + write_msa_stats(out / "msa_stats.json", result.chains, result.source, + result.seconds) + formats = list(FORMATS) if "all" in args.format else args.format + if formats: + export_msas(result.params, out / "msa", formats) + for chain, stats in result.chains.items(): + logger.info("chain %s: depth %d (paired %d)%s", chain, stats["depth"], + stats["paired_depth"], " [cached]" if stats["cached"] else "") + logger.info("Wrote %s", out_json) + return 0 + + +def _batch_main(argv: List[str]) -> int: + from abcfold.batch import run_batch + from abcfold.msa.resolve import MsaOptions + from abcfold.scripts.abc_script_utils import setup_logger + from abcfold.settings import load_settings + + setup_logger() + parser = argparse.ArgumentParser( + prog="abcfold batch", + description="Run many jobs from a CSV/JSON manifest. Flags after '--' " + "are passed to every `abcfold run`.", + ) + parser.add_argument("manifest") + parser.add_argument("output_dir") + parser.add_argument("--max-parallel", "--max_parallel", dest="max_parallel", + type=int, default=1) + parser.add_argument("--gpus", default=None, + help="GPU ids handed out round-robin to parallel jobs, " + "e.g. '1' or '1,2'") + parser.add_argument("--msa", default="server", + choices=["server", "auto", "none"]) + parser.add_argument("--msa_cache_dir") + parser.add_argument("--msa_server_url") + parser.add_argument("--force", action="store_true", + help="Re-run jobs that already completed") + parser.add_argument("--config-file", dest="config_file") + if "--" in argv: + split = argv.index("--") + argv, run_args = argv[:split], argv[split + 1:] + else: + run_args = [] + args = parser.parse_args(argv) + settings = load_settings(args.config_file).apply_overrides({ + "msa_cache_dir": args.msa_cache_dir, + "msa_server_url": args.msa_server_url, + }) + options = MsaOptions( + source="server", + cache_dir=settings.get("msa_cache_dir"), + server_url=settings.get("msa_server_url"), + user_agent=settings.get("msa_user_agent", "abcfold"), + ) + if args.config_file: + run_args = ["--config-file", args.config_file, *run_args] + for key in ("msa_cache_dir", "msa_server_url"): + if getattr(args, key): + run_args = [f"--{key}", getattr(args, key), *run_args] + status = run_batch( + args.manifest, args.output_dir, max_parallel=args.max_parallel, + gpus=args.gpus, msa=args.msa, msa_options=options, run_args=run_args, + force=args.force, + ) + counts = status.get("counts", {}) + logger.info("Batch finished: %s", counts) + failed = sum(v for k, v in counts.items() if k not in ("ok",)) + return 0 if failed == 0 else 2 + + +def _envs_main(argv: List[str]) -> int: + from abcfold.backend_envs import (BackendEnvError, BackendEnvSpec, + build_env, verify_env) + from abcfold.settings import BACKEND_NAMES, load_settings + + parser = argparse.ArgumentParser( + prog="abcfold envs", + description="Show, check or build the pinned backend environments.", + ) + parser.add_argument("action", choices=["show", "check", "build"]) + parser.add_argument("backends", nargs="*") + parser.add_argument("--dry-run", action="store_true") + parser.add_argument("--config-file", dest="config_file") + args = parser.parse_args(argv) + settings = load_settings(args.config_file) + names = args.backends or [n for n in BACKEND_NAMES if n != "alphafold3"] + code = 0 + for name in names: + pins = settings.backend(name) + if args.action == "show": + print(f"{name}: {pins.get('package')}=={pins.get('version')} " + f"env={pins.get('env')}") + continue + if "pip" not in pins: + print(f"{name}: not managed by ABCFold (container)") + continue + spec = BackendEnvSpec.from_settings(name, pins) + try: + if args.action == "check": + version = verify_env(spec) + print(f"{name}: OK {spec.package}=={version} ({spec.env})") + else: + cmds = build_env(spec, dry_run=args.dry_run) + for cmd in cmds: + print(" ".join(cmd)) + if not args.dry_run: + print(f"{name}: built {spec.env}") + except BackendEnvError as exc: + print(f"{name}: {exc}", file=sys.stderr) + code = 1 + return code + + +def main(argv: Optional[List[str]] = None) -> int: + argv = list(sys.argv[1:] if argv is None else argv) + if argv and argv[0] in ("-h", "--help"): + print(__doc__) + print("Subcommands: " + ", ".join(SUBCOMMANDS)) + print("Use `abcfold --help` for details.") + return 0 + command = argv[0] if argv and argv[0] in SUBCOMMANDS else "run" + rest = argv[1:] if argv and argv[0] in SUBCOMMANDS else argv + if command == "msa": + return _msa_main(rest) + if command == "batch": + return _batch_main(rest) + if command == "envs": + return _envs_main(rest) + from abcfold.abcfold import main as run_main + + return run_main(rest) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/abcfold/data/defaults.toml b/src/abcfold/data/defaults.toml new file mode 100644 index 0000000..af7e04b --- /dev/null +++ b/src/abcfold/data/defaults.toml @@ -0,0 +1,46 @@ +# Read-only ABCFold defaults. Override with a user config file +# (--config-file / ABCFOLD_CONFIG), ABCFOLD_ environment variables or CLI +# flags. ABCFold never writes this file or the user config file. +# An empty string means "unset". + +[paths] +# AlphaFold 3 weights and databases +model_params = "" +database_dir = "" +af3_sif_path = "" +# Backend weight caches (empty: the backend's own default, e.g. ~/.boltz) +boltz_weights = "" +openfold_weights = "" +rosettafold_weights = "" +protenix_root_dir = "" +# Shared across Chai envs so a new env does not re-download ~6.5 GB of weights +chai_downloads_dir = "~/.cache/abcfold/chai" +# Local PDB mmCIF mirror used for template structures (OpenFold3) +template_mirror_dir = "" + +[msa] +msa_cache_dir = "~/.cache/abcfold/msa" +msa_server_url = "https://api.colabfold.com" +msa_user_agent = "abcfold" +# Fail when an MSA was requested but a chain ends up with fewer rows (0 = off) +min_msa_rows = 10 + +[boltz] +boltz_preprocessing_threads = 2 +boltz_num_workers = 2 +boltz_max_parallel_samples = "" + +[alphafold3] +# docker | apptainer | command | alphafast +af3_runner = "docker" +af3_image = "alphafold3" +af3_run_script = "run_alphafold.py" +# Used when af3_runner = "command"; may contain {json_path} {json_dir} +# {json_name} {output_dir} {model_dir} {db_dir} {gpu} placeholders. +af3_command = "" +af3_append_flags = true +af3_docker_env = "romerolabduke/alphafast:latest" + +[runtime] +# Build a missing backend env on first use (never modifies an existing env) +build_missing_envs = false diff --git a/src/abcfold/gpus.py b/src/abcfold/gpus.py new file mode 100644 index 0000000..ffe1d22 --- /dev/null +++ b/src/abcfold/gpus.py @@ -0,0 +1,49 @@ +"""GPU selection relative to the GPUs this process was given.""" + +import os +from typing import Mapping, Optional + + +def to_physical(gpus: Optional[str], environ: Optional[Mapping] = None) -> Optional[str]: + """Translate ``--gpus`` indices into ids for a child ``CUDA_VISIBLE_DEVICES``. + + ``--gpus 0`` means the first GPU *visible to ABCFold*. Setting + ``CUDA_VISIBLE_DEVICES=0`` in a child process would instead select physical + GPU 0 and escape a Slurm or manual allocation such as + ``CUDA_VISIBLE_DEVICES=2``, so indices are mapped through the inherited mask. + + Returns None for "all"/None (inherit the parent mask unchanged) and "" for "cpu". + """ + if gpus is None: + return None + gpus = str(gpus).strip() + if gpus.lower() == "all": + return None + if gpus.lower() == "cpu": + return "" + environ = os.environ if environ is None else environ + parent = environ.get("CUDA_VISIBLE_DEVICES") + wanted = [g.strip() for g in gpus.split(",") if g.strip()] + if parent is None: + return ",".join(wanted) + visible = [g.strip() for g in parent.split(",") if g.strip()] + out = [] + for g in wanted: + if not g.isdigit() or int(g) >= len(visible): + raise ValueError( + f"--gpus {gpus}: index {g} is outside the GPUs given to ABCFold " + f"(CUDA_VISIBLE_DEVICES={parent})" + ) + out.append(visible[int(g)]) + return ",".join(out) + + +def docker_gpu_flags(gpus: Optional[str], environ: Optional[Mapping] = None) -> list: + """``docker run --gpus`` flags; docker sees host GPUs, so physical ids are needed.""" + if gpus is not None and str(gpus).strip().lower() == "cpu": + return [] + environ = os.environ if environ is None else environ + physical = to_physical(gpus, environ) + if physical is None: + physical = environ.get("CUDA_VISIBLE_DEVICES") + return ["--gpus", f"device={physical}"] if physical else ["--gpus", "all"] diff --git a/abcfold/html/abcfold.html.jinja2 b/src/abcfold/html/abcfold.html.jinja2 similarity index 100% rename from abcfold/html/abcfold.html.jinja2 rename to src/abcfold/html/abcfold.html.jinja2 diff --git a/abcfold/html/abcfold_vue.js b/src/abcfold/html/abcfold_vue.js similarity index 100% rename from abcfold/html/abcfold_vue.js rename to src/abcfold/html/abcfold_vue.js diff --git a/abcfold/html/bootstrap.css b/src/abcfold/html/bootstrap.css similarity index 100% rename from abcfold/html/bootstrap.css rename to src/abcfold/html/bootstrap.css diff --git a/abcfold/html/feature-viewer.bundle.js b/src/abcfold/html/feature-viewer.bundle.js similarity index 100% rename from abcfold/html/feature-viewer.bundle.js rename to src/abcfold/html/feature-viewer.bundle.js diff --git a/abcfold/html/html_utils.py b/src/abcfold/html/html_utils.py similarity index 100% rename from abcfold/html/html_utils.py rename to src/abcfold/html/html_utils.py diff --git a/abcfold/html/index.css b/src/abcfold/html/index.css similarity index 100% rename from abcfold/html/index.css rename to src/abcfold/html/index.css diff --git a/abcfold/html/jquery.js b/src/abcfold/html/jquery.js similarity index 100% rename from abcfold/html/jquery.js rename to src/abcfold/html/jquery.js diff --git a/abcfold/html/lodash.min.js b/src/abcfold/html/lodash.min.js similarity index 100% rename from abcfold/html/lodash.min.js rename to src/abcfold/html/lodash.min.js diff --git a/abcfold/html/static/ABCfold-logo.svg b/src/abcfold/html/static/ABCfold-logo.svg similarity index 100% rename from abcfold/html/static/ABCfold-logo.svg rename to src/abcfold/html/static/ABCfold-logo.svg diff --git a/abcfold/html/static/favicon.ico b/src/abcfold/html/static/favicon.ico similarity index 100% rename from abcfold/html/static/favicon.ico rename to src/abcfold/html/static/favicon.ico diff --git a/abcfold/html/static/favicon.svg b/src/abcfold/html/static/favicon.svg similarity index 100% rename from abcfold/html/static/favicon.svg rename to src/abcfold/html/static/favicon.svg diff --git a/abcfold/html/static/main_page_example.png b/src/abcfold/html/static/main_page_example.png similarity index 100% rename from abcfold/html/static/main_page_example.png rename to src/abcfold/html/static/main_page_example.png diff --git a/abcfold/html/static/pae_viewer_example.png b/src/abcfold/html/static/pae_viewer_example.png similarity index 100% rename from abcfold/html/static/pae_viewer_example.png rename to src/abcfold/html/static/pae_viewer_example.png diff --git a/abcfold/html/style.css b/src/abcfold/html/style.css similarity index 100% rename from abcfold/html/style.css rename to src/abcfold/html/style.css diff --git a/abcfold/html/vue.min.js b/src/abcfold/html/vue.min.js similarity index 100% rename from abcfold/html/vue.min.js rename to src/abcfold/html/vue.min.js diff --git a/src/abcfold/msa/__init__.py b/src/abcfold/msa/__init__.py new file mode 100644 index 0000000..c8815e8 --- /dev/null +++ b/src/abcfold/msa/__init__.py @@ -0,0 +1,14 @@ +"""MSA generation, caching and format conversion shared by all backends.""" + +from abcfold.msa.cache import MsaCache, msa_cache_key, paired_cache_key +from abcfold.msa.resolve import SOURCES, MsaOptions, MsaResult, resolve_msas + +__all__ = [ + "MsaCache", + "MsaOptions", + "MsaResult", + "SOURCES", + "msa_cache_key", + "paired_cache_key", + "resolve_msas", +] diff --git a/src/abcfold/msa/cache.py b/src/abcfold/msa/cache.py new file mode 100644 index 0000000..53d8902 --- /dev/null +++ b/src/abcfold/msa/cache.py @@ -0,0 +1,67 @@ +"""Content-addressed MSA cache. + +Unpaired MSAs are keyed by sha256 of (source, options, sequence). Paired MSAs +depend on the partner chains, so they are keyed by the ordered tuple of all +protein sequences of the complex plus the chain's index in that tuple. +""" + +from __future__ import annotations + +import hashlib +import json +import os +import tempfile +import time +from pathlib import Path +from typing import Dict, Optional, Sequence + +DEFAULT_CACHE_DIR = "~/.cache/abcfold/msa" + + +def normalize_sequence(sequence: str) -> str: + return "".join(sequence.split()).upper() + + +def msa_cache_key(sequence: str, source: str = "server", options: str = "") -> str: + payload = f"{source}\x1f{options}\x1f{normalize_sequence(sequence)}" + return hashlib.sha256(payload.encode()).hexdigest() + + +def paired_cache_key( + sequences: Sequence[str], index: int, source: str = "server", options: str = "" +) -> str: + joined = "\x1e".join(normalize_sequence(s) for s in sequences) + payload = f"paired\x1f{source}\x1f{options}\x1f{index}\x1f{joined}" + return hashlib.sha256(payload.encode()).hexdigest() + + +class MsaCache: + def __init__(self, cache_dir: Optional[os.PathLike | str] = None): + self.root = Path(cache_dir or DEFAULT_CACHE_DIR).expanduser() + + def _dir(self, key: str) -> Path: + return self.root / key[:2] / key + + def get(self, key: str) -> Optional[str]: + path = self._dir(key) / "msa.a3m" + if path.exists(): + return path.read_text() + return None + + def meta(self, key: str) -> Optional[Dict]: + path = self._dir(key) / "meta.json" + return json.loads(path.read_text()) if path.exists() else None + + def put(self, key: str, a3m: str, meta: Optional[Dict] = None) -> Path: + """Atomically store an MSA (safe for concurrent writers).""" + target = self._dir(key) + target.mkdir(parents=True, exist_ok=True) + for name, text in ( + ("msa.a3m", a3m), + ("meta.json", json.dumps({"created": time.time(), **(meta or {})})), + ): + fd, tmp = tempfile.mkstemp(dir=target, prefix=f".{name}.") + with os.fdopen(fd, "w") as handle: + handle.write(text) + os.replace(tmp, target / name) + return target / "msa.a3m" diff --git a/src/abcfold/msa/colabfold.py b/src/abcfold/msa/colabfold.py new file mode 100644 index 0000000..f4a6bc5 --- /dev/null +++ b/src/abcfold/msa/colabfold.py @@ -0,0 +1,171 @@ +"""Minimal client for the ColabFold MMseqs2 API (https://api.colabfold.com). + +Follows the protocol of ``colabfold.colabfold.run_mmseqs2``: submit a ticket, +poll it, download a tarball of A3M files whose records are grouped by query +id (101, 102, ...). +""" + +from __future__ import annotations + +import io +import logging +import random +import tarfile +import time +from typing import Callable, Dict, List, Optional, Sequence + +import requests + +from abcfold.msa.formats import format_a3m, parse_a3m + +logger = logging.getLogger("logger") + +DEFAULT_URL = "https://api.colabfold.com" +UNPAIRED_FILES = ("uniref.a3m", "bfd.mgnify30.metaeuk30.smag30.a3m") +PAIRED_FILES = ("pair.a3m",) +FIRST_ID = 101 + + +class ColabFoldError(RuntimeError): + pass + + +def split_colabfold_a3m(text: str) -> Dict[int, str]: + """Split a ColabFold result A3M into per-query blocks keyed by query id.""" + blocks: Dict[int, List[str]] = {} + current: Optional[int] = None + expect_id = True + for line in text.splitlines(keepends=True): + if "\x00" in line: + line = line.replace("\x00", "") + expect_id = True + if not line: + continue + if line.startswith(">") and expect_id: + try: + current = int(line[1:].strip()) + except ValueError: + pass + expect_id = False + blocks.setdefault(current, []) # type: ignore[arg-type] + if current is not None: + blocks[current].append(line) + return {k: "".join(v) for k, v in blocks.items()} + + +def merge_query_blocks(texts: Sequence[str], query_id: int) -> str: + """Concatenate per-database blocks of one query, keeping a single query row.""" + records = [] + for i, text in enumerate(texts): + for j, (header, seq) in enumerate(parse_a3m(text)): + if j == 0 and header.strip() == str(query_id): + if i > 0: + continue + header = "query" + records.append((header, seq)) + return format_a3m(records) + + +class ColabFoldClient: + def __init__( + self, + url: str = DEFAULT_URL, + user_agent: str = "abcfold", + session=None, + poll_seconds: float = 5.0, + timeout: float = 3600.0, + sleep: Callable[[float], None] = time.sleep, + ): + self.url = url.rstrip("/") + self.session = session or requests.Session() + self.headers = {"User-Agent": user_agent} + self.poll_seconds = poll_seconds + self.timeout = timeout + self.sleep = sleep + + def _json(self, response) -> dict: + try: + return response.json() + except ValueError: + return {"status": "ERROR", "error": response.text[:500]} + + def _submit(self, endpoint: str, sequences: Sequence[str], mode: str) -> dict: + query = "".join( + f">{FIRST_ID + i}\n{seq}\n" for i, seq in enumerate(sequences) + ) + while True: + out = self._json( + self.session.post( + f"{self.url}/{endpoint}", + data={"q": query, "mode": mode}, + headers=self.headers, + timeout=60, + ) + ) + if out.get("status") not in ("UNKNOWN", "RATELIMIT"): + return out + self.sleep(self.poll_seconds + random.random() * self.poll_seconds) + + def _wait(self, ticket: dict) -> str: + start = time.monotonic() + status = ticket.get("status") + ticket_id = ticket.get("id") + while status in ("UNKNOWN", "RUNNING", "PENDING"): + if time.monotonic() - start > self.timeout: + raise ColabFoldError(f"MSA ticket {ticket_id} timed out") + self.sleep(self.poll_seconds + random.random() * self.poll_seconds) + status = self._json( + self.session.get( + f"{self.url}/ticket/{ticket_id}", headers=self.headers, + timeout=60, + ) + ).get("status") + if status != "COMPLETE": + raise ColabFoldError( + f"ColabFold MSA server returned status {status}: {ticket}" + ) + return ticket_id + + def _download(self, ticket_id: str) -> Dict[str, str]: + response = self.session.get( + f"{self.url}/result/download/{ticket_id}", headers=self.headers, + timeout=600, + ) + files: Dict[str, str] = {} + with tarfile.open(fileobj=io.BytesIO(response.content), mode="r:gz") as tar: + for member in tar.getmembers(): + if member.isfile(): + handle = tar.extractfile(member) + if handle is not None: + files[member.name.split("/")[-1]] = handle.read().decode() + return files + + def _run(self, endpoint: str, sequences: Sequence[str], mode: str, + names: Sequence[str]) -> List[str]: + unique = list(dict.fromkeys(sequences)) + ticket = self._submit(endpoint, unique, mode) + if ticket.get("status") in ("ERROR", "MAINTENANCE"): + raise ColabFoldError(f"ColabFold MSA server error: {ticket}") + files = self._download(self._wait(ticket)) + per_file = [split_colabfold_a3m(files[n]) for n in names if n in files] + if not per_file: + raise ColabFoldError(f"No A3M files in ColabFold result: {list(files)}") + out = [] + for seq in sequences: + qid = FIRST_ID + unique.index(seq) + out.append(merge_query_blocks([blocks.get(qid, "") for blocks in per_file], + qid)) + return out + + def unpaired(self, sequences: Sequence[str], use_env: bool = True) -> List[str]: + """One unpaired A3M per input sequence (UniRef + environmental DBs).""" + mode = "env" if use_env else "all" + names = UNPAIRED_FILES if use_env else UNPAIRED_FILES[:1] + return self._run("ticket/msa", sequences, mode, names) + + def paired(self, sequences: Sequence[str], strategy: str = "greedy") -> List[str]: + """Row-aligned paired A3Ms, one per chain, in input order.""" + mode = "pairgreedy" if strategy == "greedy" else "paircomplete" + # As in ColabFold, pairing runs over the unique sequences; copies of a + # homomeric chain share the same paired rows. + return self._run("ticket/pair", sequences, mode, PAIRED_FILES) diff --git a/src/abcfold/msa/export.py b/src/abcfold/msa/export.py new file mode 100644 index 0000000..401bbaf --- /dev/null +++ b/src/abcfold/msa/export.py @@ -0,0 +1,102 @@ +"""Write resolved MSAs in each backend's native layout (``abcfold msa --format``).""" + +from __future__ import annotations + +import hashlib +from pathlib import Path +from typing import Dict, Iterable, List + +from abcfold.msa.formats import a3m_to_boltz_csv, chai_msa_frame +from abcfold.msa.resolve import protein_entities + +FORMATS = ("boltz", "chai1", "protenix", "openfold3") + + +def _chains(params: dict): + for protein in protein_entities(params): + ids = protein.get("id", []) + for chain in [ids] if isinstance(ids, str) else ids: + yield chain, protein + + +def export_boltz(params: dict, out_dir: Path) -> List[Path]: + """One file per chain: ``.csv`` when paired rows exist, else ``.a3m``.""" + out_dir.mkdir(parents=True, exist_ok=True) + written = [] + for chain, protein in _chains(params): + unpaired, paired = protein.get("unpairedMsa"), protein.get("pairedMsa") + if paired: + path = out_dir / f"{chain}.csv" + path.write_text(a3m_to_boltz_csv(unpaired, paired)) + else: + path = out_dir / f"{chain}.a3m" + path.write_text(unpaired or "") + written.append(path) + return written + + +def export_chai(params: dict, out_dir: Path) -> List[Path]: + """Chai-1 ``.aligned.pqt`` files (the name Chai looks up).""" + out_dir.mkdir(parents=True, exist_ok=True) + written = [] + seen = set() + for _, protein in _chains(params): + seq = protein["sequence"].upper() + if seq in seen: + continue + seen.add(seq) + frame = chai_msa_frame(protein.get("unpairedMsa"), protein.get("pairedMsa")) + if frame.empty: + continue + path = out_dir / f"{hashlib.sha256(seq.encode()).hexdigest()}.aligned.pqt" + frame.to_parquet(path) + written.append(path) + return written + + +def _write_pair(out_dir: Path, main_name: str, paired_name: str, protein: dict + ) -> List[Path]: + out_dir.mkdir(parents=True, exist_ok=True) + written = [] + main = out_dir / main_name + main.write_text(protein.get("unpairedMsa") or "") + written.append(main) + if protein.get("pairedMsa"): + paired = out_dir / paired_name + paired.write_text(protein["pairedMsa"]) + written.append(paired) + return written + + +def export_protenix(params: dict, out_dir: Path) -> List[Path]: + written: List[Path] = [] + for chain, protein in _chains(params): + written += _write_pair(out_dir / chain, "non_pairing.a3m", "pairing.a3m", + protein) + return written + + +def export_openfold3(params: dict, out_dir: Path) -> List[Path]: + written: List[Path] = [] + for chain, protein in _chains(params): + written += _write_pair(out_dir / chain, "colabfold_main.a3m", + "colabfold_paired.a3m", protein) + return written + + +EXPORTERS = { + "boltz": export_boltz, + "chai1": export_chai, + "protenix": export_protenix, + "openfold3": export_openfold3, +} + + +def export_msas(params: dict, out_dir: Path, formats: Iterable[str] + ) -> Dict[str, List[Path]]: + result = {} + for fmt in formats: + if fmt not in EXPORTERS: + raise ValueError(f"Unknown MSA format {fmt!r}, expected {FORMATS}") + result[fmt] = EXPORTERS[fmt](params, Path(out_dir) / fmt) + return result diff --git a/src/abcfold/msa/formats.py b/src/abcfold/msa/formats.py new file mode 100644 index 0000000..d70f0f8 --- /dev/null +++ b/src/abcfold/msa/formats.py @@ -0,0 +1,111 @@ +"""A3M helpers and conversions into backend-native MSA formats.""" + +from __future__ import annotations + +from typing import List, Optional, Tuple + +# Boltz limits (boltz.data.const) +BOLTZ_MAX_PAIRED_SEQS = 8192 +BOLTZ_MAX_MSA_SEQS = 16384 + + +def parse_a3m(text: Optional[str]) -> List[Tuple[str, str]]: + """Return ``[(header, sequence), ...]`` from an A3M string (no '>' in headers). + + Sequence lines of one record are concatenated. ``#`` comment lines and + null bytes (ColabFold separators) are skipped. + """ + records: List[Tuple[str, str]] = [] + if not text: + return records + header: Optional[str] = None + seq_parts: List[str] = [] + for raw in text.replace("\x00", "").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + if line.startswith(">"): + if header is not None: + records.append((header, "".join(seq_parts))) + header = line[1:] + seq_parts = [] + else: + seq_parts.append(line) + if header is not None: + records.append((header, "".join(seq_parts))) + return records + + +def format_a3m(records: List[Tuple[str, str]]) -> str: + return "".join(f">{h}\n{s}\n" for h, s in records) + + +def aligned_columns(sequence: str) -> str: + """Drop A3M insertions (lowercase letters and '.') -> query-aligned row.""" + return "".join(c for c in sequence if not (c.islower() or c == ".")) + + +def is_gap_row(sequence: str) -> bool: + return set(aligned_columns(sequence)) <= {"-"} + + +def a3m_to_boltz_csv(unpaired: Optional[str], paired: Optional[str] = None) -> str: + """Convert A3M MSAs into Boltz's ``key,sequence`` CSV. + + Paired rows get their row index as key (same key across chains = paired); + unpaired rows get key -1. Mirrors ``boltz.main.compute_msa``. + """ + keys: List[int] = [] + seqs: List[str] = [] + paired_rows = [s for _, s in parse_a3m(paired)][:BOLTZ_MAX_PAIRED_SEQS] + for idx, seq in enumerate(paired_rows): + if not is_gap_row(seq): + keys.append(idx) + seqs.append(seq) + unpaired_rows = [s for _, s in parse_a3m(unpaired)] + if seqs: + unpaired_rows = unpaired_rows[1:] # the query is already the first paired row + unpaired_rows = unpaired_rows[: max(0, BOLTZ_MAX_MSA_SEQS - len(seqs))] + keys += [-1] * len(unpaired_rows) + seqs += unpaired_rows + lines = ["key,sequence"] + [f"{k},{s}" for k, s in zip(keys, seqs)] + return "\n".join(lines) + "\n" + + +def chai_msa_frame(unpaired: Optional[str], paired: Optional[str] = None): + """Build Chai-1's aligned-parquet table from A3M strings. + + Follows ``chai_lab.data.dataset.msas.colabfold``: paired rows carry their + row index as ``pairing_key``; unpaired rows not already present get "". + """ + import pandas as pd + + paired_records = [ + (h, s) for h, s in parse_a3m(paired) if not is_gap_row(s) + ] + paired_keys = [str(i) for i, (_, s) in enumerate(parse_a3m(paired)) + if not is_gap_row(s)] + paired_seqs = {s for _, s in paired_records} + unpaired_records = [ + (h, s) + for i, (h, s) in enumerate(parse_a3m(unpaired)) + if (i > 0 or not paired_records) and not is_gap_row(s) and s not in paired_seqs + ] + records = paired_records + unpaired_records + keys = paired_keys + [""] * len(unpaired_records) + if not records: + return pd.DataFrame( + columns=["sequence", "source_database", "pairing_key", "comment"] + ) + sources = ["query"] + [ + "uniref90" if h.startswith("UniRef") else "bfd_uniclust" + for h, _ in records[1:] + ] + return pd.DataFrame( + { + "sequence": [s for _, s in records], + "source_database": sources, + "pairing_key": keys, + "comment": "", + } + ) diff --git a/src/abcfold/msa/guard.py b/src/abcfold/msa/guard.py new file mode 100644 index 0000000..359b8c0 --- /dev/null +++ b/src/abcfold/msa/guard.py @@ -0,0 +1,135 @@ +"""Guards against MSAs that are requested but silently lost on the way. + +A backend that gets an empty or near-empty MSA still produces a structure, +just a much worse one, so a lost MSA is easy to miss. These checks turn that +into an explicit failure. +""" + +from __future__ import annotations + +import re +from pathlib import Path +from typing import Iterable, List, Mapping, Optional + +from abcfold.msa.formats import is_gap_row, parse_a3m + +MIN_MSA_ROWS = 10 +N_MSA_PATTERN = re.compile(r"N_msa\s+(\d+)") + + +class ShallowMsaError(RuntimeError): + """An MSA was requested but the backend got fewer rows than allowed.""" + + +def min_msa_rows(config: Optional[Mapping] = None) -> int: + value = (config or {}).get("min_msa_rows") + if value in (None, "", "None"): + return MIN_MSA_ROWS + return int(value) + + +def msa_rows(unpaired: Optional[str], paired: Optional[str] = None) -> int: + """Number of distinct non-gap sequences (query included) in both MSAs.""" + seen = set() + for text in (paired, unpaired): + for _, seq in parse_a3m(text): + if not is_gap_row(seq): + seen.add(seq) + return len(seen) + + +def _read(path: Optional[str]) -> Optional[str]: + if not path: + return None + p = Path(path) + return p.read_text() if p.exists() else "" + + +def entity_msa_text(entity: Mapping) -> tuple[Optional[str], Optional[str]]: + unpaired = entity.get("unpairedMsa") + if unpaired is None: + unpaired = _read(entity.get("unpairedMsaPath")) + paired = entity.get("pairedMsa") + if paired is None: + paired = _read(entity.get("pairedMsaPath")) + return unpaired, paired + + +def msa_requested(entity: Mapping) -> bool: + """True when the input carries a non-empty MSA (or an MSA file path).""" + unpaired = entity.get("unpairedMsa") + paired = entity.get("pairedMsa") + return bool( + (isinstance(unpaired, str) and unpaired.strip()) + or (isinstance(paired, str) and paired.strip()) + or entity.get("unpairedMsaPath") + or entity.get("pairedMsaPath") + ) + + +def shallow_chains(params: Mapping, min_rows: int) -> List[str]: + """Protein chains whose requested MSA has fewer than ``min_rows`` rows.""" + out = [] + for entry in params.get("sequences", []): + protein = entry.get("protein") + if not protein or not msa_requested(protein): + continue + rows = msa_rows(*entity_msa_text(protein)) + if rows < min_rows: + ids = protein.get("id") + out.append(f"{ids}: {rows} rows") + return out + + +def check_input_msa_depth(params: Mapping, min_rows: int, + context: str = "input") -> None: + if min_rows <= 0: + return + shallow = shallow_chains(params, min_rows) + if shallow: + raise ShallowMsaError( + f"{context}: MSA requested but too shallow ({', '.join(shallow)}; " + f"minimum {min_rows}). Check the MSA source, or pass " + f"--min_msa_rows 0 for genuinely orphan proteins." + ) + + +def check_protenix_input(protenix_json: Iterable[Mapping], min_rows: int) -> None: + """Check the MSA files referenced by a Protenix input before running it.""" + if min_rows <= 0: + return + problems = [] + for job in protenix_json: + for entry in job.get("sequences", []): + chain = entry.get("proteinChain") + if not chain: + continue + for key in ("unpairedMsaPath", "pairedMsaPath"): + path = chain.get(key) + if path and not Path(path).exists(): + problems.append(f"{key} {path} does not exist") + if chain.get("unpairedMsaPath") or chain.get("unpairedMsa"): + rows = msa_rows(*entity_msa_text(chain)) + if rows < min_rows: + problems.append(f"chain {chain['sequence'][:10]}...: {rows} rows") + if problems: + raise ShallowMsaError( + "Protenix input has a missing or shallow MSA: " + "; ".join(problems) + ) + + +def parse_n_msa(log_text: str) -> List[int]: + return [int(m) for m in N_MSA_PATTERN.findall(log_text or "")] + + +def check_backend_n_msa(engine: str, log_text: str, min_rows: int) -> None: + """Fail if the backend logged an N_msa below ``min_rows``.""" + if min_rows <= 0: + return + values = parse_n_msa(log_text) + low = [v for v in values if v < min_rows] + if low: + raise ShallowMsaError( + f"{engine} used N_msa={min(low)} although an MSA was provided " + f"(minimum {min_rows}); the MSA was lost before featurisation." + ) diff --git a/src/abcfold/msa/resolve.py b/src/abcfold/msa/resolve.py new file mode 100644 index 0000000..845e248 --- /dev/null +++ b/src/abcfold/msa/resolve.py @@ -0,0 +1,279 @@ +"""Resolve MSAs for an AF3-format input from one of several sources. + +Sources: + server ColabFold MMseqs2 API (cached by sequence hash) + custom user-provided A3M files per chain + af3 a precomputed AlphaFold 3 data-pipeline JSON (``*_data.json``) + none single-sequence mode (empty MSAs for every backend) + auto reuse MSAs already present in the input, otherwise leave it untouched + +The result is written into the AF3 JSON fields (``unpairedMsa``, ``pairedMsa``, +``templates``) from which every backend converter derives its native format. +""" + +from __future__ import annotations + +import copy +import json +import logging +import time +from dataclasses import dataclass, field +from pathlib import Path +from typing import Dict, List, Optional, Sequence, Tuple + +from abcfold.msa.cache import MsaCache, msa_cache_key, normalize_sequence, \ + paired_cache_key +from abcfold.msa.colabfold import DEFAULT_URL, ColabFoldClient +from abcfold.msa.formats import parse_a3m +from abcfold.msa.stats import msa_chain_stats + +logger = logging.getLogger("logger") + +SOURCES = ("auto", "server", "custom", "af3", "none") + + +@dataclass +class MsaOptions: + source: str = "auto" + cache_dir: Optional[str] = None + server_url: str = DEFAULT_URL + user_agent: str = "abcfold" + paired: bool = True + use_env: bool = True + custom_a3m: Dict[str, str] = field(default_factory=dict) + custom_paired_a3m: Dict[str, str] = field(default_factory=dict) + af3_data_json: Optional[str] = None + + +@dataclass +class MsaResult: + params: dict + source: str + seconds: float + chains: Dict[str, dict] + + +def _ids(entity: dict) -> List[str]: + ids = entity.get("id", []) + return [ids] if isinstance(ids, str) else list(ids) + + +def protein_entities(params: dict) -> List[dict]: + return [s["protein"] for s in params.get("sequences", []) if "protein" in s] + + +def _ensure_af3_fields(protein: dict) -> None: + protein.setdefault("unpairedMsa", "") + protein.setdefault("pairedMsa", "") + if protein.get("templates") is None: + protein["templates"] = [] + + +def parse_chain_paths(items: Optional[Sequence[str]]) -> Dict[str, str]: + """Parse ``CHAIN=path`` items (``path`` alone applies to every chain: '*').""" + out: Dict[str, str] = {} + for item in items or []: + if "=" in item: + chain, path = item.split("=", 1) + for c in chain.split(","): + out[c.strip()] = path + else: + out["*"] = item + return out + + +def load_af3_data_json(path: str | Path) -> dict: + path = Path(path) + if path.is_dir(): + found = sorted(path.rglob("*_data.json")) + if not found: + raise FileNotFoundError(f"No *_data.json under {path}") + path = found[0] + return json.loads(path.read_text()) + + +def _stats_for(params: dict, source: str, seconds: Dict[str, float], + cached: Dict[str, bool]) -> Dict[str, dict]: + stats: Dict[str, dict] = {} + for protein in protein_entities(params): + seq = normalize_sequence(protein["sequence"]) + for chain in _ids(protein): + stats[chain] = msa_chain_stats( + protein.get("unpairedMsa"), + protein.get("pairedMsa"), + query_length=len(seq), + source=source, + seconds=seconds.get(seq, 0.0), + cached=cached.get(seq, False), + ) + return stats + + +def resolve_msas( + input_params: dict, + options: MsaOptions, + client: Optional[ColabFoldClient] = None, +) -> MsaResult: + params = copy.deepcopy(input_params) + proteins = protein_entities(params) + source = options.source + start = time.monotonic() + seconds: Dict[str, float] = {} + cached: Dict[str, bool] = {} + + if source not in SOURCES: + raise ValueError(f"Unknown MSA source '{source}', expected one of {SOURCES}") + + if source == "auto": + if proteins and all(p.get("unpairedMsa") is not None for p in proteins): + for p in proteins: + _ensure_af3_fields(p) + return MsaResult(params, "input", 0.0, _stats_for(params, "input", {}, {})) + return MsaResult(params, "backend", 0.0, {}) + + if source == "none": + for p in proteins: + p["unpairedMsa"] = "" + p["pairedMsa"] = "" + p["templates"] = p.get("templates") or [] + return MsaResult(params, "none", 0.0, _stats_for(params, "none", {}, {})) + + if source == "custom": + for p in proteins: + path = next( + (options.custom_a3m[c] for c in _ids(p) if c in options.custom_a3m), + options.custom_a3m.get("*"), + ) + if path is None and p.get("unpairedMsa") is None: + raise ValueError( + f"No custom A3M given for protein chain(s) {_ids(p)}" + ) + if path is not None: + text = Path(path).expanduser().read_text() + records = parse_a3m(text) + if not records: + raise ValueError(f"Custom A3M {path} has no sequences") + query = normalize_sequence(records[0][1].replace("-", "")) + if query != normalize_sequence(p["sequence"]): + raise ValueError( + f"First sequence of {path} does not match chain(s) {_ids(p)}" + ) + p["unpairedMsa"] = text + paired_path = next( + (options.custom_paired_a3m[c] for c in _ids(p) + if c in options.custom_paired_a3m), + None, + ) + if paired_path is not None: + p["pairedMsa"] = Path(paired_path).expanduser().read_text() + _ensure_af3_fields(p) + elapsed = time.monotonic() - start + return MsaResult(params, "custom", elapsed, + _stats_for(params, "custom", {}, {})) + + if source == "af3": + if not options.af3_data_json: + raise ValueError("MSA source 'af3' needs --af3_data_json") + data = load_af3_data_json(options.af3_data_json) + by_seq = { + normalize_sequence(p["sequence"]): p for p in protein_entities(data) + } + for p in proteins: + match = by_seq.get(normalize_sequence(p["sequence"])) + if match is None: + raise ValueError( + f"AF3 data JSON has no MSA for chain(s) {_ids(p)}" + ) + for key in ("unpairedMsa", "pairedMsa", "templates"): + if match.get(key) is not None: + p[key] = match[key] + _ensure_af3_fields(p) + # RNA MSAs from the AF3 pipeline are reused as well + rna_by_seq = { + normalize_sequence(s["rna"]["sequence"]): s["rna"] + for s in data.get("sequences", []) if "rna" in s + } + for s in params.get("sequences", []): + if "rna" in s: + match = rna_by_seq.get(normalize_sequence(s["rna"]["sequence"])) + if match and match.get("unpairedMsa") is not None: + s["rna"]["unpairedMsa"] = match["unpairedMsa"] + elapsed = time.monotonic() - start + return MsaResult(params, "af3", elapsed, _stats_for(params, "af3", {}, {})) + + # source == "server" + cache = MsaCache(options.cache_dir) + client = client or ColabFoldClient(options.server_url, options.user_agent) + opts = f"{options.server_url.rstrip('/')}|env={int(options.use_env)}" + unique = list(dict.fromkeys(normalize_sequence(p["sequence"]) for p in proteins)) + + unpaired: Dict[str, str] = {} + missing: List[str] = [] + for seq in unique: + hit = cache.get(msa_cache_key(seq, "server", opts)) + if hit is not None: + unpaired[seq] = hit + cached[seq] = True + else: + missing.append(seq) + if missing: + logger.info("Fetching unpaired MSAs for %d sequence(s) from %s", + len(missing), options.server_url) + t0 = time.monotonic() + fetched = client.unpaired(missing, use_env=options.use_env) + per_seq = (time.monotonic() - t0) / len(missing) + for seq, a3m in zip(missing, fetched): + unpaired[seq] = a3m + seconds[seq] = per_seq + cached[seq] = False + cache.put(msa_cache_key(seq, "server", opts), a3m, + {"kind": "unpaired", "source": "server", "options": opts, + "sequence": seq}) + + paired: Dict[str, str] = {} + if options.paired and len(unique) > 1: + keys = [paired_cache_key(unique, i, "server", opts) for i in range(len(unique))] + hits = [cache.get(k) for k in keys] + if all(h is not None for h in hits): + paired = dict(zip(unique, hits)) # type: ignore[arg-type] + else: + logger.info("Fetching paired MSAs for %d chains", len(unique)) + t0 = time.monotonic() + fetched = client.paired(unique) + share = (time.monotonic() - t0) / len(unique) + for i, (seq, a3m) in enumerate(zip(unique, fetched)): + paired[seq] = a3m + seconds[seq] = seconds.get(seq, 0.0) + share + cache.put(keys[i], a3m, {"kind": "paired", "source": "server", + "options": opts, "complex": unique}) + + for p in proteins: + seq = normalize_sequence(p["sequence"]) + p["unpairedMsa"] = unpaired[seq] + p["pairedMsa"] = paired.get(seq, "") + if p.get("templates") is None: + p["templates"] = [] + elapsed = time.monotonic() - start + return MsaResult(params, "server", elapsed, + _stats_for(params, "server", seconds, cached)) + + +def prefetch_unique_sequences( + sequences: Sequence[str], options: MsaOptions, + client: Optional[ColabFoldClient] = None, +) -> Tuple[int, int]: + """Fill the cache for many sequences with a single server request. + + Returns (number fetched, number already cached). + """ + cache = MsaCache(options.cache_dir) + opts = f"{options.server_url.rstrip('/')}|env={int(options.use_env)}" + unique = list(dict.fromkeys(normalize_sequence(s) for s in sequences)) + missing = [s for s in unique if cache.get(msa_cache_key(s, "server", opts)) is None] + if missing: + client = client or ColabFoldClient(options.server_url, options.user_agent) + for seq, a3m in zip(missing, client.unpaired(missing, options.use_env)): + cache.put(msa_cache_key(seq, "server", opts), a3m, + {"kind": "unpaired", "source": "server", "options": opts, + "sequence": seq}) + return len(missing), len(unique) - len(missing) diff --git a/src/abcfold/msa/stats.py b/src/abcfold/msa/stats.py new file mode 100644 index 0000000..54dddfb --- /dev/null +++ b/src/abcfold/msa/stats.py @@ -0,0 +1,76 @@ +"""MSA statistics written to ``msa_stats.json``.""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Dict, List, Optional + +from abcfold.msa.formats import aligned_columns, parse_a3m + +MAX_BINS = 200 +SCHEMA = "abcfold-msa-stats-v1" + + +def bin_values(values: List[int], max_bins: int = MAX_BINS) -> List[float]: + """Average ``values`` into at most ``max_bins`` contiguous bins.""" + n = len(values) + if n <= max_bins: + return [float(v) for v in values] + out = [] + for b in range(max_bins): + start = b * n // max_bins + end = (b + 1) * n // max_bins + chunk = values[start:end] + out.append(round(sum(chunk) / len(chunk), 3)) + return out + + +def msa_chain_stats( + unpaired: Optional[str], + paired: Optional[str] = None, + query_length: Optional[int] = None, + source: str = "none", + seconds: float = 0.0, + cached: bool = False, +) -> Dict: + """Depth and per-position coverage for one chain. + + depth: number of sequences (query included) in the unpaired MSA plus the + non-gap paired rows. coverage: number of non-gap residues per query column, + averaged into at most 200 bins. + """ + rows = [aligned_columns(s) for _, s in parse_a3m(unpaired)] + paired_rows = [ + aligned_columns(s) for _, s in parse_a3m(paired) + if set(aligned_columns(s)) - {"-"} + ] + length = query_length or (len(rows[0]) if rows else ( + len(paired_rows[0]) if paired_rows else 0)) + coverage = [0] * length + for row in rows + paired_rows: + for i, c in enumerate(row[:length]): + if c != "-": + coverage[i] += 1 + return { + "source": source, + "depth": len(rows), + "paired_depth": len(paired_rows), + "query_length": length, + "coverage": bin_values(coverage), + "coverage_bins": min(length, MAX_BINS), + "seconds": round(float(seconds), 3), + "cached": cached, + } + + +def write_msa_stats(path: Path, chains: Dict[str, Dict], source: str, + seconds: float) -> Dict: + data = { + "schema": SCHEMA, + "source": source, + "seconds": round(float(seconds), 3), + "chains": chains, + } + Path(path).write_text(json.dumps(data, indent=2)) + return data diff --git a/abcfold/openfold3/af3_to_openfold3.py b/src/abcfold/openfold3/af3_to_openfold3.py similarity index 71% rename from abcfold/openfold3/af3_to_openfold3.py rename to src/abcfold/openfold3/af3_to_openfold3.py index dd66387..a47c766 100644 --- a/abcfold/openfold3/af3_to_openfold3.py +++ b/src/abcfold/openfold3/af3_to_openfold3.py @@ -3,7 +3,7 @@ import random import string from pathlib import Path -from typing import Any, Dict, Union +from typing import Any, Dict, Optional, Union logger = logging.getLogger("logger") @@ -88,16 +88,16 @@ def json_to_json( if chain_entry: openfold_sequences.append(chain_entry) - if ( - "main_msa_file_paths" in chain_entry - and chain_entry["main_msa_file_paths"] - ): + q = self.openfold_dict["queries"][self.name] + if chain_entry.get("main_msa_file_paths"): if not query_flags_set: - q = self.openfold_dict["queries"][self.name] q["use_msas"] = True q["use_main_msas"] = True q["use_paired_msas"] = False query_flags_set = True + if chain_entry.get("paired_msa_file_paths"): + q["use_msas"] = True + q["use_paired_msas"] = True self.openfold_dict["queries"][self.name]["chains"] = openfold_sequences @@ -127,18 +127,22 @@ def convert_protein(self, seq_dict) -> Dict[str, Any]: ] = self.templates.resolve().as_posix() unpaired_msa = seq_dict.get("unpairedMsa") + paired_msa = seq_dict.get("pairedMsa") random_string = ''.join(random.choices(string.ascii_letters, k=5)) msa_dir = Path(self.working_dir) / random_string - if unpaired_msa and self.__create_files: + if unpaired_msa: msa_out = msa_dir / "colabfold_main.a3m" - if not msa_dir.exists(): + if self.__create_files: msa_dir.mkdir(parents=True, exist_ok=True) - self.msa_to_file( - unpaired_msa, - msa_out - ) - protein_chain["main_msa_file_paths"] = [ - msa_dir.resolve().as_posix() + self.msa_to_file(unpaired_msa, msa_out) + protein_chain["main_msa_file_paths"] = [msa_out.resolve().as_posix()] + if paired_msa: + paired_out = msa_dir / "colabfold_paired.a3m" + if self.__create_files: + msa_dir.mkdir(parents=True, exist_ok=True) + self.msa_to_file(paired_msa, paired_out) + protein_chain["paired_msa_file_paths"] = [ + paired_out.resolve().as_posix() ] return protein_chain @@ -216,20 +220,31 @@ def write_json(self, out_file: Union[str, Path]): with open(out_file, "w") as f: json.dump(self.openfold_dict, f, indent=4) - def write_yaml(self, out_file: Union[str, Path]): + def write_yaml( + self, + out_file: Union[str, Path], + num_recycles: Optional[int] = None, + diffusion_steps: Optional[int] = None, + fetch_templates: bool = False, + template_mirror_dir: Optional[Union[str, Path]] = None, + cache_dir: Optional[Union[str, Path]] = None, + ) -> str: """ - Write the OpenFold 3 runner yaml file + Write the OpenFold 3 runner yaml file. - Args: - out_file (Union[str, Path]): output file path - - Returns: - None + Template structures are fetched from RCSB only when ``fetch_templates`` + is True; otherwise OpenFold3 reads them from ``template_mirror_dir``. + Without either, templates are disabled. """ seeds_str = f"[{', '.join(str(s) for s in self.seeds)}]" - use_templates = False - if self.templates is not None: - use_templates = True + use_templates = self.templates is not None + if use_templates and not fetch_templates and not template_mirror_dir: + logger.warning( + "OpenFold3 templates need a local mmCIF mirror " + "(--template_mirror_dir) or --openfold_fetch_templates; " + "running OpenFold3 without templates" + ) + use_templates = False lines = [ "model_update:", @@ -242,19 +257,33 @@ def write_yaml(self, out_file: Union[str, Path]): " eval:", " use_cueq_triangle_kernels: true", " use_deepspeed_evo_attention: false", + ] + if num_recycles is not None or diffusion_steps is not None: + lines += [" architecture:", " shared:"] + if num_recycles is not None: + lines.append(f" num_recycles: {int(num_recycles)}") + if diffusion_steps is not None: + lines += [ + " diffusion:", + f" no_full_rollout_steps: {int(diffusion_steps)}", + ] + lines += [ "experiment_settings:", " mode: predict", f" seeds: {seeds_str}", f" use_templates: {str(use_templates).lower()}", + "template_preprocessor_settings:", + f" fetch_missing_structures: {str(bool(fetch_templates)).lower()}", ] + if template_mirror_dir: + mirror = Path(template_mirror_dir).expanduser().resolve().as_posix() + lines.append(f" structure_directory: {mirror}") + if cache_dir: + lines.append(f"cache_path: {Path(cache_dir).expanduser().as_posix()}") - yaml_string = "\n".join(lines) + yaml_string = "\n".join(lines) + "\n" - try: - out_path = Path(out_file) - if self.__create_files: - out_path.write_text(yaml_string) - except Exception: - logger.debug("Could not write yaml to %s", out_file) + if self.__create_files: + Path(out_file).write_text(yaml_string) return yaml_string diff --git a/src/abcfold/openfold3/check_install.py b/src/abcfold/openfold3/check_install.py new file mode 100644 index 0000000..f3e183c --- /dev/null +++ b/src/abcfold/openfold3/check_install.py @@ -0,0 +1,49 @@ +import logging +import os +from pathlib import Path +from typing import Optional + +from abcfold.backend_envs import MicromambaEnv, ensure_backend_env + +logger = logging.getLogger("logger") + +DEFAULT_CHECKPOINT = "openbind-2025-06-30-174k" + + +def ensure_openfold_env(config: dict) -> MicromambaEnv: + """Verify (never modify) the pinned OpenFold3 environment.""" + return ensure_backend_env("openfold3", config) + + +def openfold_cache_dir(config: dict) -> Path: + weights = config.get("openfold_weights") + if weights: + return Path(str(weights)).expanduser() + return Path(os.environ.get("OPENFOLD_CACHE", Path.home() / ".openfold3")) + + +def ensure_openfold_checkpoint( + env: MicromambaEnv, + cache_dir: Path, + checkpoint_name: Optional[str] = None, +) -> None: + """Download the pinned OpenFold3 parameters into ``cache_dir`` if missing. + + Uses OpenFold3's own downloader inside the backend env, so the checkpoint + registry always matches the installed OpenFold3 version. + """ + name = checkpoint_name or DEFAULT_CHECKPOINT + code = ( + "from pathlib import Path\n" + "from openfold3.entry_points.parameters import (\n" + " OPENFOLD_MODEL_CHECKPOINT_REGISTRY, download_model_parameters,\n" + " get_default_checkpoint_dir)\n" + f"d = get_default_checkpoint_dir(cache_path=Path({str(cache_dir)!r}))\n" + f"name = {name!r}\n" + "f = d / OPENFOLD_MODEL_CHECKPOINT_REGISTRY[name].file_name\n" + "if not f.exists():\n" + " download_model_parameters(d, name, skip_confirmation=True)\n" + "print(f)\n" + ) + cache_dir.mkdir(parents=True, exist_ok=True) + env.run(["python", "-c", code], quiet=True) diff --git a/src/abcfold/openfold3/run_openfold3.py b/src/abcfold/openfold3/run_openfold3.py new file mode 100644 index 0000000..11a820e --- /dev/null +++ b/src/abcfold/openfold3/run_openfold3.py @@ -0,0 +1,164 @@ +import logging +import subprocess +import tempfile +from pathlib import Path +from typing import Optional, Union + +from abcfold.gpus import to_physical +from abcfold.openfold3.af3_to_openfold3 import OpenfoldJson +from abcfold.openfold3.check_install import (ensure_openfold_checkpoint, + ensure_openfold_env, + openfold_cache_dir) + +logger = logging.getLogger("logger") + + +def run_openfold( + input_json: Union[str, Path], + output_dir: Union[str, Path], + config: dict, + save_input: bool = False, + test: bool = False, + number_of_models: int = 5, + template_hits_path: Path | None = None, + input_ckpt: Optional[Union[str, Path]] = None, + num_recycles: Optional[int] = None, + diffusion_steps: Optional[int] = None, + fetch_templates: bool = False, + template_mirror_dir: Optional[Union[str, Path]] = None, + gpus: str = "all", +) -> bool: + """ + Run OpenFold 3 using the input JSON file. + + Template structures are never fetched from RCSB unless ``fetch_templates`` + is set; ``template_mirror_dir`` points OpenFold3 at a local mmCIF mirror. + + Returns: + bool: True if the run produced at least one structure. + """ + input_json = Path(input_json) + output_dir = Path(output_dir) + + env = None + if not test: + logger.debug("Checking OpenFold3 environment") + env = ensure_openfold_env(config=config) + + ckpt_path: Optional[Path] = None + if input_ckpt is not None: + ckpt_path = Path(input_ckpt) + if not ckpt_path.exists(): + logger.error("OpenFold3 checkpoint not found: %s", ckpt_path) + return False + logger.info("Using user provided OpenFold3 checkpoint: %s", ckpt_path) + + cache_dir = openfold_cache_dir(config) + ckpt_name = config.get("openfold_checkpoint") + if ckpt_path is None and env is not None: + ensure_openfold_checkpoint(env, cache_dir, ckpt_name) + + with tempfile.TemporaryDirectory() as temp_dir: + working_dir = Path(temp_dir) + if save_input: + logger.info("Saving input json file and msa to the output directory") + working_dir = output_dir + + openfold_json = OpenfoldJson(working_dir, templates=template_hits_path) + openfold_json.json_to_json(input_json) + runner_yaml = working_dir / "openfold3_runner.yml" + openfold_json.write_yaml( + runner_yaml, + num_recycles=num_recycles, + diffusion_steps=diffusion_steps, + fetch_templates=fetch_templates, + template_mirror_dir=template_mirror_dir, + cache_dir=cache_dir, + ) + + for seed in openfold_json.seeds: + out_file = working_dir.joinpath(f"{input_json.stem}_seed-{seed}.json") + + openfold_json.write_json(out_file) + logger.info("Running OpenFold 3 using seed: %s", seed) + openfold_out_dir = output_dir / f"openfold_results_seed-{seed}" + cmd = ( + generate_openfold_command( + out_file, + openfold_out_dir, + runner_yaml, + ckpt_path, + number_of_models, + checkpoint_name=None if ckpt_path else ckpt_name, + ) + if not test + else generate_openfold_test_command() + ) + if test: + continue + + try: + assert env is not None + env.run(cmd, extra_env=_gpu_env(gpus) | {"OPENFOLD_CACHE": str(cache_dir)}) + except subprocess.CalledProcessError as e: + _write_error(output_dir, "openfold_error.log", e) + return False + + if not list(openfold_out_dir.rglob("*_model.cif")): + logger.error( + "OpenFold 3 exited without writing a structure for seed %s", seed + ) + return False + + logger.info("OpenFold 3 run complete") + logger.info("Output files are in %s", output_dir) + return True + + +def _gpu_env(gpus: str) -> dict: + if gpus in (None, "all"): + return {} + if gpus == "cpu": + return {"CUDA_VISIBLE_DEVICES": ""} + return {"CUDA_VISIBLE_DEVICES": to_physical(gpus)} + + +def _write_error(output_dir: Path, name: str, e: subprocess.CalledProcessError): + stderr = e.stderr or "" + output_dir.mkdir(parents=True, exist_ok=True) + err_file = output_dir / name + err_file.write_text(stderr) + logger.error("OpenFold 3 run failed. Error log is in %s", err_file) + + +def generate_openfold_command( + input_json: Union[str, Path], + output_dir: Union[str, Path], + runner_yaml: Union[str, Path], + ckpt_path: Optional[Union[str, Path]], + number_of_models: int = 5, + checkpoint_name: Optional[str] = None, +) -> list: + """Build the ``run_openfold predict`` command.""" + cmd = [ + "run_openfold", + "predict", + "--query_json", str(input_json), + "--runner_yaml", str(runner_yaml), + "--num_diffusion_samples", str(number_of_models), + "--output_dir", str(output_dir), + "--use_msa_server", "false", + ] + if ckpt_path is not None: + cmd += ["--inference_ckpt_path", str(ckpt_path)] + elif checkpoint_name: + cmd += ["--inference_ckpt_name", str(checkpoint_name)] + return cmd + + +def generate_openfold_test_command() -> list: + return [ + "run_openfold", + "predict", + "--help", + ] diff --git a/abcfold/output/alphafold3.py b/src/abcfold/output/alphafold3.py similarity index 97% rename from abcfold/output/alphafold3.py rename to src/abcfold/output/alphafold3.py index 0bc7894..8b7d79a 100644 --- a/abcfold/output/alphafold3.py +++ b/src/abcfold/output/alphafold3.py @@ -2,7 +2,7 @@ from typing import Union from abcfold.output.file_handlers import CifFile, ConfidenceJsonFile -from abcfold.output.utils import Af3Pae +from abcfold.output.utils import af3_pae_path, Af3Pae class AlphafoldOutput: @@ -97,6 +97,8 @@ def process_af3_output(self): cif_file = self.reorder_chains(cif_file) cif_file.to_file(str(file)) file_groups[seed][sample]["cif"] = cif_file + elif file.name.endswith("_af3_pae.json"): + continue elif file.suffix == ".json" and "summary" not in file.stem: file_groups[seed][sample]["af3_pae"] = ConfidenceJsonFile( str(file) @@ -147,7 +149,7 @@ def pae_to_af3(self): cif_file, ) - out_name = pae_file.pathway + out_name = af3_pae_path(cif_file) pae.to_file(out_name) diff --git a/abcfold/output/atoms.py b/src/abcfold/output/atoms.py similarity index 100% rename from abcfold/output/atoms.py rename to src/abcfold/output/atoms.py diff --git a/abcfold/output/boltz.py b/src/abcfold/output/boltz.py similarity index 99% rename from abcfold/output/boltz.py rename to src/abcfold/output/boltz.py index a5dbae1..a93deb7 100644 --- a/abcfold/output/boltz.py +++ b/src/abcfold/output/boltz.py @@ -5,7 +5,7 @@ from abcfold.boltz.af3_to_boltz import BoltzYaml from abcfold.output.file_handlers import (CifFile, ConfidenceJsonFile, FileTypes, ModelCount, NpzFile) -from abcfold.output.utils import Af3Pae +from abcfold.output.utils import af3_pae_path, Af3Pae logger = logging.getLogger("logger") @@ -275,7 +275,7 @@ def pae_to_af3(self): cif_file, ) - out_name = pae_file.pathway + out_name = af3_pae_path(cif_file) pae.to_file(out_name) diff --git a/abcfold/output/chai.py b/src/abcfold/output/chai.py similarity index 98% rename from abcfold/output/chai.py rename to src/abcfold/output/chai.py index 14da3d6..5ba487c 100644 --- a/abcfold/output/chai.py +++ b/src/abcfold/output/chai.py @@ -6,7 +6,7 @@ from abcfold.chai1.af3_to_chai import ChaiFasta from abcfold.output.file_handlers import (CifFile, ConfidenceJsonFile, FileTypes, NpyFile, NpzFile) -from abcfold.output.utils import Af3Pae +from abcfold.output.utils import af3_pae_path, Af3Pae logger = logging.getLogger("logger") @@ -207,7 +207,7 @@ def pae_to_af3(self): cif_file, ) - out_name = pae_file.pathway + out_name = af3_pae_path(cif_file) pae.to_file(out_name) diff --git a/abcfold/output/file_handlers.py b/src/abcfold/output/file_handlers.py similarity index 100% rename from abcfold/output/file_handlers.py rename to src/abcfold/output/file_handlers.py diff --git a/abcfold/output/openfold3.py b/src/abcfold/output/openfold3.py similarity index 98% rename from abcfold/output/openfold3.py rename to src/abcfold/output/openfold3.py index 2f57941..e7c3e3d 100644 --- a/abcfold/output/openfold3.py +++ b/src/abcfold/output/openfold3.py @@ -4,7 +4,7 @@ from abcfold.output.file_handlers import (CifFile, ConfidenceJsonFile, FileTypes, NpzFile) -from abcfold.output.utils import Af3Pae +from abcfold.output.utils import af3_pae_path, Af3Pae logger = logging.getLogger("logger") @@ -193,7 +193,7 @@ def pae_to_af3(self): cif_file, ) - out_name = pae_file.pathway + out_name = af3_pae_path(cif_file) pae.to_file(out_name) diff --git a/abcfold/output/protenix.py b/src/abcfold/output/protenix.py similarity index 98% rename from abcfold/output/protenix.py rename to src/abcfold/output/protenix.py index aeffb5d..c3d5240 100644 --- a/abcfold/output/protenix.py +++ b/src/abcfold/output/protenix.py @@ -4,7 +4,7 @@ from abcfold.output.file_handlers import (CifFile, ConfidenceJsonFile, FileTypes, NpzFile) -from abcfold.output.utils import Af3Pae +from abcfold.output.utils import af3_pae_path, Af3Pae from abcfold.protenix.af3_to_protenix import ProtenixJson logger = logging.getLogger("logger") @@ -195,7 +195,7 @@ def pae_to_af3(self) -> None: cif_file, ) - out_name = pae_file.pathway + out_name = af3_pae_path(cif_file) pae.to_file(out_name) diff --git a/abcfold/output/rosettafold3.py b/src/abcfold/output/rosettafold3.py similarity index 98% rename from abcfold/output/rosettafold3.py rename to src/abcfold/output/rosettafold3.py index a128b4f..ba9376c 100644 --- a/abcfold/output/rosettafold3.py +++ b/src/abcfold/output/rosettafold3.py @@ -3,7 +3,7 @@ from typing import Union from abcfold.output.file_handlers import CifFile, ConfidenceJsonFile, FileTypes -from abcfold.output.utils import Af3Pae +from abcfold.output.utils import af3_pae_path, Af3Pae logger = logging.getLogger("logger") @@ -189,7 +189,7 @@ def pae_to_af3(self): cif_file, ) - out_name = pae_file.pathway + out_name = af3_pae_path(cif_file) pae.to_file(out_name) diff --git a/abcfold/output/utils.py b/src/abcfold/output/utils.py similarity index 94% rename from abcfold/output/utils.py rename to src/abcfold/output/utils.py index 9c12575..a095431 100644 --- a/abcfold/output/utils.py +++ b/src/abcfold/output/utils.py @@ -510,34 +510,11 @@ def make_dummy_m8_file(run_json, output_dir): return m8_file -def verify_config_file(abc_config, default_config_file): - """ - Verify that the config file has the correct keys and values - - Args: - abc_config (Union[str, Path]): The config file to verify - default_config_file (Union[str, Path]): The path to the default config file +def af3_pae_path(cif_file) -> Path: + """Path of the AF3-format PAE JSON written next to a model CIF. - Returns: - None + The converted PAE always gets its own ``_af3_pae.json`` file; native + backend outputs (``.npz``/``.npy``/confidence JSON) are never rewritten. """ - - config_a = configparser.SafeConfigParser() - config_a.read(str(abc_config)) - - config_b = configparser.SafeConfigParser() - config_b.read(str(default_config_file)) - - for section in config_b.sections(): - if section == "Versions": - # Update the versions to match the default config file so we know we're - # using compatible versions of the programs - config_a[section] = config_b[section] - if not config_a.has_section(section): - config_a.add_section(section) - for key in config_b[section]: - if not config_a.has_option(section, key): - config_a[section][key] = config_b[section][key] - - with open(abc_config, "w") as f: - config_a.write(f) + cif_path = Path(getattr(cif_file, "pathway", cif_file)) + return cif_path.with_name(f"{cif_path.stem}_af3_pae.json") diff --git a/abcfold/plots/pae-viewer-main/LICENSE b/src/abcfold/plots/pae-viewer-main/LICENSE similarity index 100% rename from abcfold/plots/pae-viewer-main/LICENSE rename to src/abcfold/plots/pae-viewer-main/LICENSE diff --git a/abcfold/plots/pae-viewer-main/README.md b/src/abcfold/plots/pae-viewer-main/README.md similarity index 100% rename from abcfold/plots/pae-viewer-main/README.md rename to src/abcfold/plots/pae-viewer-main/README.md diff --git a/abcfold/plots/pae-viewer-main/src/css/complex-sequence-viewer.css b/src/abcfold/plots/pae-viewer-main/src/css/complex-sequence-viewer.css similarity index 100% rename from abcfold/plots/pae-viewer-main/src/css/complex-sequence-viewer.css rename to src/abcfold/plots/pae-viewer-main/src/css/complex-sequence-viewer.css diff --git a/abcfold/plots/pae-viewer-main/src/css/pae-viewer.css b/src/abcfold/plots/pae-viewer-main/src/css/pae-viewer.css similarity index 100% rename from abcfold/plots/pae-viewer-main/src/css/pae-viewer.css rename to src/abcfold/plots/pae-viewer-main/src/css/pae-viewer.css diff --git a/abcfold/plots/pae-viewer-main/src/css/structure-carousel.css b/src/abcfold/plots/pae-viewer-main/src/css/structure-carousel.css similarity index 100% rename from abcfold/plots/pae-viewer-main/src/css/structure-carousel.css rename to src/abcfold/plots/pae-viewer-main/src/css/structure-carousel.css diff --git a/abcfold/plots/pae-viewer-main/src/css/structure-panel.css b/src/abcfold/plots/pae-viewer-main/src/css/structure-panel.css similarity index 100% rename from abcfold/plots/pae-viewer-main/src/css/structure-panel.css rename to src/abcfold/plots/pae-viewer-main/src/css/structure-panel.css diff --git a/abcfold/plots/pae-viewer-main/src/css/structure-viewer.css b/src/abcfold/plots/pae-viewer-main/src/css/structure-viewer.css similarity index 100% rename from abcfold/plots/pae-viewer-main/src/css/structure-viewer.css rename to src/abcfold/plots/pae-viewer-main/src/css/structure-viewer.css diff --git a/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/arrows-fullscreen.svg b/src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/arrows-fullscreen.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/arrows-fullscreen.svg rename to src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/arrows-fullscreen.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/camera.svg b/src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/camera.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/camera.svg rename to src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/camera.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/download.svg b/src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/download.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/download.svg rename to src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/download.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/exclamation-circle.svg b/src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/exclamation-circle.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/exclamation-circle.svg rename to src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/exclamation-circle.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/fullscreen-exit.svg b/src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/fullscreen-exit.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/fullscreen-exit.svg rename to src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/fullscreen-exit.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/question-circle.svg b/src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/question-circle.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/question-circle.svg rename to src/abcfold/plots/pae-viewer-main/src/img/bootstrap-icons/question-circle.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.ico b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.ico similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.ico rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.ico diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.svg b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.svg rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/favicon.svg diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-overlapping-selection.png b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-overlapping-selection.png similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-overlapping-selection.png rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-overlapping-selection.png diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-point-selection.png b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-point-selection.png similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-point-selection.png rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-point-selection.png diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-range-selection.png b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-range-selection.png similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-range-selection.png rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-range-selection.png diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-regions.png b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-regions.png similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-regions.png rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer-regions.png diff --git a/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer.png b/src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer.png similarity index 100% rename from abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer.png rename to src/abcfold/plots/pae-viewer-main/src/img/pae-demo/screenshot-pae-viewer.png diff --git a/abcfold/plots/pae-viewer-main/src/jsonify_scores.py b/src/abcfold/plots/pae-viewer-main/src/jsonify_scores.py similarity index 100% rename from abcfold/plots/pae-viewer-main/src/jsonify_scores.py rename to src/abcfold/plots/pae-viewer-main/src/jsonify_scores.py diff --git a/abcfold/plots/pae-viewer-main/src/modules/complex-sequence-viewer.js b/src/abcfold/plots/pae-viewer-main/src/modules/complex-sequence-viewer.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/complex-sequence-viewer.js rename to src/abcfold/plots/pae-viewer-main/src/modules/complex-sequence-viewer.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/pae-viewer-demo.js b/src/abcfold/plots/pae-viewer-main/src/modules/pae-viewer-demo.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/pae-viewer-demo.js rename to src/abcfold/plots/pae-viewer-main/src/modules/pae-viewer-demo.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/pae-viewer.js b/src/abcfold/plots/pae-viewer-main/src/modules/pae-viewer.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/pae-viewer.js rename to src/abcfold/plots/pae-viewer-main/src/modules/pae-viewer.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/predicted-complex.js b/src/abcfold/plots/pae-viewer-main/src/modules/predicted-complex.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/predicted-complex.js rename to src/abcfold/plots/pae-viewer-main/src/modules/predicted-complex.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/read-crosslinks.js b/src/abcfold/plots/pae-viewer-main/src/modules/read-crosslinks.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/read-crosslinks.js rename to src/abcfold/plots/pae-viewer-main/src/modules/read-crosslinks.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/read-scores.js b/src/abcfold/plots/pae-viewer-main/src/modules/read-scores.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/read-scores.js rename to src/abcfold/plots/pae-viewer-main/src/modules/read-scores.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/read-structure.js b/src/abcfold/plots/pae-viewer-main/src/modules/read-structure.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/read-structure.js rename to src/abcfold/plots/pae-viewer-main/src/modules/read-structure.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/structure-carousel.js b/src/abcfold/plots/pae-viewer-main/src/modules/structure-carousel.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/structure-carousel.js rename to src/abcfold/plots/pae-viewer-main/src/modules/structure-carousel.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/structure-meta.js b/src/abcfold/plots/pae-viewer-main/src/modules/structure-meta.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/structure-meta.js rename to src/abcfold/plots/pae-viewer-main/src/modules/structure-meta.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/structure-panel.js b/src/abcfold/plots/pae-viewer-main/src/modules/structure-panel.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/structure-panel.js rename to src/abcfold/plots/pae-viewer-main/src/modules/structure-panel.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/structure-style.js b/src/abcfold/plots/pae-viewer-main/src/modules/structure-style.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/structure-style.js rename to src/abcfold/plots/pae-viewer-main/src/modules/structure-style.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/structure-viewer.js b/src/abcfold/plots/pae-viewer-main/src/modules/structure-viewer.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/structure-viewer.js rename to src/abcfold/plots/pae-viewer-main/src/modules/structure-viewer.js diff --git a/abcfold/plots/pae-viewer-main/src/modules/utils.js b/src/abcfold/plots/pae-viewer-main/src/modules/utils.js similarity index 100% rename from abcfold/plots/pae-viewer-main/src/modules/utils.js rename to src/abcfold/plots/pae-viewer-main/src/modules/utils.js diff --git a/abcfold/plots/pae-viewer-main/src/templates/complex-sequence-viewer.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/complex-sequence-viewer.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/complex-sequence-viewer.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/complex-sequence-viewer.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/pae-viewer.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/pae-viewer.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/pae-viewer.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/pae-viewer.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemoLayout.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemoLayout.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemoLayout.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemoLayout.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__consent.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__consent.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__consent.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__consent.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__ptms.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__ptms.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__ptms.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__ptms.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__sequence.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__sequence.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__sequence.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__sequence.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__structure.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__structure.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__structure.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__structure.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__upload.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__upload.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__upload.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__upload.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__viewer.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__viewer.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__viewer.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__help__viewer.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__news.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__news.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__news.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__news.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__citation.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__citation.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__citation.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__citation.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__examples.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__examples.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__examples.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__examples.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__offline.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__offline.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__offline.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__offline.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__upload.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__upload.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__upload.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tab__upload.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tabs.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tabs.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tabs.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/paeViewerDemo__tabs.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/structure-carousel.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/structure-carousel.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/structure-carousel.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/structure-carousel.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/structure-panel-demo.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/structure-panel-demo.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/structure-panel-demo.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/structure-panel-demo.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/structure-panel.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/structure-panel.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/structure-panel.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/structure-panel.tpl diff --git a/abcfold/plots/pae-viewer-main/src/templates/structure-viewer.tpl b/src/abcfold/plots/pae-viewer-main/src/templates/structure-viewer.tpl similarity index 100% rename from abcfold/plots/pae-viewer-main/src/templates/structure-viewer.tpl rename to src/abcfold/plots/pae-viewer-main/src/templates/structure-viewer.tpl diff --git a/abcfold/plots/pae-viewer-main/standalone/create_template.py b/src/abcfold/plots/pae-viewer-main/standalone/create_template.py similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/create_template.py rename to src/abcfold/plots/pae-viewer-main/standalone/create_template.py diff --git a/abcfold/plots/pae-viewer-main/standalone/css/common.css b/src/abcfold/plots/pae-viewer-main/standalone/css/common.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/common.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/common.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayout.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayout.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayout.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayout.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutAF3.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutAF3.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutAF3.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutAF3.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutBoltz.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutBoltz.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutBoltz.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutBoltz.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutChai.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutChai.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutChai.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutChai.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutOpenfold.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutOpenfold.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutOpenfold.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutOpenfold.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutProtenix.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutProtenix.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutProtenix.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutProtenix.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutRosetta.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutRosetta.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutRosetta.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneLayoutRosetta.css diff --git a/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneOverrides.css b/src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneOverrides.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneOverrides.css rename to src/abcfold/plots/pae-viewer-main/standalone/css/paeViewerStandaloneOverrides.css diff --git a/abcfold/plots/pae-viewer-main/standalone/favicon.ico b/src/abcfold/plots/pae-viewer-main/standalone/favicon.ico similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/favicon.ico rename to src/abcfold/plots/pae-viewer-main/standalone/favicon.ico diff --git a/abcfold/plots/pae-viewer-main/standalone/favicon.svg b/src/abcfold/plots/pae-viewer-main/standalone/favicon.svg similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/favicon.svg rename to src/abcfold/plots/pae-viewer-main/standalone/favicon.svg diff --git a/abcfold/plots/pae-viewer-main/standalone/js/pae-viewer-standalone.js b/src/abcfold/plots/pae-viewer-main/standalone/js/pae-viewer-standalone.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/js/pae-viewer-standalone.js rename to src/abcfold/plots/pae-viewer-main/standalone/js/pae-viewer-standalone.js diff --git a/abcfold/plots/pae-viewer-main/standalone/js/setup.js b/src/abcfold/plots/pae-viewer-main/standalone/js/setup.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/js/setup.js rename to src/abcfold/plots/pae-viewer-main/standalone/js/setup.js diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/FileSaver.min.js b/src/abcfold/plots/pae-viewer-main/standalone/libs/FileSaver.min.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/FileSaver.min.js rename to src/abcfold/plots/pae-viewer-main/standalone/libs/FileSaver.min.js diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.bundle.min.js b/src/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.bundle.min.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.bundle.min.js rename to src/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.bundle.min.js diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.min.css b/src/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.min.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.min.css rename to src/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap.min.css diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap@5.1.3.css b/src/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap@5.1.3.css similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/bootstrap@5.1.3.css rename to src/abcfold/plots/pae-viewer-main/standalone/libs/bootstrap@5.1.3.css diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/chroma.min.js b/src/abcfold/plots/pae-viewer-main/standalone/libs/chroma.min.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/chroma.min.js rename to src/abcfold/plots/pae-viewer-main/standalone/libs/chroma.min.js diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/jquery-ui.min.js b/src/abcfold/plots/pae-viewer-main/standalone/libs/jquery-ui.min.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/jquery-ui.min.js rename to src/abcfold/plots/pae-viewer-main/standalone/libs/jquery-ui.min.js diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/jquery.min.js b/src/abcfold/plots/pae-viewer-main/standalone/libs/jquery.min.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/jquery.min.js rename to src/abcfold/plots/pae-viewer-main/standalone/libs/jquery.min.js diff --git a/abcfold/plots/pae-viewer-main/standalone/libs/ngl.js b/src/abcfold/plots/pae-viewer-main/standalone/libs/ngl.js similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/libs/ngl.js rename to src/abcfold/plots/pae-viewer-main/standalone/libs/ngl.js diff --git a/abcfold/plots/pae-viewer-main/standalone/pae-viewer.bak b/src/abcfold/plots/pae-viewer-main/standalone/pae-viewer.bak similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae-viewer.bak rename to src/abcfold/plots/pae-viewer-main/standalone/pae-viewer.bak diff --git a/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB.zip b/src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB.zip similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB.zip rename to src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB.zip diff --git a/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/GatA-GatB.csv b/src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/GatA-GatB.csv similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/GatA-GatB.csv rename to src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/GatA-GatB.csv diff --git a/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/ReadMe.txt b/src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/ReadMe.txt similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/ReadMe.txt rename to src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/ReadMe.txt diff --git a/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_full_data_0.json b/src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_full_data_0.json similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_full_data_0.json rename to src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_full_data_0.json diff --git a/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_model_0.cif b/src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_model_0.cif similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_model_0.cif rename to src/abcfold/plots/pae-viewer-main/standalone/pae-viewer/sample/GatA-GatB/fold_gata_gatb_model_0.cif diff --git a/abcfold/plots/pae-viewer-main/standalone/pae_viewer.py b/src/abcfold/plots/pae-viewer-main/standalone/pae_viewer.py similarity index 100% rename from abcfold/plots/pae-viewer-main/standalone/pae_viewer.py rename to src/abcfold/plots/pae-viewer-main/standalone/pae_viewer.py diff --git a/abcfold/plots/pae_plot.py b/src/abcfold/plots/pae_plot.py similarity index 100% rename from abcfold/plots/pae_plot.py rename to src/abcfold/plots/pae_plot.py diff --git a/abcfold/plots/plddt_plot.py b/src/abcfold/plots/plddt_plot.py similarity index 100% rename from abcfold/plots/plddt_plot.py rename to src/abcfold/plots/plddt_plot.py diff --git a/abcfold/protenix/af3_to_protenix.py b/src/abcfold/protenix/af3_to_protenix.py similarity index 79% rename from abcfold/protenix/af3_to_protenix.py rename to src/abcfold/protenix/af3_to_protenix.py index 0a8ce8f..920a396 100644 --- a/abcfold/protenix/af3_to_protenix.py +++ b/src/abcfold/protenix/af3_to_protenix.py @@ -30,6 +30,7 @@ def __init__(self, working_dir: Union[str, Path], create_files: bool = True): self.seeds: list = [42] self.__ids: Dict = {} self.__id_counter: int = 1 + self.__copies: Dict = {} self.__create_files = create_files self.protenix_dict: Dict = {} @@ -37,6 +38,18 @@ def __init__(self, working_dir: Union[str, Path], create_files: bool = True): def chain_ids(self) -> Dict: return self.__ids + def _register_entity(self, seq_dict) -> List[str]: + """Map each chain id to its (entity index, copy index), both 1-based.""" + chain_ids = seq_dict.get("id", []) + if isinstance(chain_ids, str): + chain_ids = [chain_ids] + entity = self.__id_counter + self.__id_counter += 1 + for copy, chain in enumerate(chain_ids, start=1): + self.__ids[chain] = entity + self.__copies[chain] = copy + return chain_ids + def msa_to_file(self, msa: str, file_path: Union[str, Path]): """ Takes a msa string and writes it to a file @@ -108,10 +121,7 @@ def json_to_json( def convert_protein(self, seq_dict) -> Dict[str, Any]: sequence = seq_dict["sequence"] - chain_ids = seq_dict.get("id", []) - for chain in chain_ids: - self.__ids[chain] = self.__id_counter - self.__id_counter += 1 + chain_ids = self._register_entity(seq_dict) count = len(chain_ids) if chain_ids else 1 protein_chain = { @@ -131,31 +141,24 @@ def convert_protein(self, seq_dict) -> Dict[str, Any]: prefixed.append(m) protein_chain["modifications"] = prefixed - unpaired_msa = seq_dict.get("unpairedMsa") - paired_msa = seq_dict.get("pairedMsa") + # AF3 inputs may carry the MSA inline or as a file path + from abcfold.msa.guard import entity_msa_text + + unpaired_msa, paired_msa = entity_msa_text(seq_dict) random_string = ''.join(random.choices(string.ascii_letters, k=5)) msa_dir = Path(self.working_dir) / random_string - if unpaired_msa and self.__create_files: - if not msa_dir.exists(): + if unpaired_msa: + unpaired_path = msa_dir / "non_pairing.a3m" + if self.__create_files: msa_dir.mkdir(parents=True, exist_ok=True) - self.msa_to_file( - unpaired_msa, - msa_dir / "non_pairing.a3m" - ) - - if paired_msa and self.__create_files: - if not msa_dir.exists(): + self.msa_to_file(unpaired_msa, unpaired_path) + protein_chain["unpairedMsaPath"] = unpaired_path.resolve().as_posix() + if paired_msa: + paired_path = msa_dir / "pairing.a3m" + if self.__create_files: msa_dir.mkdir(parents=True, exist_ok=True) - self.msa_to_file( - paired_msa, - msa_dir / "pairing.a3m" - ) - - if unpaired_msa or paired_msa and self.__create_files: - protein_chain["msa"] = { - "precomputed_msa_dir": msa_dir.as_posix(), - "pairing_db": "uniref100" - } + self.msa_to_file(paired_msa, paired_path) + protein_chain["pairedMsaPath"] = paired_path.resolve().as_posix() return { "proteinChain": protein_chain @@ -163,10 +166,7 @@ def convert_protein(self, seq_dict) -> Dict[str, Any]: def convert_rna(self, seq_dict) -> Dict[str, Any]: sequence = seq_dict["sequence"] - chain_ids = seq_dict.get("id", []) - for chain in chain_ids: - self.__ids[chain] = self.__id_counter - self.__id_counter += 1 + chain_ids = self._register_entity(seq_dict) count = len(chain_ids) if chain_ids else 1 rna_chain = { @@ -192,10 +192,7 @@ def convert_rna(self, seq_dict) -> Dict[str, Any]: def convert_dna(self, seq_dict) -> Dict[str, Any]: sequence = seq_dict["sequence"] - chain_ids = seq_dict.get("id", []) - for chain in chain_ids: - self.__ids[chain] = self.__id_counter - self.__id_counter += 1 + chain_ids = self._register_entity(seq_dict) count = len(chain_ids) if chain_ids else 1 dna_chain = { @@ -220,35 +217,22 @@ def convert_dna(self, seq_dict) -> Dict[str, Any]: } def convert_ligand(self, seq_dict) -> Dict[str, Any]: - chain_ids = seq_dict.get("id", []) - for chain in chain_ids: - self.__ids[chain] = self.__id_counter - self.__id_counter += 1 + chain_ids = self._register_entity(seq_dict) count = len(chain_ids) if chain_ids else 1 if "ccdCodes" in seq_dict: - ligand_id = seq_dict["ccdCodes"][0] - ligand = f"CCD_{ligand_id}" + ligand = "_".join(f"CCD_{code}" for code in seq_dict["ccdCodes"]) else: ligand = seq_dict["smiles"] - ligand_id = ligand - if ligand_id.upper() in ION_CCD_CODES: - ligand_chain = { - "ion": ligand, - "count": count, - } - return { - "ion": ligand_chain - } - else: - ligand_chain = { + # Protenix has no usable "ion" entity: ions are CCD ligands, e.g. + # {"ligand": {"ligand": "CCD_MG", "count": 1}} + return { + "ligand": { "ligand": ligand, "count": count, } - return { - "ligand": ligand_chain - } + } def convert_bonded_atom_pairs(self, bonded_atom_pairs: List[List[List[Union[str, int]]]]): @@ -259,11 +243,11 @@ def convert_bonded_atom_pairs(self, contact = { "entity1": self.__ids[entity1], "position1": position1, - "copy1": 1, + "copy1": self.__copies.get(entity1, 1), "atom1": atom1, "entity2": self.__ids[entity2], "position2": position2, - "copy2": 1, + "copy2": self.__copies.get(entity2, 1), "atom2": atom2, "max_distance": 6, "min_distance": 0 diff --git a/src/abcfold/protenix/check_install.py b/src/abcfold/protenix/check_install.py new file mode 100644 index 0000000..4bc70b4 --- /dev/null +++ b/src/abcfold/protenix/check_install.py @@ -0,0 +1,10 @@ +import logging + +from abcfold.backend_envs import MicromambaEnv, ensure_backend_env + +logger = logging.getLogger("logger") + + +def ensure_protenix_env(config: dict) -> MicromambaEnv: + """Verify (never modify) the pinned protenix environment.""" + return ensure_backend_env("protenix", config) diff --git a/src/abcfold/protenix/run_protenix.py b/src/abcfold/protenix/run_protenix.py new file mode 100644 index 0000000..d953cb5 --- /dev/null +++ b/src/abcfold/protenix/run_protenix.py @@ -0,0 +1,215 @@ +import json +import logging +import os +import shutil +import subprocess +import tempfile +from pathlib import Path +from typing import Optional, Union + +from abcfold.gpus import to_physical +from abcfold.msa.guard import (ShallowMsaError, check_backend_n_msa, + check_protenix_input, min_msa_rows, + msa_requested) +from abcfold.protenix.af3_to_protenix import ProtenixJson +from abcfold.protenix.check_install import ensure_protenix_env + +logger = logging.getLogger("logger") + +DEFAULT_PROTENIX_MODEL = "protenix_base_default_v1.0.0" + + +def cuda_toolkit_available(env=None, environ=None) -> bool: + """True when nvcc is reachable, i.e. Protenix can JIT-build its fused + layernorm kernel. Checks CUDA_HOME first, then PATH (inside ``env``).""" + environ = os.environ if environ is None else environ + cuda_home = environ.get("CUDA_HOME") or environ.get("CUDA_PATH") + if cuda_home and Path(cuda_home, "bin", "nvcc").exists(): + return True + if env is not None and hasattr(env, "has_executable"): + return env.has_executable("nvcc") + return shutil.which("nvcc") is not None + + +def protenix_runtime_env( + config: dict, + gpus: str = "all", + nvcc_available: bool = False, + environ=None, +) -> dict: + """Environment variables for a Protenix run.""" + environ = os.environ if environ is None else environ + extra = {} + if "LAYERNORM_TYPE" not in environ and not nvcc_available: + # Without nvcc Protenix fails while JIT-compiling the fused layernorm + extra["LAYERNORM_TYPE"] = "torch" + root = config.get("protenix_root_dir") + if root: + extra["PROTENIX_ROOT_DIR"] = str(Path(str(root)).expanduser()) + if gpus not in (None, "all"): + extra["CUDA_VISIBLE_DEVICES"] = to_physical(gpus, environ) + return extra + + +def run_protenix( + input_json: Union[str, Path], + output_dir: Union[str, Path], + config: dict, + save_input: bool = False, + test: bool = False, + number_of_models: int = 5, + num_recycles: int = 10, + diffusion_steps: Optional[int] = None, + gpus: str = "all", +) -> bool: + """ + Run Protenix using the input JSON file. + + Returns: + bool: True only if every seed produced at least one structure. + """ + input_json = Path(input_json) + output_dir = Path(output_dir) + + env = None + extra_env: dict = {} + if not test: + logger.debug("Checking Protenix environment") + env = ensure_protenix_env(config=config) + extra_env = protenix_runtime_env( + config, gpus=gpus, nvcc_available=cuda_toolkit_available(env) + ) + if extra_env.get("LAYERNORM_TYPE") == "torch": + logger.info("nvcc not found; running Protenix with LAYERNORM_TYPE=torch") + + min_rows = min_msa_rows(config) + input_params = json.loads(input_json.read_text()) + msa_expected = any( + msa_requested(s["protein"]) for s in input_params.get("sequences", []) + if "protein" in s + ) + + # The MSA files referenced by unpairedMsaPath/pairedMsaPath live in + # working_dir, which must outlive every Protenix process below. + with tempfile.TemporaryDirectory(prefix="abcfold-protenix-") as temp_dir: + working_dir = Path(temp_dir) + if save_input: + logger.info("Saving input json file and msa to the output directory") + working_dir = output_dir + + protenix_json = ProtenixJson(working_dir) + protenix_json.json_to_json(input_json) + + for seed in protenix_json.seeds: + out_file = working_dir.joinpath(f"{input_json.stem}_seed-{seed}.json") + + protenix_json.write_json(out_file) + if msa_expected: + check_protenix_input(json.loads(out_file.read_text()), min_rows) + protenix_out_dir = output_dir / f"protenix_results_seed-{seed}" + logger.info("Running Protenix using seed: %s", seed) + cmd = ( + generate_protenix_command( + out_file, + protenix_out_dir, + config, + number_of_models, + num_recycles, + seed=seed, + diffusion_steps=diffusion_steps, + ) + if not test + else generate_protenix_test_command() + ) + + if test: + logger.info("Skipping Protenix backend execution in test mode") + continue + log_path = output_dir / f"protenix_seed-{seed}.log" + output_dir.mkdir(parents=True, exist_ok=True) + try: + assert env is not None + env.run(cmd, extra_env=extra_env, log_file=log_path) + except subprocess.CalledProcessError as e: + output_dir.mkdir(parents=True, exist_ok=True) + output_err_file = output_dir / "protenix_error.log" + output_err_file.write_text(e.stderr or "") + logger.error( + "Protenix run failed. Error log is in %s", output_err_file + ) + return False + + if msa_expected and log_path.exists(): + try: + check_backend_n_msa("Protenix", log_path.read_text(), min_rows) + except ShallowMsaError as exc: + (output_dir / "protenix_error.log").write_text(str(exc)) + logger.error(str(exc)) + raise + + # Protenix logs per-sample exceptions and still exits 0 + if not list(protenix_out_dir.rglob("*.cif")): + logger.error( + "Protenix exited without writing a structure for seed %s", seed + ) + return False + + logger.info("Protenix run complete") + logger.info("Output files are in %s", output_dir) + return True + + +def generate_protenix_command( + input_json: Union[str, Path], + output_dir: Union[str, Path], + config: dict, + number_of_models: int, + num_recycles: int, + seed: int, + diffusion_steps: Optional[int] = None, +) -> list: + """Build the ``runner.inference`` command for Protenix.""" + use_msa = False + with open(str(input_json), "r") as f: + data = json.load(f) + for entry in data[0].get("sequences", []): + chain = entry.get("proteinChain") + if chain and ( + "msa" in chain or chain.get("unpairedMsaPath") or chain.get("pairedMsaPath") + ): + use_msa = True + break + + model = config.get("protenix_model") or DEFAULT_PROTENIX_MODEL + cmd = [ + "python", + "-m", + "runner.inference", + "--model_name", + str(model), + "--input_json_path", + str(input_json), + "--dump_dir", + str(output_dir), + "--sample_diffusion.N_sample", + str(number_of_models), + "--model.N_cycle", + str(num_recycles), + "--seeds", + str(seed), + "--use_msa", + str(use_msa), + "--need_atom_confidence", + "True", + ] + if diffusion_steps is not None: + cmd += ["--sample_diffusion.N_step", str(diffusion_steps)] + return cmd + + +def generate_protenix_test_command() -> list: + return [ + "protenix", + "predict", + "--help", + ] diff --git a/src/abcfold/report.py b/src/abcfold/report.py new file mode 100644 index 0000000..75dc6b2 --- /dev/null +++ b/src/abcfold/report.py @@ -0,0 +1,288 @@ +"""Structured run report (``report.json``, schema ``cofolding-report-v2``).""" + +from __future__ import annotations + +import json +import os +import tempfile +from dataclasses import asdict, dataclass, field +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence + +import numpy as np + +SCHEMA = "cofolding-report-v2" +ENGINES = ("alphafold3", "boltz", "chai1", "protenix", "openfold3", "rosettafold3") +STATUSES = ("ok", "failed", "skipped") + +# Score keys in order of preference; the first one present is the engine's +# native ranking score. +SCORE_KEYS = ( + "ranking_score", # AlphaFold 3, Protenix + "confidence_score", # Boltz + "aggregate_score", # Chai-1 + "sample_ranking_score", # OpenFold3 +) + +SAMPLE_FIELDS = ( + "engine", "version", "seed", "rank", "cif", "score", "ptm", "iptm", + "plddt", "ligand_plddt", "ligand_pae", "chain_ids", "status", "seconds", +) + + +def _scalar(value: Any) -> Optional[float]: + if value is None: + return None + try: + arr = np.asarray(value, dtype=float).reshape(-1) + except (TypeError, ValueError): + return None + if arr.size == 0 or not np.isfinite(arr[0]): + return None + return float(arr[0]) + + +def extract_scores(data: Optional[Mapping]) -> Dict[str, Optional[float]]: + """Pick score/ptm/iptm out of any backend's confidence summary.""" + data = data or {} + score = None + for key in SCORE_KEYS: + if key in data: + score = _scalar(data[key]) + if score is not None: + break + return { + "score": score, + "ptm": _scalar(data.get("ptm")), + "iptm": _scalar(data.get("iptm")), + } + + +def to_percent(values: Iterable[float]) -> Optional[float]: + arr = np.asarray(list(values), dtype=float) + if arr.size == 0: + return None + mean = float(arr.mean()) + # Boltz/Chai/OF3 write pLDDT in B-factors on a 0-1 scale. + if float(arr.max()) <= 1.0: + mean *= 100.0 + return round(mean, 3) + + +def ligand_pae( + pae: Optional[Sequence[Sequence[float]]], + token_chain_ids: Optional[Sequence[str]], + ligand_chains: Sequence[str], +) -> Optional[float]: + """Mean ligand<->polymer PAE over both directions (Angstrom).""" + if pae is None or token_chain_ids is None or not ligand_chains: + return None + matrix = np.asarray(pae, dtype=float) + chains = np.asarray(token_chain_ids) + if matrix.ndim != 2 or matrix.shape[0] != len(chains): + return None + lig = np.isin(chains, list(ligand_chains)) + other = ~lig + if not lig.any() or not other.any(): + return None + block = np.concatenate([ + matrix[np.ix_(lig, other)].ravel(), + matrix[np.ix_(other, lig)].ravel(), + ]) + return round(float(block.mean()), 3) + + +@dataclass +class SampleRecord: + engine: str + version: Optional[str] + seed: Optional[int] + rank: Optional[int] + cif: str + score: Optional[float] = None + ptm: Optional[float] = None + iptm: Optional[float] = None + plddt: Optional[float] = None + ligand_plddt: Optional[float] = None + ligand_pae: Optional[float] = None + chain_ids: List[str] = field(default_factory=list) + status: str = "ok" + seconds: Optional[float] = None + + +@dataclass +class EngineRecord: + engine: str + version: Optional[str] = None + status: str = "skipped" + seconds: Optional[float] = None + error: Optional[str] = None + samples: List[SampleRecord] = field(default_factory=list) + + def rank_samples(self) -> None: + def key(s: SampleRecord): + return (s.score is None, -(s.score or 0.0)) + + for i, sample in enumerate(sorted(self.samples, key=key), start=1): + sample.rank = i + self.samples.sort(key=lambda s: s.rank or 0) + + +def _seed_int(seed: Any) -> Optional[int]: + text = str(seed) + digits = "".join(ch for ch in text.split("-")[-1] if ch.isdigit()) + return int(digits) if digits else None + + +def _load_score_data(score_obj: Any) -> Optional[Mapping]: + if score_obj is None: + return None + data = getattr(score_obj, "data", score_obj) + if isinstance(data, Mapping): + return data + if hasattr(data, "files"): # np.lib.npyio.NpzFile + return {k: data[k] for k in data.files} + return None + + +def samples_from_output( + engine: str, + version: Optional[str], + output: Mapping, + output_dir: Path, + seconds_per_sample: Optional[float] = None, +) -> List[SampleRecord]: + """Convert an ``abcfold.output.*Output.output`` mapping into samples.""" + samples: List[SampleRecord] = [] + for seed, models in output.items(): + for idx, files in models.items(): + if isinstance(idx, int) and idx < 0: + continue + cif = files.get("cif") + if cif is None: + continue + score_obj = None + for key in ("summary", "json", "scores", "score"): + if files.get(key) is not None: + score_obj = files[key] + break + scores = extract_scores(_load_score_data(score_obj)) + chain_ids = [chain.id for chain in cif.get_chains()] + ligand_chains = [c.id for c in cif.get_chains() if cif.check_ligand(c)] + ligand_bfactors = [ + b for values in cif.get_plddt_per_ligand().values() for b in values + ] + pae_data = _load_score_data(files.get("af3_pae")) or {} + cif_path = Path(cif.pathway) + try: + cif_rel = cif_path.resolve().relative_to(output_dir.resolve()) + cif_str = cif_rel.as_posix() + except ValueError: + cif_str = str(cif_path) + samples.append(SampleRecord( + engine=engine, + version=version, + seed=_seed_int(seed), + rank=None, + cif=cif_str, + score=scores["score"], + ptm=scores["ptm"], + iptm=scores["iptm"], + plddt=to_percent(cif.plddts), + ligand_plddt=to_percent(ligand_bfactors), + ligand_pae=ligand_pae(pae_data.get("pae"), + pae_data.get("token_chain_ids"), + ligand_chains), + chain_ids=chain_ids, + seconds=seconds_per_sample, + )) + return samples + + +def build_report( + name: str, + engines: Sequence[EngineRecord], + msa: Optional[Mapping] = None, + input_json: Optional[str] = None, + output_dir: Optional[str] = None, + abcfold_version: Optional[str] = None, +) -> Dict[str, Any]: + for engine in engines: + engine.rank_samples() + requested = [e for e in engines if e.status != "skipped"] + ok = [e for e in requested if e.status == "ok"] + if not requested: + status = "skipped" + elif len(ok) == len(requested): + status = "ok" + elif ok: + status = "partial" + else: + status = "failed" + samples = [asdict(s) for e in engines for s in e.samples] + return { + "schema": SCHEMA, + "name": name, + "status": status, + "created": datetime.now(timezone.utc).isoformat(timespec="seconds"), + "abcfold_version": abcfold_version, + "input_json": input_json, + "output_dir": output_dir, + "engines": [ + { + "engine": e.engine, + "version": e.version, + "status": e.status, + "seconds": None if e.seconds is None else round(e.seconds, 2), + "error": e.error, + "n_samples": len(e.samples), + "top_score": e.samples[0].score if e.samples else None, + } + for e in engines + ], + "samples": samples, + "msa": dict(msa) if msa else {"source": None, "chains": {}}, + } + + +def validate_report(report: Mapping) -> List[str]: + """Return a list of schema violations (empty when valid).""" + errors: List[str] = [] + if report.get("schema") != SCHEMA: + errors.append(f"schema must be {SCHEMA!r}") + for key in ("name", "status", "engines", "samples", "msa"): + if key not in report: + errors.append(f"missing key {key!r}") + if report.get("status") not in ("ok", "partial", "failed", "skipped"): + errors.append(f"bad status {report.get('status')!r}") + for i, engine in enumerate(report.get("engines", [])): + if engine.get("engine") not in ENGINES: + errors.append(f"engines[{i}]: unknown engine {engine.get('engine')!r}") + if engine.get("status") not in STATUSES: + errors.append(f"engines[{i}]: bad status {engine.get('status')!r}") + if engine.get("status") == "failed" and not engine.get("error"): + errors.append(f"engines[{i}]: failed engine without error") + for i, sample in enumerate(report.get("samples", [])): + missing = [f for f in SAMPLE_FIELDS if f not in sample] + if missing: + errors.append(f"samples[{i}]: missing {missing}") + for key in ("score", "ptm", "iptm", "plddt", "ligand_plddt", "ligand_pae", + "seconds"): + value = sample.get(key) + if value is not None and not isinstance(value, (int, float)): + errors.append(f"samples[{i}].{key} is not numeric") + msa = report.get("msa", {}) + if not isinstance(msa, Mapping) or "chains" not in msa: + errors.append("msa must be an object with 'chains'") + return errors + + +def write_report(report: Mapping, path: Path | str) -> Path: + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + fd, tmp = tempfile.mkstemp(dir=path.parent, prefix=".report.", suffix=".json") + with os.fdopen(fd, "w") as handle: + json.dump(report, handle, indent=2) + os.replace(tmp, path) + return path diff --git a/abcfold/rosettafold3/af3_to_rosettafold3.py b/src/abcfold/rosettafold3/af3_to_rosettafold3.py similarity index 100% rename from abcfold/rosettafold3/af3_to_rosettafold3.py rename to src/abcfold/rosettafold3/af3_to_rosettafold3.py diff --git a/src/abcfold/rosettafold3/check_install.py b/src/abcfold/rosettafold3/check_install.py new file mode 100644 index 0000000..125ae18 --- /dev/null +++ b/src/abcfold/rosettafold3/check_install.py @@ -0,0 +1,41 @@ +import logging +import urllib.request +from pathlib import Path + +from abcfold.backend_envs import MicromambaEnv, ensure_backend_env + +logger = logging.getLogger("logger") + +RF3_BASE_URL = "http://files.ipd.uw.edu/pub/rf3" +CHECKPOINT_NAME = "rf3_foundry_01_24_latest_remapped.ckpt" +RF3_URL = f"{RF3_BASE_URL}/{CHECKPOINT_NAME}" + + +def ensure_rosettafold_checkpoint(target_path: Path) -> Path: + if target_path.exists(): + return target_path + + target_path.parent.mkdir(parents=True, exist_ok=True) + + try: + logger.info( + "Downloading RoseTTAFold3 checkpoint via HTTPS " + "(this may take a while)..." + ) + urllib.request.urlretrieve(RF3_URL, target_path) + except Exception as e: + raise RuntimeError( + "Failed to download RoseTTAFold3 checkpoint.\n" + f"Target: {target_path}\n" + f"Error: {e}" + ) + + if not target_path.exists(): + raise RuntimeError("Checkpoint download completed but file not found") + + return target_path + + +def ensure_rosettafold_env(config: dict) -> MicromambaEnv: + """Verify (never modify) the pinned RoseTTAFold3 environment.""" + return ensure_backend_env("rosettafold3", config) diff --git a/abcfold/rosettafold3/run_rosettafold3.py b/src/abcfold/rosettafold3/run_rosettafold3.py similarity index 100% rename from abcfold/rosettafold3/run_rosettafold3.py rename to src/abcfold/rosettafold3/run_rosettafold3.py diff --git a/abcfold/scripts/abc_script_utils.py b/src/abcfold/scripts/abc_script_utils.py similarity index 100% rename from abcfold/scripts/abc_script_utils.py rename to src/abcfold/scripts/abc_script_utils.py diff --git a/abcfold/scripts/add_custom_template.py b/src/abcfold/scripts/add_custom_template.py similarity index 100% rename from abcfold/scripts/add_custom_template.py rename to src/abcfold/scripts/add_custom_template.py diff --git a/abcfold/scripts/add_mmseqs_msa.py b/src/abcfold/scripts/add_mmseqs_msa.py similarity index 100% rename from abcfold/scripts/add_mmseqs_msa.py rename to src/abcfold/scripts/add_mmseqs_msa.py diff --git a/abcfold/scripts/ipsae.py b/src/abcfold/scripts/ipsae.py similarity index 100% rename from abcfold/scripts/ipsae.py rename to src/abcfold/scripts/ipsae.py diff --git a/src/abcfold/settings.py b/src/abcfold/settings.py new file mode 100644 index 0000000..e202a5b --- /dev/null +++ b/src/abcfold/settings.py @@ -0,0 +1,232 @@ +"""Read-only configuration for ABCFold. + +Precedence (lowest to highest): + +1. packaged ``data/defaults.toml`` and ``backends.toml`` (read-only), +2. a user config file given by ``--config-file`` or ``ABCFOLD_CONFIG`` + (TOML, or a legacy ABCFold ``config.ini``); it is read, never written, +3. ``ABCFOLD_`` environment variables, +4. command line flags. + +Unset values are ``None``; the strings ``""`` and ``"None"`` count as unset. +""" + +from __future__ import annotations + +import configparser +import copy +import os +import sys +from dataclasses import dataclass, field +from importlib import resources +from pathlib import Path +from typing import Any, Dict, Mapping, Optional + +if sys.version_info >= (3, 11): + import tomllib +else: # pragma: no cover + import tomli as tomllib + +ENV_PREFIX = "ABCFOLD_" +BACKEND_NAMES = ( + "boltz", + "chai1", + "protenix", + "openfold3", + "rosettafold3", + "alphafold3", +) + +# Keys used by the legacy flat runtime config (config.ini era) +LEGACY_ENV_KEYS = { + "boltz_env": "boltz", + "chai_env": "chai1", + "protenix_env": "protenix", + "openfold_env": "openfold3", + "rosettafold_env": "rosettafold3", +} +LEGACY_VERSION_KEYS = { + "boltz_version": "boltz", + "chai_version": "chai1", + "protenix_version": "protenix", + "openfold_version": "openfold3", + "rosetta_version": "rosettafold3", + "af3_version": "alphafold3", +} + + +def _unset(value: Any) -> bool: + return value is None or (isinstance(value, str) and value.strip() in {"", "None"}) + + +def normalize_value(value: Any) -> Any: + """Map the unset markers to None and leave other values untouched.""" + return None if _unset(value) else value + + +def _read_toml_resource(name: str) -> dict: + text = resources.files("abcfold").joinpath(name).read_text() + return tomllib.loads(text) + + +def load_packaged_defaults() -> Dict[str, Any]: + flat: Dict[str, Any] = {} + for section in _read_toml_resource("data/defaults.toml").values(): + if isinstance(section, dict): + for key, value in section.items(): + flat[key] = normalize_value(value) + return flat + + +def load_backend_pins() -> Dict[str, Dict[str, Any]]: + data = _read_toml_resource("backends.toml") + return {k: v for k, v in data.items() if isinstance(v, dict)} + + +def _read_user_file(path: Path) -> tuple[Dict[str, Any], Dict[str, Dict[str, Any]]]: + """Return (flat values, backend overrides) from a TOML or legacy INI file.""" + values: Dict[str, Any] = {} + backends: Dict[str, Dict[str, Any]] = {} + if path.suffix == ".toml": + data = tomllib.loads(path.read_text()) + for key, section in data.items(): + if key == "backends" and isinstance(section, dict): + for name, override in section.items(): + backends[name] = dict(override) + elif isinstance(section, dict): + for sub_key, value in section.items(): + values[sub_key] = normalize_value(value) + else: + values[key] = normalize_value(section) + return values, backends + + parser = configparser.ConfigParser() + parser.read(path) + for section in parser.sections(): + for key, value in parser.items(section): + value = normalize_value(value) + if key in LEGACY_VERSION_KEYS: + if value is not None: + backends.setdefault(LEGACY_VERSION_KEYS[key], {})["version"] = value + elif key in LEGACY_ENV_KEYS: + if value is not None: + backends.setdefault(LEGACY_ENV_KEYS[key], {})["env"] = value + elif key == "protenix_model": + if value is not None: + backends.setdefault("protenix", {})["model"] = value + else: + values[key] = value + return values, backends + + +def _coerce_like(value: str, reference: Any) -> Any: + if isinstance(reference, bool): + return value.strip().lower() in {"1", "true", "yes", "on"} + if isinstance(reference, int): + try: + return int(value) + except ValueError: + return value + return value + + +@dataclass +class Settings: + values: Dict[str, Any] = field(default_factory=dict) + backends: Dict[str, Dict[str, Any]] = field(default_factory=dict) + source_file: Optional[Path] = None + + def get(self, key: str, default: Any = None) -> Any: + value = self.values.get(key) + return default if value is None else value + + def path(self, key: str) -> Optional[Path]: + value = self.get(key) + return None if value is None else Path(str(value)).expanduser() + + def backend(self, name: str) -> Dict[str, Any]: + if name not in self.backends: + raise KeyError(f"Unknown backend '{name}'") + return self.backends[name] + + def apply_overrides(self, overrides: Mapping[str, Any]) -> "Settings": + """Return a copy with non-None overrides applied (e.g. CLI flags).""" + new = copy.deepcopy(self) + for key, value in overrides.items(): + if value is not None: + new.values[key] = value + return new + + def runtime_config(self) -> Dict[str, Any]: + """Flat dict with the keys the backend runners historically used.""" + cfg: Dict[str, Any] = dict(self.values) + for key, name in LEGACY_ENV_KEYS.items(): + cfg[key] = self.backends.get(name, {}).get("env") + for key, name in LEGACY_VERSION_KEYS.items(): + cfg[key] = self.backends.get(name, {}).get("version") + cfg["protenix_model"] = self.backends.get("protenix", {}).get("model") + cfg["openfold_checkpoint"] = self.backends.get("openfold3", {}).get( + "checkpoint" + ) + cfg["_settings"] = self + return cfg + + +def load_settings( + config_file: Optional[os.PathLike | str] = None, + environ: Optional[Mapping[str, str]] = None, +) -> Settings: + """Load settings without writing anything to disk.""" + environ = os.environ if environ is None else environ + values = load_packaged_defaults() + backends = load_backend_pins() + + if config_file is None: + config_file = environ.get(ENV_PREFIX + "CONFIG") or None + source = None + if config_file is not None: + source = Path(config_file).expanduser() + if not source.exists(): + raise FileNotFoundError(f"Config file not found: {source}") + user_values, user_backends = _read_user_file(source) + values.update({k: v for k, v in user_values.items()}) + for name, override in user_backends.items(): + backends.setdefault(name, {}).update(override) + # A version override without a pip override must still be honoured + if "version" in override and "pip" not in override: + package = backends[name].get("package") + pins = backends[name].get("pip", []) + backends[name]["pip"] = [ + _replace_pin(spec, package, override["version"]) for spec in pins + ] + + for key in list(values): + env_key = ENV_PREFIX + key.upper() + if env_key in environ: + values[key] = normalize_value( + _coerce_like(environ[env_key], values.get(key)) + ) + for name in BACKEND_NAMES: + for field_name in ("version", "env"): + env_key = f"{ENV_PREFIX}{name.upper()}_{field_name.upper()}" + if env_key in environ and name in backends: + backends[name][field_name] = environ[env_key] + if field_name == "version": + package = backends[name].get("package") + backends[name]["pip"] = [ + _replace_pin(spec, package, environ[env_key]) + for spec in backends[name].get("pip", []) + ] + + return Settings(values=values, backends=backends, source_file=source) + + +def _replace_pin(spec: str, package: Optional[str], version: str) -> str: + """Replace the ``==`` version of ``package`` in a pip requirement string.""" + if package is None or "==" not in spec: + return spec + name, _ = spec.split("==", 1) + base = name.split("[", 1)[0].strip().lower().replace("-", "_") + if base == package.lower().replace("-", "_"): + return f"{name}=={version}" + return spec diff --git a/tests/conftest.py b/tests/conftest.py index 0c6a4f3..15a216e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,5 @@ # mypy: ignore-errors -import configparser import json import logging import shutil @@ -11,6 +10,7 @@ import pytest from abcfold.output.alphafold3 import AlphafoldOutput +from abcfold.settings import load_settings from abcfold.output.boltz import BoltzOutput from abcfold.output.chai import ChaiOutput from abcfold.output.openfold3 import OpenfoldOutput @@ -46,14 +46,7 @@ def test_data(): stem, suffix = test_file.stem, test_file.suffix[1:] d[f"test_{stem.replace('-', '_')}_{suffix}"] = str(test_file) - config_file = Path("../abcfold/data/config.ini") - if not config_file.exists(): - config_file = Path("./abcfold/data/config.ini") - config = configparser.ConfigParser() - config_dict = {} - config.read(str(config_file)) - for section in config.sections(): - config_dict.update(dict(config.items(section))) + config_dict = load_settings(environ={}).runtime_config() d["config_dict"] = config_dict nt = namedtuple("TestData", d) @@ -74,14 +67,7 @@ def output_objs(): raise FileNotFoundError() d = {} - config_file = Path("../abcfold/data/config.ini") - if not config_file.exists(): - config_file = Path("./abcfold/data/config.ini") - config = configparser.ConfigParser() - config_dict = {} - config.read(str(config_file)) - for section in config.sections(): - config_dict.update(dict(config.items(section))) + config_dict = load_settings(environ={}).runtime_config() adir = data_dir.joinpath("alphafold3_6BJ9") bdir = data_dir.joinpath("boltz_6BJ9_seed-1") diff --git a/tests/test_af3_adapter.py b/tests/test_af3_adapter.py new file mode 100644 index 0000000..5916158 --- /dev/null +++ b/tests/test_af3_adapter.py @@ -0,0 +1,204 @@ +import json +import os +import time + +import pytest + +from abcfold.alphafold3.af3_adapter import (Af3Config, af3_subprocess_env, + build_af3_command, + find_af3_job_dir, parse_af3_output, + prepare_inference_input, run_af3, + sanitised_name) + + +@pytest.fixture +def cfg(tmp_path): + return Af3Config( + runner="docker", + image="alphafold3", + model_dir=str(tmp_path / "models"), + db_dir=str(tmp_path / "db"), + gpus="1", + num_diffusion_samples=2, + num_recycles=3, + ) + + +def test_sanitised_name(): + # Same rule as AlphaFold 3: lower case, spaces to "_", drop everything outside [a-z0-9_-.] + assert sanitised_name("KRAS G12D (MRTX1133)") == "kras_g12d_mrtx1133" + + +def test_docker_full_command(tmp_path, cfg): + cmd = build_af3_command(tmp_path / "in" / "job.json", tmp_path / "out", cfg) + assert cmd[:3] == ["docker", "run", "--rm"] + assert cmd[cmd.index("--gpus") + 1] == "device=1" + assert f"{tmp_path / 'models'}:/root/models:ro" in cmd + assert f"{tmp_path / 'db'}:/root/public_databases:ro" in cmd + i = cmd.index("alphafold3") + assert cmd[i + 1:i + 3] == ["python", "run_alphafold.py"] + assert "--json_path=/root/af_input/job.json" in cmd + assert "--db_dir=/root/public_databases" in cmd + assert "--num_diffusion_samples=2" in cmd + assert "--num_recycles=3" in cmd + assert not any("run_data_pipeline" in c or "run_inference" in c for c in cmd) + + +def test_docker_data_pipeline_only(tmp_path, cfg): + cfg.model_dir = None + cmd = build_af3_command(tmp_path / "job.json", tmp_path / "out", cfg, + mode="data_pipeline") + assert "--run_inference=false" in cmd + assert "--gpus" not in cmd + assert not any(c.startswith("--model_dir") for c in cmd) + assert not any("/root/models" in c for c in cmd) + + +def test_docker_inference_only_needs_no_databases(tmp_path, cfg): + cfg.db_dir = None + cmd = build_af3_command(tmp_path / "job.json", tmp_path / "out", cfg, + mode="inference") + assert "--run_data_pipeline=false" in cmd + assert not any("public_databases" in c for c in cmd) + assert "--model_dir=/root/models" in cmd + + +def test_missing_paths_raise(tmp_path, cfg): + cfg.db_dir = None + with pytest.raises(ValueError, match="database"): + build_af3_command(tmp_path / "j.json", tmp_path, cfg, mode="full") + + +def test_apptainer_command(tmp_path, cfg): + cfg.runner = "apptainer" + cfg.image = str(tmp_path / "af3.sif") + cmd = build_af3_command(tmp_path / "job.json", tmp_path / "out", cfg) + assert cmd[:3] == ["apptainer", "exec", "--nv"] + assert "--bind" in cmd + assert cmd[cmd.index(cfg.image) + 2] == "/app/alphafold/run_alphafold.py" + env = af3_subprocess_env(cfg, environ={"LD_PRELOAD": "x"}) + assert env["APPTAINERENV_CUDA_VISIBLE_DEVICES"] == "1" + assert "LD_PRELOAD" not in env + + +def test_wrapper_command_template(tmp_path, cfg): + """Site wrapper such as lobachevsky's ~/bin/alphafold3 [gpu].""" + cfg.runner = "command" + cfg.command = "~/bin/alphafold3 {input_json} {output_dir} {gpus}" + cfg.append_flags = False + cmd = build_af3_command(tmp_path / "job.json", tmp_path / "out", cfg) + assert cmd == [os.path.expanduser("~/bin/alphafold3"), + str(tmp_path / "job.json"), str(tmp_path / "out"), "1"] + cfg.append_flags = True + cfg.gpus = "all" + cmd = build_af3_command(tmp_path / "job.json", tmp_path / "out", cfg, + mode="inference") + assert cmd[3:] == ["--run_data_pipeline=false", "--num_diffusion_samples=2", + "--num_recycles=3"] + + +def test_from_runtime_config(): + cfg = Af3Config.from_runtime_config( + {"af3_runner": "command", "af3_command": "wrap {input_json}", + "af3_append_flags": "false", "model_params": "None"}, + gpus="2", + ) + assert cfg.runner == "command" + assert cfg.append_flags is False + assert cfg.model_dir is None + assert cfg.gpus == "2" + + +def test_prepare_inference_input_fills_msa_fields(): + params = {"sequences": [ + {"protein": {"id": "A", "sequence": "MK"}}, + {"protein": {"id": "B", "sequence": "GS", "unpairedMsa": ">q\nGS\n"}}, + {"rna": {"id": "C", "sequence": "AGCU"}}, + {"ligand": {"id": "D", "ccdCodes": ["ATP"]}}, + ]} + out = prepare_inference_input(params) + a, b, c = (out["sequences"][i] for i in range(3)) + assert a["protein"] == {"id": "A", "sequence": "MK", "unpairedMsa": "", + "pairedMsa": "", "templates": []} + assert b["protein"]["unpairedMsa"] == ">q\nGS\n" + assert c["rna"]["unpairedMsa"] == "" + assert "unpairedMsa" not in params["sequences"][0]["protein"] + + +def make_af3_output(root, name="kras", samples=((1, 0), (1, 1)), prefixed=True): + job = root / name + job.mkdir(parents=True) + (job / f"{name}_model.cif").write_text("data_top\n") + (job / f"{name}_summary_confidences.json").write_text('{"ranking_score": 0.9}') + (job / f"{name}_confidences.json").write_text('{"pae": []}') + (job / f"{name}_data.json").write_text("{}") + rows = ["seed,sample,ranking_score"] + for seed, sample in samples: + d = job / f"seed-{seed}_sample-{sample}" + d.mkdir() + pre = f"{name}_seed-{seed}_sample-{sample}_" if prefixed else "" + (d / f"{pre}model.cif").write_text("data_x\n") + (d / f"{pre}summary_confidences.json").write_text( + json.dumps({"ranking_score": 0.5 + sample / 10})) + (d / f"{pre}confidences.json").write_text('{"pae": []}') + rows.append(f"{seed},{sample},{0.5 + sample / 10}") + (job / f"{name}_ranking_scores.csv").write_text("\n".join(rows) + "\n") + return job + + +@pytest.mark.parametrize("prefixed", [True, False]) +def test_parse_af3_output(tmp_path, prefixed): + job = make_af3_output(tmp_path, prefixed=prefixed) + result = parse_af3_output(tmp_path, "KRAS") + assert result.job_dir == job + assert result.top_model.name == "kras_model.cif" + assert result.top_summary.name == "kras_summary_confidences.json" + assert result.top_confidences.name == "kras_confidences.json" + assert result.data_json.name == "kras_data.json" + assert [(s.seed, s.sample) for s in result.samples] == [(1, 0), (1, 1)] + assert result.samples[1].ranking_score == pytest.approx(0.6) + assert "summary" not in result.samples[0].confidences.name + + +def test_find_timestamped_job_dir(tmp_path): + make_af3_output(tmp_path) + time.sleep(0.01) + newer = tmp_path / "kras_20261016_101010" + newer.mkdir() + (tmp_path / "kras_other").mkdir() + assert find_af3_job_dir(tmp_path, "kras") == newer + assert parse_af3_output(tmp_path, "nothing") is None + + +def test_run_af3_with_fake_wrapper(tmp_path, monkeypatch, cfg): + calls = [] + + def fake_run(argv, stdout, stderr, env, check): + calls.append(argv) + make_af3_output(tmp_path / "out") + + class P: + returncode = 0 + return P() + + monkeypatch.setattr("abcfold.alphafold3.af3_adapter.subprocess.run", fake_run) + params = {"name": "kras", "sequences": [{"protein": {"id": "A", + "sequence": "MK"}}]} + result = run_af3(params, tmp_path / "out", cfg, mode="inference") + assert result.ok + written = json.loads((tmp_path / "out/af3_input/kras.json").read_text()) + assert written["sequences"][0]["protein"]["unpairedMsa"] == "" + assert "--run_data_pipeline=false" in calls[0] + + +def test_run_af3_failure_raises(tmp_path, monkeypatch, cfg): + def fake_run(argv, stdout, stderr, env, check): + stdout.write("boom\n") + + class P: + returncode = 3 + return P() + + monkeypatch.setattr("abcfold.alphafold3.af3_adapter.subprocess.run", fake_run) + with pytest.raises(RuntimeError, match="exited with 3"): + run_af3({"name": "x", "sequences": []}, tmp_path / "o", cfg) diff --git a/tests/test_af3_to_protenix.py b/tests/test_af3_to_protenix.py index b0edf1e..5d60415 100644 --- a/tests/test_af3_to_protenix.py +++ b/tests/test_af3_to_protenix.py @@ -79,7 +79,7 @@ def test_af3_to_protenix_ligand(test_data): {'ligand': {'ligand': 'CCD_ATP', 'count': 2}}, {'ligand': {'ligand': 'CC(=O)OC1C[NH+]2CCC1CC2', 'count': 1}}, {'ligand': {'ligand': 'CCCCCCCCCCCC(O)=O', 'count': 2}}, - {'ion': {'ion': 'CCD_MG', 'count': 1}} + {'ligand': {'ligand': 'CCD_MG', 'count': 1}} ] } @@ -169,18 +169,17 @@ def test_protenix_output_msa(test_data): protenix_json = ProtenixJson(temp_dir) data = protenix_json.json_to_json(test_data.test_inputAmsa_json) - msa_path = ( - data["sequences"][0]["proteinChain"] - .get("msa", {}) - .get("precomputed_msa_dir") - ) - # MSA directory has a random path, so just check that it exists then give - # it a placeholder value for comparison - assert msa_path is not None - assert Path(msa_path).exists() - data["sequences"][0]["proteinChain"]["msa"]["precomputed_msa_dir"] = ( - "PRECOMPUTED_MSA_DIR" - ) + chain = data["sequences"][0]["proteinChain"] + # Protenix >= 1.0 reads unpairedMsaPath/pairedMsaPath; the old + # msa.precomputed_msa_dir field is deprecated and was silently dropped. + assert "msa" not in chain + msa_path = Path(chain["unpairedMsaPath"]) + assert msa_path.exists() + assert msa_path.name == "non_pairing.a3m" + with open(test_data.test_inputAmsa_json) as f: + source = json.load(f)["sequences"][0]["protein"]["unpairedMsa"] + assert msa_path.read_text() == source + chain["unpairedMsaPath"] = "UNPAIRED_MSA_PATH" reference = { 'name': '2PV7', @@ -199,9 +198,7 @@ def test_protenix_output_msa(test_data): 'sequences': [ {'proteinChain': {'sequence': 'GMRESYANENQFGFKTINSDIHKIVIVGGYGKLGGLFARYLRASGYPISILDREDWAVAESILANADVVIVSVPINLTLETIERLKPYLTENMLLADLTSVKREPLAKMLEVHTGAVLGLHPMFGADIASMAKQVVVRCDGRFPERYEWLLEQIQIWGAKIYQTNATEHDHNMTYIQALRHFSTFANGLHLSKQPINLANLLALSSPIYRLELAMIGRLFAQDAELYADIIMDKSENLAVIETLKQTYDEALTFFENNDRQGFIDAFHKVRDWFGDYSEQFLKESRQLLQQANDLKQG', 'count': 1, - 'msa': {'precomputed_msa_dir': 'PRECOMPUTED_MSA_DIR', - 'pairing_db': 'uniref100' - } + 'unpairedMsaPath': 'UNPAIRED_MSA_PATH', } } ] diff --git a/tests/test_batch.py b/tests/test_batch.py new file mode 100644 index 0000000..e5cd826 --- /dev/null +++ b/tests/test_batch.py @@ -0,0 +1,166 @@ +import json +import threading +import time + +import pytest + +from abcfold.batch import (BatchJob, ManifestError, job_command, parse_manifest, + parse_models, run_batch) + +KRAS = "MTEYKLVVVGADGVGKSALTIQ" +PART = "GSHMLEDPV" + + +def write_csv(path, rows): + path.write_text("\n".join(rows) + "\n") + return path + + +def test_parse_models_aliases(): + assert parse_models("boltz;chai") == ["boltz", "chai1"] + assert parse_models("af3, of3 protenix") == ["alphafold3", "openfold3", + "protenix"] + assert parse_models(None) == ["boltz"] + assert len(parse_models("all")) == 6 + with pytest.raises(ManifestError): + parse_models("alphafold2") + + +def test_parse_csv_manifest(tmp_path): + manifest = write_csv(tmp_path / "m.csv", [ + "id,protein,smiles,ccd,models,n_models", + f"kras,{KRAS},CCO,MG;GDP,boltz;protenix,2", + f"dimer,{KRAS}:{PART},,,chai1,", + ]) + jobs = parse_manifest(manifest) + assert [j.id for j in jobs] == ["kras", "dimer"] + kras = jobs[0] + assert kras.models == ["boltz", "protenix"] + assert kras.n_models == 2 + seqs = kras.params["sequences"] + assert seqs[0] == {"protein": {"id": "A", "sequence": KRAS}} + assert seqs[1] == {"ligand": {"id": "B", "smiles": "CCO"}} + assert seqs[2] == {"ligand": {"id": "C", "ccdCodes": ["MG"]}} + assert seqs[3] == {"ligand": {"id": "D", "ccdCodes": ["GDP"]}} + assert kras.params["name"] == "kras" + assert jobs[1].protein_sequences == [KRAS, PART] + + +def test_parse_json_manifest_with_af3_json(tmp_path): + af3 = tmp_path / "x.json" + af3.write_text(json.dumps({"name": "orig", "modelSeeds": [7], "sequences": [ + {"protein": {"id": "A", "sequence": KRAS}}]})) + manifest = tmp_path / "m.json" + manifest.write_text(json.dumps({ + "defaults": {"models": ["boltz", "chai1"]}, + "jobs": [{"id": "a", "af3_json": "x.json"}, + {"id": "b", "protein": [KRAS], "smiles": ["CCO", "CCN"], + "models": "protenix"}], + })) + a, b = parse_manifest(manifest) + assert a.params["name"] == "a" and a.params["modelSeeds"] == [7] + assert a.models == ["boltz", "chai1"] + assert b.models == ["protenix"] + assert len(b.params["sequences"]) == 3 + + +@pytest.mark.parametrize("rows,msg", [ + (["id,protein", f",{KRAS}"], "missing 'id'"), + (["id,protein", f"a,{KRAS}", f"a,{KRAS}"], "Duplicate"), + (["id,protein", "a/b,X"], "invalid id"), + (["id,smiles", "a,CCO"], "needs 'protein'"), +]) +def test_manifest_errors(tmp_path, rows, msg): + with pytest.raises(ManifestError, match=msg): + parse_manifest(write_csv(tmp_path / "m.csv", rows)) + + +def test_job_command(tmp_path): + job = BatchJob("a", {}, ["boltz", "chai1"], n_models=2) + cmd = job_command(job, tmp_path / "a.json", tmp_path / "out", "1", "server", + ["--diffusion_steps", "50"]) + assert cmd[1:4] == ["-m", "abcfold.cli", "run"] + assert "--boltz" in cmd and "--chai1" in cmd + assert cmd[cmd.index("--gpus") + 1] == "1" + assert cmd[cmd.index("--msa") + 1] == "server" + assert cmd[-2:] == ["--diffusion_steps", "50"] + + +class FakeRunner: + def __init__(self, codes=None, delay=0.0): + self.codes = codes or {} + self.calls = [] + self.delay = delay + self.active = 0 + self.max_active = 0 + self.lock = threading.Lock() + + def __call__(self, cmd, log_path, env): + with self.lock: + self.active += 1 + self.max_active = max(self.max_active, self.active) + out = cmd[cmd.index("run") + 2] + job_id = out.rstrip("/").split("/")[-1] + self.calls.append((job_id, cmd[cmd.index("--gpus") + 1] + if "--gpus" in cmd else None)) + time.sleep(self.delay) + code = self.codes.get(job_id, 0) + import pathlib + pathlib.Path(out).mkdir(parents=True, exist_ok=True) + (pathlib.Path(out) / "report.json").write_text(json.dumps({ + "engines": [{"engine": "boltz", "status": "ok" if code == 0 else + "failed"}]})) + log_path.write_text("log\n") + with self.lock: + self.active -= 1 + return code + + +def manifest_of(tmp_path, n): + rows = ["id,protein,models"] + [f"j{i},{KRAS},boltz" for i in range(n)] + return write_csv(tmp_path / "m.csv", rows) + + +def test_run_batch_status_and_resume(tmp_path): + manifest = manifest_of(tmp_path, 3) + runner = FakeRunner(codes={"j1": 1, "j2": 2}) + status = run_batch(manifest, tmp_path / "out", msa="none", runner=runner) + jobs = status["jobs"] + assert {k: v["status"] for k, v in jobs.items()} == { + "j0": "ok", "j1": "failed", "j2": "partial"} + assert jobs["j0"]["engines"] == {"boltz": "ok"} + on_disk = json.loads((tmp_path / "out" / "batch_status.json").read_text()) + assert on_disk["counts"] == {"ok": 1, "failed": 1, "partial": 1} + assert (tmp_path / "out" / "inputs" / "j0.json").exists() + + runner2 = FakeRunner() + run_batch(manifest, tmp_path / "out", msa="none", runner=runner2) + assert sorted(c[0] for c in runner2.calls) == ["j1", "j2"] # j0 skipped + + runner3 = FakeRunner() + run_batch(manifest, tmp_path / "out", msa="none", runner=runner3, force=True) + assert len(runner3.calls) == 3 + + +def test_run_batch_parallel_round_robin_gpus(tmp_path): + manifest = manifest_of(tmp_path, 4) + runner = FakeRunner(delay=0.05) + run_batch(manifest, tmp_path / "out", max_parallel=2, gpus="1,2", + msa="none", runner=runner) + assert runner.max_active == 2 + assert {gpu for _, gpu in runner.calls} == {"1", "2"} + + +def test_run_batch_prefetches_unique_sequences_once(tmp_path, monkeypatch): + calls = [] + + def fake_prefetch(sequences, options, client=None): + calls.append(list(sequences)) + return len(set(sequences)), 0 + + monkeypatch.setattr("abcfold.msa.resolve.prefetch_unique_sequences", + fake_prefetch) + run_batch(manifest_of(tmp_path, 3), tmp_path / "out", msa="server", + runner=FakeRunner()) + assert len(calls) == 1 + assert calls[0] == [KRAS, KRAS, KRAS] diff --git a/tests/test_cli_run.py b/tests/test_cli_run.py new file mode 100644 index 0000000..887d650 --- /dev/null +++ b/tests/test_cli_run.py @@ -0,0 +1,150 @@ +import json +import tempfile +from pathlib import Path + +import pytest + +import abcfold.abcfold as abc +from abcfold import cli +from abcfold.protenix.af3_to_protenix import ProtenixJson +from abcfold.report import validate_report + + +def run_cli(argv): + return abc.main(argv) + + +def test_failed_backend_is_reported_and_cli_survives(test_data, tmp_path, + monkeypatch): + """Defect 8: a failed backend was reported as success / crashed the CLI.""" + def boom(*a, **k): + raise RuntimeError("CUDA out of memory") + + monkeypatch.setattr(abc, "_run_boltz", boom) + monkeypatch.setattr(abc, "_run_chai", + lambda *a, **k: abc.EngineOutcome(False)) + out = tmp_path / "out" + code = run_cli([test_data.test_inputAB_json, str(out), "-b", "-c", + "--no_visuals"]) + assert code == abc.EXIT_FAILED + report = json.loads((out / "report.json").read_text()) + assert validate_report(report) == [] + engines = {e["engine"]: e for e in report["engines"]} + assert engines["boltz"]["status"] == "failed" + assert "CUDA out of memory" in engines["boltz"]["error"] + assert engines["chai1"]["status"] == "failed" + assert engines["protenix"]["status"] == "skipped" + assert report["status"] == "failed" + + +def test_partial_success_exit_code(test_data, tmp_path, monkeypatch): + monkeypatch.setattr(abc, "_run_boltz", lambda *a, **k: abc.EngineOutcome(True)) + monkeypatch.setattr(abc, "_run_chai", lambda *a, **k: abc.EngineOutcome(False)) + code = run_cli([test_data.test_inputAB_json, str(tmp_path / "o"), "-b", "-c", + "--no_visuals"]) + assert code == abc.EXIT_PARTIAL + + +def test_msa_is_kept_in_abc_input(test_data, tmp_path, monkeypatch): + """Defect 4: the MSA must stay in the written abc_.json.""" + seen = {} + + def fake_boltz(args, rt_config, run_json, input_params, name): + seen["json"] = json.loads(Path(run_json).read_text()) + return abc.EngineOutcome(True) + + monkeypatch.setattr(abc, "_run_boltz", fake_boltz) + msa = tmp_path / "a.a3m" + data = json.loads(Path(test_data.test_inputA_json).read_text()) + seq = data["sequences"][0]["protein"]["sequence"] + msa.write_text(f">query\n{seq}\n" + "".join( + f">h{i}\n{seq[:-1]}{'ACDEFGHIKLMNPQ'[i]}\n" for i in range(12))) + out = tmp_path / "o" + code = run_cli([test_data.test_inputA_json, str(out), "-b", "--no_visuals", + "--msa", "custom", "--msa_a3m", str(msa)]) + assert code == abc.EXIT_OK + written = json.loads((out / f"abc_{Path(test_data.test_inputA_json).name}") + .read_text()) + protein = written["sequences"][0]["protein"] + assert protein["unpairedMsa"].startswith(">query") + assert seen["json"] == written + stats = json.loads((out / "msa_stats.json").read_text()) + assert stats["chains"]["A"]["depth"] == 13 + report = json.loads((out / "report.json").read_text()) + assert report["msa"]["source"] == "custom" + + +def test_shallow_msa_fails_every_engine(test_data, tmp_path, monkeypatch): + called = [] + monkeypatch.setattr(abc, "_run_boltz", + lambda *a, **k: called.append(1) or abc.EngineOutcome(True)) + data = json.loads(Path(test_data.test_inputA_json).read_text()) + seq = data["sequences"][0]["protein"]["sequence"] + msa = tmp_path / "a.a3m" + msa.write_text(f">query\n{seq}\n") + out = tmp_path / "o" + code = run_cli([test_data.test_inputA_json, str(out), "-b", "--no_visuals", + "--msa", "custom", "--msa_a3m", str(msa)]) + assert code == abc.EXIT_FAILED + assert called == [] + report = json.loads((out / "report.json").read_text()) + assert "too shallow" in report["engines"][1]["error"] + + +def test_cli_routes_legacy_invocation(monkeypatch): + seen = {} + monkeypatch.setattr("abcfold.abcfold.main", + lambda argv: seen.setdefault("argv", argv) and 0) + cli.main(["in.json", "out", "-b"]) + assert seen["argv"] == ["in.json", "out", "-b"] + seen.clear() + cli.main(["run", "in.json", "out"]) + assert seen["argv"] == ["in.json", "out"] + + +def test_cli_envs_show(capsys): + assert cli.main(["envs", "show", "protenix"]) == 0 + assert "protenix==2.0.0" in capsys.readouterr().out + + +def test_diffusion_steps_flag_aliases(test_data, tmp_path): + parser = abc.build_run_parser() + args = parser.parse_args([test_data.test_inputA_json, str(tmp_path), + "--sampling_steps", "50"]) + assert args.diffusion_steps == 50 + args = parser.parse_args([test_data.test_inputA_json, str(tmp_path)]) + assert args.diffusion_steps is None + assert args.openfold_fetch_templates is False + + +def test_protenix_ions_are_ligands(): + """Defect 7: ions must be {"ligand": {"ligand": "CCD_MG", "count": N}}.""" + params = {"name": "ions", "modelSeeds": [1], "sequences": [ + {"protein": {"id": "A", "sequence": "MKV"}}, + {"ligand": {"id": ["B", "C"], "ccdCodes": ["MG"]}}, + {"ligand": {"id": "D", "ccdCodes": ["ZN"]}}, + ]} + with tempfile.TemporaryDirectory() as tmp: + src = Path(tmp) / "in.json" + src.write_text(json.dumps(params)) + data = ProtenixJson(tmp).json_to_json(src) + ligands = [s for s in data["sequences"] if "ligand" in s] + assert {"ligand": {"ligand": "CCD_MG", "count": 2}} in ligands + assert {"ligand": {"ligand": "CCD_ZN", "count": 1}} in ligands + assert not any("ion" in s for s in data["sequences"]) + + +@pytest.mark.parametrize("flags,expected", [ + ([], False), + (["--openfold_fetch_templates"], True), +]) +def test_openfold_template_fetch_flag(test_data, tmp_path, flags, expected): + """Defect 6: OpenFold3 must not fetch RCSB templates unless asked.""" + from abcfold.openfold3.af3_to_openfold3 import OpenfoldJson + + args = abc.build_run_parser().parse_args( + [test_data.test_inputA_json, str(tmp_path)] + flags) + out = tmp_path / "runner.yaml" + OpenfoldJson(tmp_path).write_yaml(out, fetch_templates=args.openfold_fetch_templates) + text = out.read_text() + assert f"fetch_missing_structures: {str(expected).lower()}" in text.lower() diff --git a/tests/test_gpus.py b/tests/test_gpus.py new file mode 100644 index 0000000..f2af28d --- /dev/null +++ b/tests/test_gpus.py @@ -0,0 +1,37 @@ +import pytest + +from abcfold.gpus import docker_gpu_flags, to_physical +from abcfold.openfold3.run_openfold3 import _gpu_env +from abcfold.protenix.run_protenix import protenix_runtime_env + + +def test_indices_follow_inherited_mask(): + """Defect 13: --gpus 0 under CUDA_VISIBLE_DEVICES=2 must stay on physical GPU 2.""" + env = {"CUDA_VISIBLE_DEVICES": "2,3"} + assert to_physical("0", env) == "2" + assert to_physical("1,0", env) == "3,2" + assert to_physical("all", env) is None + assert to_physical("cpu", env) == "" + + +def test_without_mask_indices_are_physical(): + assert to_physical("0,1", {}) == "0,1" + + +def test_index_outside_mask_fails(): + with pytest.raises(ValueError): + to_physical("1", {"CUDA_VISIBLE_DEVICES": "2"}) + + +def test_docker_never_sees_all_host_gpus_under_a_mask(): + assert docker_gpu_flags("all", {"CUDA_VISIBLE_DEVICES": "2"}) == ["--gpus", "device=2"] + assert docker_gpu_flags("0", {"CUDA_VISIBLE_DEVICES": "3"}) == ["--gpus", "device=3"] + assert docker_gpu_flags("all", {}) == ["--gpus", "all"] + assert docker_gpu_flags("cpu", {}) == [] + + +def test_backend_envs_use_physical_ids(monkeypatch): + monkeypatch.setenv("CUDA_VISIBLE_DEVICES", "2") + assert _gpu_env("0") == {"CUDA_VISIBLE_DEVICES": "2"} + extra = protenix_runtime_env({}, "0", nvcc_available=True, environ={"CUDA_VISIBLE_DEVICES": "2"}) + assert extra["CUDA_VISIBLE_DEVICES"] == "2" diff --git a/tests/test_msa.py b/tests/test_msa.py new file mode 100644 index 0000000..c2d0a56 --- /dev/null +++ b/tests/test_msa.py @@ -0,0 +1,305 @@ +import io +import json +import tarfile + +import pytest + +from abcfold.msa.cache import (MsaCache, msa_cache_key, normalize_sequence, + paired_cache_key) +from abcfold.msa.colabfold import (ColabFoldClient, ColabFoldError, + merge_query_blocks, split_colabfold_a3m) +from abcfold.msa.export import export_msas +from abcfold.msa.formats import a3m_to_boltz_csv, chai_msa_frame, parse_a3m +from abcfold.msa.resolve import MsaOptions, parse_chain_paths, resolve_msas +from abcfold.msa.stats import MAX_BINS, bin_values, msa_chain_stats + +SEQ_A = "MKTAYIAKQR" +SEQ_B = "GSHMLEDPV" + + +def a3m(query, n, prefix="UniRef100_X"): + rows = [f">query\n{query}\n"] + for i in range(n): + rows.append(f">{prefix}{i}\n{query[:-1]}{'ACDEFGHIKL'[i % 10]}\n") + return "".join(rows) + + +# --- cache hashing ------------------------------------------------------- + + +def test_cache_key_normalises_sequence(): + assert normalize_sequence(" mkt ay\n") == "MKTAY" + assert msa_cache_key("mktay") == msa_cache_key("MKTAY ") + + +def test_cache_key_depends_on_source_and_options(): + keys = { + msa_cache_key(SEQ_A, "server", ""), + msa_cache_key(SEQ_A, "custom", ""), + msa_cache_key(SEQ_A, "server", "env=0"), + msa_cache_key(SEQ_B, "server", ""), + } + assert len(keys) == 4 + assert len(msa_cache_key(SEQ_A)) == 64 + + +def test_paired_key_depends_on_partners_and_index(): + k0 = paired_cache_key([SEQ_A, SEQ_B], 0) + assert k0 != paired_cache_key([SEQ_A, SEQ_B], 1) + assert k0 != paired_cache_key([SEQ_A, "MMMM"], 0) + assert k0 != msa_cache_key(SEQ_A) + + +def test_cache_roundtrip(tmp_path): + cache = MsaCache(tmp_path) + key = msa_cache_key(SEQ_A) + assert cache.get(key) is None + path = cache.put(key, "a3m", {"source": "server"}) + assert path == tmp_path / key[:2] / key / "msa.a3m" + assert cache.get(key) == "a3m" + assert cache.meta(key)["source"] == "server" + + +# --- ColabFold client ---------------------------------------------------- + + +class FakeResponse: + def __init__(self, payload=None, content=b""): + self.payload = payload + self.content = content + self.text = json.dumps(payload) + + def json(self): + return self.payload + + +def make_tar(files): + buf = io.BytesIO() + with tarfile.open(fileobj=buf, mode="w:gz") as tar: + for name, text in files.items(): + data = text.encode() + info = tarfile.TarInfo(name) + info.size = len(data) + tar.addfile(info, io.BytesIO(data)) + return buf.getvalue() + + +class FakeSession: + def __init__(self, files, statuses=("RUNNING", "COMPLETE")): + self.files = files + self.statuses = list(statuses) + self.posts = [] + + def post(self, url, data, headers, timeout): + self.posts.append((url, data)) + return FakeResponse({"id": "T1", "status": "PENDING"}) + + def get(self, url, headers, timeout): + if "/ticket/" in url: + return FakeResponse({"status": self.statuses.pop(0)}) + return FakeResponse(content=make_tar(self.files)) + + +def colabfold_block(qid, query, hits): + lines = [f">{qid}\n{query}\n"] + [f">hit{qid}_{i}\n{h}\n" for i, h in + enumerate(hits)] + return "".join(lines) + + +def test_split_and_merge_colabfold_blocks(): + text = (colabfold_block(101, SEQ_A, ["MKTAYIAKQA"]) + "\x00" + + colabfold_block(102, SEQ_B, ["GSHMLEDPA"])) + blocks = split_colabfold_a3m(text) + assert set(blocks) == {101, 102} + env = colabfold_block(101, SEQ_A, ["MKTAYIAKQE"]) + merged = parse_a3m(merge_query_blocks([blocks[101], env], 101)) + assert merged[0] == ("query", SEQ_A) + assert [s for _, s in merged] == [SEQ_A, "MKTAYIAKQA", "MKTAYIAKQE"] + + +def test_client_unpaired_maps_queries_back(): + uniref = (colabfold_block(101, SEQ_A, ["MKTAYIAKQA"]) + "\x00" + + colabfold_block(102, SEQ_B, ["GSHMLEDPA"])) + env = colabfold_block(101, SEQ_A, ["MKTAYIAKQE"]) + "\x00" + colabfold_block( + 102, SEQ_B, []) + session = FakeSession({ + "uniref.a3m": uniref, + "bfd.mgnify30.metaeuk30.smag30.a3m": env, + }) + client = ColabFoldClient("http://msa.test/", session=session, + sleep=lambda s: None) + # The server numbers unique queries from 101 in submission order: SEQ_A -> 101, SEQ_B -> 102. + out = client.unpaired([SEQ_A, SEQ_B, SEQ_A]) + # duplicates are submitted once + assert session.posts[0][1]["q"].count(">") == 2 + assert session.posts[0][0] == "http://msa.test/ticket/msa" + assert session.posts[0][1]["mode"] == "env" + assert parse_a3m(out[0])[0][1] == SEQ_A + assert len(parse_a3m(out[0])) == 3 + assert parse_a3m(out[1])[0][1] == SEQ_B + assert out[0] == out[2] + + +def test_client_raises_on_error_status(): + session = FakeSession({}, statuses=["ERROR"]) + client = ColabFoldClient(session=session, sleep=lambda s: None) + with pytest.raises(ColabFoldError): + client.unpaired([SEQ_A]) + + +# --- formats and stats --------------------------------------------------- + + +def test_boltz_csv_pairs_rows_by_key(): + paired = f">query\n{SEQ_A}\n>p1\nMKTAYIAKQA\n>p2\n{'-' * len(SEQ_A)}\n" + csv = a3m_to_boltz_csv(a3m(SEQ_A, 3), paired).splitlines() + assert csv[0] == "key,sequence" + assert csv[1] == f"0,{SEQ_A}" + assert csv[2] == "1,MKTAYIAKQA" + # gap-only paired row dropped, unpaired query not duplicated + assert [r.split(",")[0] for r in csv[3:]] == ["-1"] * 3 + + +def test_chai_frame_columns_and_pairing(): + paired = f">query\n{SEQ_A}\n>p1\nMKTAYIAKQA\n" + frame = chai_msa_frame(a3m(SEQ_A, 2), paired) + assert list(frame.columns) == ["sequence", "source_database", "pairing_key", + "comment"] + assert frame.iloc[0]["source_database"] == "query" + assert list(frame["pairing_key"][:2]) == ["0", "1"] + assert frame["pairing_key"].iloc[-1] == "" + + +def test_bin_values_limits_to_max_bins(): + assert bin_values([1, 2, 3]) == [1.0, 2.0, 3.0] + binned = bin_values(list(range(1000))) + assert len(binned) == MAX_BINS + assert binned[0] == pytest.approx(2.0) + + +def test_msa_chain_stats(): + stats = msa_chain_stats(a3m(SEQ_A, 4), None, len(SEQ_A), "server", 1.5, True) + assert stats["depth"] == 5 + assert stats["paired_depth"] == 0 + assert stats["source"] == "server" + assert stats["cached"] is True + assert len(stats["coverage"]) == len(SEQ_A) + assert max(stats["coverage"]) == 5 + + +# --- resolver ------------------------------------------------------------ + + +def complex_input(*seqs): + return { + "name": "t", + "modelSeeds": [1], + "sequences": [ + {"protein": {"id": chr(65 + i), "sequence": s}} for i, s in enumerate(seqs) + ] + [{"ligand": {"id": "Z", "ccdCodes": ["ATP"]}}], + } + + +class FakeClient: + def __init__(self): + self.unpaired_calls = [] + self.paired_calls = [] + + def unpaired(self, seqs, use_env=True): + self.unpaired_calls.append(list(seqs)) + return [a3m(s, 12) for s in seqs] + + def paired(self, seqs, strategy="greedy"): + self.paired_calls.append(list(seqs)) + return [f">query\n{s}\n>p\n{s}\n" for s in seqs] + + +def test_resolve_server_caches_and_pairs(tmp_path): + client = FakeClient() + opts = MsaOptions(source="server", cache_dir=str(tmp_path)) + params = complex_input(SEQ_A, SEQ_B, SEQ_A) + result = resolve_msas(params, opts, client=client) + assert client.unpaired_calls == [[SEQ_A, SEQ_B]] + assert client.paired_calls == [[SEQ_A, SEQ_B]] + proteins = [s["protein"] for s in result.params["sequences"] if "protein" in s] + assert all(p["unpairedMsa"].startswith(">query") for p in proteins) + assert all(p["pairedMsa"] for p in proteins) + assert all(p["templates"] == [] for p in proteins) + assert set(result.chains) == {"A", "B", "C"} + assert result.chains["A"]["cached"] is False + # input is not mutated + assert "unpairedMsa" not in params["sequences"][0]["protein"] + + again = resolve_msas(params, opts, client=FakeClient()) + assert again.chains["A"]["cached"] is True + assert again.params == result.params + + +def test_resolve_server_homomer_is_not_paired(tmp_path): + client = FakeClient() + result = resolve_msas(complex_input(SEQ_A, SEQ_A), + MsaOptions(source="server", cache_dir=str(tmp_path)), + client=client) + assert client.paired_calls == [] + assert result.params["sequences"][0]["protein"]["pairedMsa"] == "" + + +def test_resolve_none_and_auto(): + none = resolve_msas(complex_input(SEQ_A), MsaOptions(source="none")) + protein = none.params["sequences"][0]["protein"] + assert protein["unpairedMsa"] == "" and protein["pairedMsa"] == "" + auto = resolve_msas(complex_input(SEQ_A), MsaOptions(source="auto")) + assert auto.source == "backend" + assert "unpairedMsa" not in auto.params["sequences"][0]["protein"] + + +def test_resolve_custom(tmp_path): + path = tmp_path / "a.a3m" + path.write_text(a3m(SEQ_A, 11)) + path_b = tmp_path / "b.a3m" + path_b.write_text(a3m(SEQ_B, 3)) + result = resolve_msas( + complex_input(SEQ_A, SEQ_B), + MsaOptions(source="custom", custom_a3m=parse_chain_paths([f"A={path}", + f"B={path_b}"])), + ) + assert result.chains["A"]["depth"] == 12 + empty = tmp_path / "empty.a3m" + empty.write_text("") + for chains in ([f"A={path}"], [f"A={path}", f"B={path}"], [f"A={empty}"]): + with pytest.raises(ValueError): + resolve_msas(complex_input(SEQ_A, SEQ_B), + MsaOptions(source="custom", + custom_a3m=parse_chain_paths(chains))) + + +def test_resolve_af3_data_json(tmp_path): + data = complex_input(SEQ_A) + data["sequences"][0]["protein"].update( + unpairedMsa=a3m(SEQ_A, 10), pairedMsa="", templates=[{"mmcif": "x"}] + ) + (tmp_path / "t").mkdir() + (tmp_path / "t" / "t_data.json").write_text(json.dumps(data)) + result = resolve_msas(complex_input(SEQ_A), + MsaOptions(source="af3", af3_data_json=str(tmp_path))) + protein = result.params["sequences"][0]["protein"] + assert protein["templates"] == [{"mmcif": "x"}] + assert result.chains["A"]["depth"] == 11 + + +def test_parse_chain_paths(): + assert parse_chain_paths(["A,B=x.a3m", "C=y.a3m", "z.a3m"]) == { + "A": "x.a3m", "B": "x.a3m", "C": "y.a3m", "*": "z.a3m"} + + +def test_export_formats(tmp_path): + params = resolve_msas(complex_input(SEQ_A, SEQ_B), + MsaOptions(source="server", cache_dir=str(tmp_path / "c")), + client=FakeClient()).params + written = export_msas(params, tmp_path / "out", + ["boltz", "chai1", "protenix", "openfold3"]) + assert (tmp_path / "out/boltz/A.csv").exists() + assert len(written["chai1"]) == 2 + assert (tmp_path / "out/protenix/A/non_pairing.a3m").exists() + assert (tmp_path / "out/protenix/A/pairing.a3m").exists() + assert (tmp_path / "out/openfold3/B/colabfold_main.a3m").exists() diff --git a/tests/test_msa_guard.py b/tests/test_msa_guard.py new file mode 100644 index 0000000..7cb11df --- /dev/null +++ b/tests/test_msa_guard.py @@ -0,0 +1,129 @@ +"""Regression tests: a requested MSA must reach the backend (Protenix N_msa 2 bug).""" + +import json +import re +from pathlib import Path + +import pytest + +from abcfold.msa.guard import (ShallowMsaError, check_backend_n_msa, + check_input_msa_depth, check_protenix_input, + msa_rows, parse_n_msa) +from abcfold.protenix import run_protenix as rp + +QUERY = "MTEYKLVVVGADGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQ" + + +def a3m(n): + rows = [f">query\n{QUERY}\n"] + for i in range(n): + rows.append(f">hit{i}\n{QUERY[:-2]}{'ACDEFGHIKLMNPQRSTVWY'[i % 20]}" + f"{'ACDEFGHIKLMNPQRSTVWY'[(i // 20) % 20]}\n") + return "".join(rows) + + +def kras_input(msa): + protein = {"id": "A", "sequence": QUERY} + if msa is not None: + protein.update(unpairedMsa=msa, pairedMsa="", templates=[]) + return { + "name": "kras", + "modelSeeds": [1], + "sequences": [ + {"protein": protein}, + {"ligand": {"id": "B", "ccdCodes": ["GDP"]}}, + {"ligand": {"id": "C", "ccdCodes": ["MG"]}}, + ], + } + + +def test_msa_rows_counts_distinct_non_gap_rows(): + assert msa_rows(a3m(30)) == 31 + gap = f">g\n{'-' * len(QUERY)}\n" + assert msa_rows(a3m(3) + gap, f">query\n{QUERY}\n") == 4 + + +def test_parse_n_msa(): + log = "kras [seed:1]: N_asym 4, N_token 242, N_atom 1430, N_msa 2\n" + assert parse_n_msa(log) == [2] + + +def test_input_depth_guard(): + check_input_msa_depth(kras_input(a3m(50)), 10) + check_input_msa_depth(kras_input(None), 10) # no MSA requested + check_input_msa_depth(kras_input(""), 10) # single-sequence mode + with pytest.raises(ShallowMsaError, match="A: 3 rows"): + check_input_msa_depth(kras_input(a3m(2)), 10) + check_input_msa_depth(kras_input(a3m(2)), 0) # disabled + + +def test_protenix_input_guard_detects_missing_file(tmp_path): + job = [{"sequences": [{"proteinChain": { + "sequence": QUERY, "count": 1, + "unpairedMsaPath": str(tmp_path / "gone" / "non_pairing.a3m")}}]}] + with pytest.raises(ShallowMsaError, match="does not exist"): + check_protenix_input(job, 10) + + +def test_backend_n_msa_guard(): + check_backend_n_msa("Protenix", "N_msa 512", 10) + with pytest.raises(ShallowMsaError, match="N_msa=2"): + check_backend_n_msa("Protenix", "N_msa 2", 10) + + +class FakeProtenixEnv: + """Stands in for the Protenix env: checks what Protenix would read.""" + + def __init__(self, report_n_msa=None): + self.report_n_msa = report_n_msa + self.seen_rows = [] + + def has_executable(self, name): + return False + + def run(self, cmd, extra_env=None, log_file=None, **kwargs): + input_json = Path(cmd[cmd.index("--input_json_path") + 1]) + dump_dir = Path(cmd[cmd.index("--dump_dir") + 1]) + assert cmd[cmd.index("--use_msa") + 1] == "True" + job = json.loads(input_json.read_text())[0] + chain = job["sequences"][0]["proteinChain"] + assert "msa" not in chain # deprecated field must not be used + # The MSA file must still exist while Protenix runs + rows = msa_rows(Path(chain["unpairedMsaPath"]).read_text()) + self.seen_rows.append(rows) + n_msa = self.report_n_msa if self.report_n_msa is not None else rows + Path(log_file).write_text( + f"kras [seed:1]: N_asym 3, N_token 60, N_atom 400, N_msa {n_msa}\n" + ) + out = dump_dir / "kras" / "seed_1" / "predictions" + out.mkdir(parents=True) + (out / "kras_sample_0.cif").write_text("data_x\n") + + +def _run(tmp_path, monkeypatch, msa, env): + monkeypatch.setattr(rp, "ensure_protenix_env", lambda config: env) + input_json = tmp_path / "abc_input.json" + input_json.write_text(json.dumps(kras_input(msa))) + return rp.run_protenix(input_json, tmp_path / "out", config={}, + number_of_models=1) + + +def test_protenix_receives_full_msa(tmp_path, monkeypatch): + env = FakeProtenixEnv() + assert _run(tmp_path, monkeypatch, a3m(200), env) is True + assert env.seen_rows == [201] + + +def test_protenix_fails_loudly_when_msa_is_lost(tmp_path, monkeypatch): + env = FakeProtenixEnv(report_n_msa=2) + with pytest.raises(ShallowMsaError): + _run(tmp_path, monkeypatch, a3m(200), env) + err = (tmp_path / "out" / "protenix_error.log").read_text() + assert re.search(r"N_msa=2", err) + + +def test_protenix_shallow_input_fails_before_running(tmp_path, monkeypatch): + env = FakeProtenixEnv() + with pytest.raises(ShallowMsaError): + _run(tmp_path, monkeypatch, a3m(3), env) + assert env.seen_rows == [] diff --git a/tests/test_plots.py b/tests/test_plots.py index e081377..5c02edb 100644 --- a/tests/test_plots.py +++ b/tests/test_plots.py @@ -54,16 +54,19 @@ def test_pae_plots(output_objs): assert len(plot_pathways) == 10 values = [Path(value).name for value in plot_pathways.values()] - assert "confidences_seed-1_sample-0_af3_pae_plot.html" in values - assert "confidences_seed-1_sample-1_af3_pae_plot.html" in values - assert "pae_test_mmseqs_model_0_test_mmseqs_af3_pae_plot.html" in values - assert "pae_test_mmseqs_model_1_test_mmseqs_af3_pae_plot.html" in values - assert "pae_scores_model_0_chai1_6BJ9_seed-1_af3_pae_plot.html" in values - assert "pae_scores_model_1_chai1_6BJ9_seed-1_af3_pae_plot.html" in values - assert "6BJ9_full_data_sample_0_predictions_af3_pae_plot.html" in values - assert "6BJ9_full_data_sample_1_predictions_af3_pae_plot.html" in values - assert "6BJ9_seed_1_sample_1_confidences_seed_1_af3_pae_plot.html" in values - assert "6BJ9_seed_1_sample_2_confidences_seed_1_af3_pae_plot.html" in values + # PAE is converted to a separate _af3_pae.json per model (inputs are never rewritten in place). + assert sorted(values) == [ + "6BJ9_sample_0_af3_pae_predictions_af3_pae_plot.html", + "6BJ9_sample_1_af3_pae_predictions_af3_pae_plot.html", + "6BJ9_seed_1_sample_1_model_fixed_af3_pae_seed_1_af3_pae_plot.html", + "6BJ9_seed_1_sample_2_model_fixed_af3_pae_seed_1_af3_pae_plot.html", + "model_af3_pae_seed-1_sample-0_af3_pae_plot.html", + "model_af3_pae_seed-1_sample-1_af3_pae_plot.html", + "pred.model_idx_0_af3_pae_chai1_6BJ9_seed-1_af3_pae_plot.html", + "pred.model_idx_1_af3_pae_chai1_6BJ9_seed-1_af3_pae_plot.html", + "test_mmseqs_model_0_af3_pae_test_mmseqs_af3_pae_plot.html", + "test_mmseqs_model_1_af3_pae_test_mmseqs_af3_pae_plot.html", + ] assert ( any( diff --git a/tests/test_report.py b/tests/test_report.py new file mode 100644 index 0000000..94a5e3a --- /dev/null +++ b/tests/test_report.py @@ -0,0 +1,124 @@ +import json +import sys +from pathlib import Path + +import numpy as np +import pytest + +from abcfold.output.utils import af3_pae_path +from abcfold.report import (SCHEMA, EngineRecord, SampleRecord, build_report, + extract_scores, ligand_pae, samples_from_output, + to_percent, validate_report, write_report) + + +@pytest.mark.parametrize("data,score", [ + ({"ranking_score": 0.8, "ptm": 0.7, "iptm": 0.6}, 0.8), # AF3/Protenix + ({"confidence_score": 0.9, "ptm": 0.5, "iptm": 0.4}, 0.9), # Boltz + ({"aggregate_score": np.array([0.3]), "ptm": np.array([0.2]), + "iptm": np.array([0.1])}, 0.3), # Chai-1 + ({"sample_ranking_score": 0.42}, 0.42), # OpenFold3 + ({}, None), +]) +def test_extract_scores(data, score): + out = extract_scores(data) + assert out["score"] == (pytest.approx(score) if score is not None else None) + + +def test_to_percent_scales_unit_plddt(): + assert to_percent([0.5, 0.7]) == pytest.approx(60.0) + assert to_percent([50, 70]) == pytest.approx(60.0) + assert to_percent([]) is None + + +def test_ligand_pae_both_directions(): + pae = [[0, 1, 2], + [3, 0, 4], + [5, 6, 0]] + chains = ["A", "A", "L"] + # A->L: 2, 4 ; L->A: 5, 6 + assert ligand_pae(pae, chains, ["L"]) == pytest.approx(17 / 4) + assert ligand_pae(pae, chains, []) is None + assert ligand_pae(pae, ["A", "A"], ["L"]) is None + + +def engine(name, status, scores=(), error=None): + rec = EngineRecord(engine=name, version="1.0", status=status, seconds=10.0, + error=error) + rec.samples = [ + SampleRecord(engine=name, version="1.0", seed=1, rank=None, + cif=f"{name}_{i}.cif", score=s, chain_ids=["A", "B"]) + for i, s in enumerate(scores) + ] + return rec + + +def test_build_report_ranks_and_status(): + report = build_report( + "kras", + [engine("boltz", "ok", [0.2, 0.9, None]), + engine("chai1", "failed", error="boom"), + engine("protenix", "skipped")], + msa={"source": "server", "chains": {"A": {"depth": 10}}}, + ) + assert report["schema"] == SCHEMA + assert report["status"] == "partial" + boltz = [s for s in report["samples"] if s["engine"] == "boltz"] + assert [s["score"] for s in boltz] == [0.9, 0.2, None] + assert [s["rank"] for s in boltz] == [1, 2, 3] + eng = {e["engine"]: e for e in report["engines"]} + assert eng["boltz"]["top_score"] == 0.9 + assert eng["chai1"]["error"] == "boom" + assert validate_report(report) == [] + + +def test_report_status_all_failed_and_ok(): + assert build_report("x", [engine("boltz", "failed", error="e")])["status"] == \ + "failed" + assert build_report("x", [engine("boltz", "ok", [0.1])])["status"] == "ok" + + +def test_validate_report_catches_problems(): + report = build_report("x", [engine("boltz", "failed")]) + errors = validate_report(report) + assert any("failed engine without error" in e for e in errors) + report["samples"] = [{"engine": "boltz", "score": "high"}] + assert any("missing" in e for e in validate_report(report)) + + +def test_write_report_is_json(tmp_path): + report = build_report("x", [engine("boltz", "ok", [0.5])]) + path = write_report(report, tmp_path / "sub" / "report.json") + assert json.loads(path.read_text())["schema"] == SCHEMA + + +def test_samples_from_output_with_real_outputs(output_objs, tmp_path): + samples = samples_from_output("boltz", "2.2.1", output_objs.boltz_output.output, + tmp_path, seconds_per_sample=3.0) + assert samples + s = samples[0] + assert s.engine == "boltz" and s.version == "2.2.1" + assert s.score is not None and 0 <= s.score <= 1 + assert s.plddt is not None and 0 < s.plddt <= 100 + assert s.chain_ids + assert s.seconds == 3.0 + af3 = samples_from_output("alphafold3", "3.0.4", output_objs.af3_output.output, + tmp_path) + assert all(x.score is not None for x in af3) + report = build_report("6BJ9", [EngineRecord("boltz", "2.2.1", "ok", 1.0, + samples=samples)]) + assert validate_report(report) == [] + + +def test_pae_files_use_json_extension(): + """Defect 5: converted PAE files were written with npz/npy suffixes.""" + for name in ("pred.model_idx_0.cif", "model_0.cif", "x.npz.cif"): + out = af3_pae_path(Path("/o") / name) + assert out.suffix == ".json" + assert out.name.endswith("_af3_pae.json") + + +def test_report_cli_exit_codes_are_distinct(): + from abcfold.abcfold import EXIT_FAILED, EXIT_OK, EXIT_PARTIAL + + assert len({EXIT_OK, EXIT_FAILED, EXIT_PARTIAL}) == 3 + assert "abcfold.report" in sys.modules diff --git a/tests/test_run_chai.py b/tests/test_run_chai.py index f77d37b..9cfca5f 100644 --- a/tests/test_run_chai.py +++ b/tests/test_run_chai.py @@ -90,6 +90,6 @@ def test_chai_fast_manifests_preserve_quality_settings(): assert '"number_of_models": 5' in manifest_text assert '"num_recycles": 10' in manifest_text assert ( - "num_diffn_timesteps=200" + 'num_diffn_timesteps=task.get("diffusion_steps", 200)' in _write_worker_script(Path(temp_dir)).read_text() ) diff --git a/tests/test_settings.py b/tests/test_settings.py new file mode 100644 index 0000000..d0ae9bc --- /dev/null +++ b/tests/test_settings.py @@ -0,0 +1,104 @@ +from abcfold.abcfold import build_run_parser, resolve_settings +from abcfold.backend_envs import (FORBIDDEN_PACKAGES, BackendEnvSpec, + build_commands) +from abcfold.settings import load_backend_pins, load_settings + + +def test_defaults_have_no_none_strings(): + settings = load_settings(environ={}) + assert all(v != "None" for v in settings.values.values()) + assert settings.get("model_params") is None + assert settings.get("msa_server_url") == "https://api.colabfold.com" + assert settings.get("min_msa_rows") == 10 + + +def test_parser_parses_with_unset_config(tmp_path): + """Defect 1: a None/"None" default in the config crashed argparse.""" + cfg = tmp_path / "legacy.ini" + cfg.write_text("[Boltz]\nboltz_max_parallel_samples = None\n" + "boltz_num_workers = 3\n[Weights]\nmodel_params = None\n") + input_json = tmp_path / "in.json" + input_json.write_text("{}") + args = build_run_parser().parse_args( + [str(input_json), str(tmp_path / "out"), "--config-file", str(cfg), "-b"] + ) + settings = resolve_settings(args) + assert args.boltz_max_parallel_samples is None + assert args.boltz_num_workers == "3" or args.boltz_num_workers == 3 + assert args.model_params is None + assert settings.source_file == cfg + + +def test_cli_flags_override_config(tmp_path): + cfg = tmp_path / "c.toml" + cfg.write_text('[msa]\nmsa_server_url = "http://cfg"\n') + input_json = tmp_path / "in.json" + input_json.write_text("{}") + args = build_run_parser().parse_args([ + str(input_json), str(tmp_path / "o"), "--config-file", str(cfg), + "--msa_server_url", "http://cli", + ]) + assert resolve_settings(args).get("msa_server_url") == "http://cli" + args = build_run_parser().parse_args([ + str(input_json), str(tmp_path / "o"), "--config-file", str(cfg)]) + assert resolve_settings(args).get("msa_server_url") == "http://cfg" + + +def test_config_versions_are_honoured(tmp_path): + """Defect 2: versions in the config file were ignored.""" + cfg = tmp_path / "c.toml" + cfg.write_text('[backends.boltz]\nversion = "2.1.0"\nenv = "my-boltz"\n') + boltz = load_settings(cfg, environ={}).backend("boltz") + assert boltz["version"] == "2.1.0" + assert boltz["env"] == "my-boltz" + assert any(spec.startswith("boltz") and "==2.1.0" in spec for spec in boltz["pip"]) + + +def test_legacy_ini_versions_and_env_override(tmp_path): + cfg = tmp_path / "c.ini" + cfg.write_text("[Versions]\nchai_version = 0.6.0\n[Environments]\n" + "protenix_env = px-old\n") + settings = load_settings(cfg, environ={"ABCFOLD_PROTENIX_VERSION": "1.0.4", + "ABCFOLD_MIN_MSA_ROWS": "0"}) + assert settings.backend("chai1")["version"] == "0.6.0" + assert settings.backend("protenix")["env"] == "px-old" + assert settings.backend("protenix")["version"] == "1.0.4" + assert settings.get("min_msa_rows") == 0 + + +def test_settings_never_write(tmp_path): + cfg = tmp_path / "c.toml" + cfg.write_text('[paths]\nmodel_params = "/x"\n') + before = cfg.read_text() + load_settings(cfg, environ={}).apply_overrides({"model_params": "/y"}) + assert cfg.read_text() == before + assert list(tmp_path.iterdir()) == [cfg] + + +def test_backend_pins_are_exact_and_rdkit_pypi_free(): + pins = load_backend_pins() + for name in ("boltz", "chai1", "protenix", "openfold3"): + spec = pins[name] + assert any(f"=={spec['version']}" in p for p in spec["pip"]), name + assert not any("rdkit-pypi" in p for p in spec["pip"]), name + assert pins["protenix"]["model"] == "protenix_base_default_v1.0.0" + + +def test_build_commands_remove_rdkit_pypi(): + spec = BackendEnvSpec.from_settings("protenix", load_backend_pins()["protenix"]) + cmds = build_commands(spec, python_path="/env/bin/python") + assert cmds[0][:2] == ["micromamba", "create"] + install = cmds[1] + assert install[:3] == ["uv", "pip", "install"] + assert "--torch-backend" in install + assert "protenix==2.0.0" in install + assert cmds[2][-len(FORBIDDEN_PACKAGES):] == list(FORBIDDEN_PACKAGES) + assert "uninstall" in cmds[2] + + +def test_runtime_config_exposes_legacy_keys(): + cfg = load_settings(environ={}).runtime_config() + assert cfg["boltz_env"] == "abcfold2-boltz" + assert cfg["protenix_model"] == "protenix_base_default_v1.0.0" + assert cfg["openfold_checkpoint"] + assert cfg["_settings"] is not None diff --git a/tests/test_utilities.py b/tests/test_utilities.py index 145e762..3606313 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -1,5 +1,6 @@ import json import tempfile +import shutil from pathlib import Path from abcfold.output.file_handlers import CifFile, ConfidenceJsonFile @@ -81,9 +82,12 @@ def test_clash_checker(test_data): assert len(clashes) == 2 -def test_af3_pae_reorder(test_data): - test_cif = Path(test_data.test_alphafold3_6BJ9_).joinpath( - "seed-1_sample-0", "model.cif" +def test_af3_pae_reorder(test_data, tmp_path): + # reorder_chains() persists to the source file, so work on a copy of the fixture. + test_cif = tmp_path / "model.cif" + shutil.copy( + Path(test_data.test_alphafold3_6BJ9_).joinpath("seed-1_sample-0", "model.cif"), + test_cif, ) test_pae = Path(test_data.test_alphafold3_6BJ9_).joinpath( "seed-1_sample-0", "confidences.json" @@ -113,5 +117,3 @@ def test_af3_pae_reorder(test_data): pae_obj.scores["token_chain_ids"][787 + 50 :] # noqa: E203 == pae_to_compare_tci[:51] ) - - cif.reorder_chains(["A", "B", "C", "D"])