import os from time import time from glob import glob import torch from antiberty import AntiBERTyRunner import igfold from igfold.model.IgFold import IgFold from igfold.utils.folding import fold from igfold.utils.embed import embed from igfold.utils.general import exists def display_license(): license_url = "https://github.com/Graylab/IgFold/blob/main/LICENSE.md" license_message = f""" The code, data, and weights for this work are made available for non-commercial use (including at commercial entities) under the terms of the JHU Academic Software License Agreement. For commercial inquiries, please contact awichma2[at]jhu.edu. License: {license_url} """ print(license_message) class IgFoldRunner(): """ Wrapper for IgFold model predictions. """ def __init__(self, num_models=4, model_ckpts=None, try_gpu=True): """ Initialize IgFoldRunner. :param num_models: Number of pre-trained IgFold models to use for prediction. :param model_ckpts: List of model checkpoints to use (instead of pre-trained). """ display_license() if exists(model_ckpts): num_models = len(model_ckpts) else: if num_models < 1 or num_models > 4: raise ValueError("num_models must be between 1 and 4.") if not exists(model_ckpts): project_path = os.path.dirname( os.path.realpath(igfold.__file__)) ckpt_path = os.path.join( project_path, "trained_models/IgFold/*.ckpt", ) model_ckpts = list(glob(ckpt_path)) model_ckpts = list(sorted(model_ckpts))[:num_models] print(f"Loading {num_models} IgFold models...") device = torch.device( "cuda:0" if torch.cuda.is_available() and try_gpu else "cpu") print(f"Using device: {device}") self.models = [] for ckpt_file in model_ckpts: print(f"Loading {ckpt_file}...") self.models.append( IgFold.load_from_checkpoint(ckpt_file).eval().to(device)) print(f"Successfully loaded {num_models} IgFold models.") self.antiberty = AntiBERTyRunner() self.antiberty.model.eval() self.antiberty.model.to(device) print("Loaded AntiBERTy model.") def fold( self, pdb_file, fasta_file=None, sequences=None, template_pdb=None, ignore_cdrs=None, ignore_chain=None, skip_pdb=False, do_refine=True, use_openmm=False, do_renum=True, truncate_sequences=False, ): """ Predict antibody structure with IgFold. :param pdb_file: PDB file to predict. :param fasta_file: FASTA file containing sequences. :param sequences: Dictionary of sequences. :param template_pdb: PDB file containing template structure. :param ignore_cdrs: List of CDRs to ignore. :param ignore_chain: Chain to ignore. :param skip_pdb: Skip PDB processing. :param do_refine: Perform PyRosetta refinement. :param do_renum: Renumber PDB to Chothia with AbNum. :param truncate_sequences: Truncate sequences with AbNumber. """ start_time = time() model_out = fold( self.antiberty, self.models, pdb_file=pdb_file, fasta_file=fasta_file, sequences=sequences, template_pdb=template_pdb, ignore_cdrs=ignore_cdrs, ignore_chain=ignore_chain, skip_pdb=skip_pdb, do_refine=do_refine, use_openmm=use_openmm, do_renum=do_renum, truncate_sequences=truncate_sequences, ) print(f"Completed folding in {time() - start_time:.2f} seconds.") return model_out def embed( self, model_idx=0, fasta_file=None, sequences=None, template_pdb=None, ignore_cdrs=None, ignore_chain=None, ): """ Embed antibody sequences with IgFold. :param fasta_file: FASTA file containing sequences. :param sequences: Dictionary of sequences. :param template_pdb: PDB file containing template structure. :param ignore_cdrs: List of CDRs to ignore. :param ignore_chain: Chain to ignore. """ start_time = time() model_out = embed( self.antiberty, self.models[model_idx], fasta_file=fasta_file, sequences=sequences, template_pdb=template_pdb, ignore_cdrs=ignore_cdrs, ignore_chain=ignore_chain, ) print(f"Completed embedding in {time() - start_time:.2f} seconds.") return model_out