diff --git a/ImmuneBuilder/ABodyBuilder2.py b/ImmuneBuilder/ABodyBuilder2.py index 8528534..3006647 100644 --- a/ImmuneBuilder/ABodyBuilder2.py +++ b/ImmuneBuilder/ABodyBuilder2.py @@ -46,7 +46,7 @@ def save_single_unrefined(self, filename, index=0): file.write(unrefined) - def save_all(self, dirname=None, filename=None): + def save_all(self, dirname=None, filename=None, check_for_strained_bonds=True): if dirname is None: dirname="ABodyBuilder2_output" if filename is None: @@ -60,22 +60,22 @@ def save_all(self, dirname=None, filename=None): np.save(os.path.join(dirname,"error_estimates"), self.error_estimates.mean(0).cpu().numpy()) final_filename = os.path.join(dirname, filename) - refine(os.path.join(dirname,"rank0_unrefined.pdb"), final_filename) + refine(os.path.join(dirname,"rank0_unrefined.pdb"), final_filename, check_for_strained_bonds=check_for_strained_bonds) add_errors_as_bfactors(final_filename, self.error_estimates.mean(0).sqrt().cpu().numpy(), header=[header]) - def save(self, filename=None): + def save(self, filename=None,check_for_strained_bonds=True): if filename is None: filename = "ABodyBuilder2_output.pdb" for i in range(len(self.atoms)): self.save_single_unrefined(filename, index=self.ranking.index(i)) - success = refine(filename, filename) + success = refine(filename, filename, check_for_strained_bonds=check_for_strained_bonds) if success: break else: self.save_single_unrefined(filename, index=self.ranking.index(i)) - success = refine(filename, filename) + success = refine(filename, filename, check_for_strained_bonds=check_for_strained_bonds) if success: break @@ -147,8 +147,8 @@ def command_line_interface(): parser.add_argument("--to_directory", help="Save all unrefined models and the top ranked refined model to a directory. " "If this flag is set the output argument will be assumed to be a directory", default=False, action="store_true") parser.add_argument("-n", "--numbering_scheme", help="The scheme used to number output antibody structures. Available numbering schemes are: imgt, chothia, kabat, aho, wolfguy, martin and raw. Default is imgt.", default='imgt') + parser.add_argument("-u", "--no_sidechain_bond_check", help="Don't check for strained bonds. This is a bit faster but will rarely generate unphysical side chains", default=False, action="store_true") parser.add_argument("-v", "--verbose", help="Verbose output", default=False, action="store_true") - args = parser.parse_args() if (args.heavy_sequence is not None) and (args.light_sequence is not None): @@ -158,6 +158,8 @@ def command_line_interface(): else: raise ValueError("Missing input sequences") + check_for_strained_bonds = not args.no_sidechain_bond_check + if args.verbose: print(description, flush=True) print(f"Sequences loaded succesfully.\nHeavy and light chains are:", flush=True) @@ -174,11 +176,11 @@ def command_line_interface(): print("Antibody modelled succesfully, starting refinement.", flush=True) if args.to_directory: - antibody.save_all(args.output) + antibody.save_all(args.output,check_for_strained_bonds) if args.verbose: print("Refinement finished. Saving all outputs to directory", flush=True) else: - antibody.save(args.output) + antibody.save(args.output,check_for_strained_bonds) if args.verbose: outfile = "ABodyBuilder2_output.pdb" if args.output is None else args.output print(f"Refinement finished. Saving final structure to {outfile}", flush=True) diff --git a/ImmuneBuilder/NanoBodyBuilder2.py b/ImmuneBuilder/NanoBodyBuilder2.py index 68c2152..f5cae13 100644 --- a/ImmuneBuilder/NanoBodyBuilder2.py +++ b/ImmuneBuilder/NanoBodyBuilder2.py @@ -46,7 +46,7 @@ def save_single_unrefined(self, filename, index=0): file.write(unrefined) - def save_all(self, dirname=None, filename=None): + def save_all(self, dirname=None, filename=None, check_for_strained_bonds=True): if dirname is None: dirname="NanoBodyBuilder2_output" if filename is None: @@ -60,22 +60,22 @@ def save_all(self, dirname=None, filename=None): np.save(os.path.join(dirname,"error_estimates"), self.error_estimates.mean(0).cpu().numpy()) final_filename = os.path.join(dirname, filename) - refine(os.path.join(dirname,"rank0_unrefined.pdb"), final_filename) + refine(os.path.join(dirname,"rank0_unrefined.pdb"), final_filename, check_for_strained_bonds=check_for_strained_bonds) add_errors_as_bfactors(final_filename, self.error_estimates.mean(0).sqrt().cpu().numpy(), header=[header]) - def save(self, filename=None): + def save(self, filename=None, check_for_strained_bonds=True): if filename is None: filename = "NanoBodyBuilder2_output.pdb" for i in range(len(self.atoms)): self.save_single_unrefined(filename, index=self.ranking.index(i)) - success = refine(filename, filename) + success = refine(filename, filename, check_for_strained_bonds=check_for_strained_bonds) if success: break else: self.save_single_unrefined(filename, index=self.ranking.index(i)) - success = refine(filename, filename) + success = refine(filename, filename, check_for_strained_bonds=check_for_strained_bonds) if success: break @@ -150,7 +150,7 @@ def command_line_interface(): parser.add_argument("--to_directory", help="Save all unrefined models and the top ranked refined model to a directory. " "If this flag is set the output argument will be assumed to be a directory", default=False, action="store_true") parser.add_argument("-n", "--numbering_scheme", help="The scheme used to number output nanobody structures. Available numbering schemes are: imgt, chothia, kabat, aho, wolfguy, martin and raw. Default is imgt.", default='imgt') - + parser.add_argument("-u", "--no_sidechain_bond_check", help="Don't check for strained bonds. This is a bit faster but will rarely generate unphysical side chains", default=False, action="store_true") parser.add_argument("-v", "--verbose", help="Verbose output", default=False, action="store_true") args = parser.parse_args() @@ -162,6 +162,8 @@ def command_line_interface(): else: raise ValueError("Missing input sequences") + check_for_strained_bonds = not args.no_sidechain_bond_check + if args.verbose: print(description, flush=True) print(f"Sequence loaded succesfully.\nHeavy chain is:", flush=True) @@ -178,11 +180,11 @@ def command_line_interface(): print("Nanobody modelled succesfully, starting refinement.", flush=True) if args.to_directory: - antibody.save_all(args.output) + antibody.save_all(args.output,check_for_strained_bonds) if args.verbose: print("Refinement finished. Saving all outputs to directory", flush=True) else: - antibody.save(args.output) + antibody.save(args.output,check_for_strained_bonds) if args.verbose: outfile = "NanoBodyBuilder2_output.pdb" if args.output is None else args.output print(f"Refinement finished. Saving final structure to {outfile}", flush=True) diff --git a/ImmuneBuilder/TCRBuilder2.py b/ImmuneBuilder/TCRBuilder2.py index efb16e4..620ff11 100644 --- a/ImmuneBuilder/TCRBuilder2.py +++ b/ImmuneBuilder/TCRBuilder2.py @@ -46,7 +46,7 @@ def save_single_unrefined(self, filename, index=0): file.write(unrefined) - def save_all(self, dirname=None, filename=None): + def save_all(self, dirname=None, filename=None, check_for_strained_bonds=True): if dirname is None: dirname="TCRBuilder2_output" if filename is None: @@ -60,22 +60,22 @@ def save_all(self, dirname=None, filename=None): np.save(os.path.join(dirname,"error_estimates"), self.error_estimates.mean(0).cpu().numpy()) final_filename = os.path.join(dirname, filename) - refine(os.path.join(dirname,"rank0_unrefined.pdb"), final_filename) + refine(os.path.join(dirname,"rank0_unrefined.pdb"), final_filename, check_for_strained_bonds=check_for_strained_bonds) add_errors_as_bfactors(final_filename, self.error_estimates.mean(0).sqrt().cpu().numpy(), header=[header]) - def save(self, filename=None): + def save(self, filename=None, check_for_strained_bonds=True): if filename is None: filename = "TCRBuilder2_output.pdb" for i in range(len(self.atoms)): self.save_single_unrefined(filename, index=self.ranking.index(i)) - success = refine(filename, filename) + success = refine(filename, filename, check_for_strained_bonds=check_for_strained_bonds) if success: break else: self.save_single_unrefined(filename, index=self.ranking.index(i)) - success = refine(filename, filename) + success = refine(filename, filename, check_for_strained_bonds=check_for_strained_bonds) if success: break @@ -147,6 +147,7 @@ def command_line_interface(): parser.add_argument("-o", "--output", help="Path to where the output model should be saved. Defaults to the same directory as input file.", default=None) parser.add_argument("--to_directory", help="Save all unrefined models and the top ranked refined model to a directory. " "If this flag is set the output argument will be assumed to be a directory", default=False, action="store_true") + parser.add_argument("-u", "--no_sidechain_bond_check", help="Don't check for strained bonds. This is a bit faster but will rarely generate unphysical side chains", default=False, action="store_true") parser.add_argument("-v", "--verbose", help="Verbose output", default=False, action="store_true") args = parser.parse_args() @@ -158,6 +159,8 @@ def command_line_interface(): else: raise ValueError("Missing input sequences") + check_for_strained_bonds = not args.no_sidechain_bond_check + if args.verbose: print(description, flush=True) print(f"Sequences loaded succesfully.\nAlpha and Beta chains are:", flush=True) @@ -174,11 +177,11 @@ def command_line_interface(): print("TCR modelled succesfully, starting refinement.", flush=True) if args.to_directory: - tcr.save_all(args.output) + tcr.save_all(args.output,check_for_strained_bonds) if args.verbose: print("Refinement finished. Saving all outputs to directory", flush=True) else: - tcr.save(args.output) + tcr.save(args.output,check_for_strained_bonds) if args.verbose: outfile = "TCRBuilder2_output.pdb" if args.output is None else args.output print(f"Refinement finished. Saving final structure to {outfile}", flush=True) diff --git a/ImmuneBuilder/refine.py b/ImmuneBuilder/refine.py index 87c04a2..d491621 100644 --- a/ImmuneBuilder/refine.py +++ b/ImmuneBuilder/refine.py @@ -26,14 +26,14 @@ forcefield = app.ForceField("amber14/protein.ff14SB.xml") -def refine(input_file, output_file, tries=3, n=6): +def refine(input_file, output_file, check_for_strained_bonds=True, tries=3, n=6): for i in range(tries): - if refine_once(input_file, output_file, n=n): + if refine_once(input_file, output_file, check_for_strained_bonds=check_for_strained_bonds, n=n): return True return False -def refine_once(input_file, output_file, n=6): +def refine_once(input_file, output_file, check_for_strained_bonds=True, n=6): k1s = [2.5,1,0.5,0.25,0.1,0.001] k2s = [2.5,5,7.5,15,25,50] success = False @@ -81,17 +81,20 @@ def refine_once(input_file, output_file, n=6): topology, positions = fixer.topology, fixer.positions continue - # If all other checks pass, check and fix strained sidechain bonds: - try: - strained_bonds = strained_sidechain_bonds_check(topology, positions) - if len(strained_bonds) > 0: - needs_recheck = True - topology, positions = strained_sidechain_bonds_fixer(strained_bonds, topology, positions) - else: - needs_recheck = False - except OpenMMException as e: - topology, positions = fixer.topology, fixer.positions - continue + if check_for_strained_bonds: + # If all other checks pass, check and fix strained sidechain bonds: + try: + strained_bonds = strained_sidechain_bonds_check(topology, positions) + if len(strained_bonds) > 0: + needs_recheck = True + topology, positions = strained_sidechain_bonds_fixer(strained_bonds, topology, positions) + else: + needs_recheck = False + except OpenMMException as e: + topology, positions = fixer.topology, fixer.positions + continue + else: + needs_recheck = False # If it passes all the tests, we are done tests = bond_check(topology, positions) and cis_check(topology, positions)