class FitterObject(object): def __init__(self, time=True, verbose=True): self.allowedArgs = allowed_fitter_args self.preferChain = DEFAULT_OUTPUT_CHAIN[0] # Settings self.time = time self.verbose = verbose self.runtime = -1.0 self.timeout = 99999 # Custom Init self._custom_init() def fit_ligand(self, ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags=[]): """Fit Ligand to a structure""" # Prepare input and output filenames self._prepare_to_fit_ligand(ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags) # Check to see if already run, and if not, run the custom part of the object - different for each program if os.path.exists(self.outpdb) and os.path.exists(self.outlog): if self.verbose: print('\tLigand already fitted - DOING NOTHING') self._post_process(ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags) else: if self.verbose: print('\tFitting using {!s}.'.format(self.name)) cmd_line_args, std_inpt_args = self._create_program_arguments( ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags) # Initialise CommandManager self.Fitter = CommandManager(self.program) # Set Command-Line Args if cmd_line_args: self.Fitter.SetArguments(cmd_line_args) # Set Standard Input if std_inpt_args: self.Fitter.SetInput(std_inpt_args) # Set Parameters self.Fitter.SetParameters(timeout=self.timeout) # RUN self.Fitter.Run() # Calculate runtime (seconds) self.runtime = self.Fitter.runtime try: # Process results and generate the list of modelled ligands if self.verbose: print('\tFinished fitting - post-processing models.') self._post_process(ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags) if not self.outmodels: raise FittingError( 'No fitted models found! Log: {!s}'.format( self.outlog)) if not os.path.exists(self.outpdb): # Map the model of the best ligand to the asu and check it's near to the protein self._map_to_asu(ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags) # Create symbolic links to the output file self._link_output_files() # Merge the best ligand with the apo structure if not os.path.exists(self.mergedpdb): self.Merger = merge_pdb_files(apopdb, self.outpdb, self.mergedpdb) finally: self.write_log_file() return self.outpdb, self.mergedpdb, self.outlog def _prepare_to_fit_ligand(self, ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags): """Set up the generic file names""" # Process outputfile if '/' in outfile: raise ValueError('outfile must be a file, not a path') # Record Template and Outdir self.outtemplate = os.path.join(outdir, outfile) self.outdir = outdir # Record Filenames self.outpdb = self.outtemplate + '.lig.pdb' self.mergedpdb = self.outtemplate + '.pdb' self.outlog = self.outtemplate + '.log' # Storage self.outmodels = [] self.filtmodels = [] self.bestmodel = None self.fittingdata = None # Prepare custom settings self._custom_prepare_to_fit_ligand(ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags) return def _map_to_asu(self, ligcif, ligpdb, mtz, apopdb, outdir, outfile, flags): """Map the best ligand file to the asu of the protein - pick the symmetry version with the most contacts""" candidate = None if self.verbose: print('\tMapping fitted models back to the asymmetric unit.') for model in self.outmodels: ligand_sym_file = model.replace('.pdb', '.sym.pdb') if os.path.exists(ligand_sym_file): self.filtmodels.append(model) else: try: # Create Cryst Line shutil.move(model, model + '.temp.pdb') PDBSET = create_cryst_line_from_mtz( model + '.temp.pdb', ligand_sym_file, mtz) # Rename the original file, then create a symmetry equivalent ligand that is close to the protein # shutil.move(model, ligand_sym_file) # candidate, ordered_files = map_structure_to_asu(apopdb, mtz, ligand_sym_file, model, delete_structures=True) candidate = map_to_reference_using_symmetry( refpdb=apopdb, movpdb=ligand_sym_file, pdbout=model) self.filtmodels.append(candidate) except (DistanceError, IOError) as err: print(err) continue # If it gets here we have a candidate # Break here for fast (1 model per fitter max) # break if not self.filtmodels: raise FittingError('No fitted models within range of protein!') else: # Rename all of the filtered models [ change_residue_chain_and_number(filtfile) for filtfile in self.filtmodels ] # Pick the `best` one to be the output self.bestmodel = self.filtmodels[0] return def _link_output_files(self): """Make links to the output files""" # Create Symlinks os.symlink(os.path.relpath(self.bestmodel, start=self.outdir), self.outpdb) return def write_log_file(self): """Write the log file""" if self.verbose: print('\tWriting fitting logfile.') with open(self.outlog, 'w') as logfile: if hasattr(self, 'Fitter'): # Write out the input command logfile.write('\nCOMMAND\n\n') logfile.write('\n'.join(self.Fitter.command)) logfile.write('\nINPUT\n\n') logfile.write(self.Fitter.inp) # Write out & err logfile.write('\nFITTER STDOUT\n\n') logfile.write(self.Fitter.out) logfile.write('\nFITTER STDERR\n\n') logfile.write(self.Fitter.err) if hasattr(self, 'Merger'): # Write out the input command logfile.write('\nCOMMAND\n\n') logfile.write('\n'.join(self.Merger.command)) logfile.write('\nINPUT\n\n') logfile.write(self.Merger.inp) # Write out & err logfile.write('\nMERGER STDOUT\n\n') logfile.write(self.Merger.out) logfile.write('\nMERGER STDERR\n\n') logfile.write(self.Merger.err) return
class RefinerObject(object): def __init__(self, time=True, verbose=True): self.allowedArgs = allowed_refiner_args # Settings self.time = time self.verbose = verbose self.runtime = -1.0 self.timeout = 1800 # Custom Init self._custom_init() def run_refinement(self, inpdb, inmtz, outdir, outfile, incif=None, flags=[]): """Run Refinement of a Structure""" # Prepare standard settings self._prepare_to_refine_structure(inpdb, inmtz, outdir, outfile, incif, flags) # Check to see if already run, and if not, run the custom part of the object - different for each program if os.path.exists(self.outpdb) and os.path.exists( self.outmtz) and os.path.exists(self.outlog): if self.verbose: print('\tRefinement already done - DOING NOTHING') else: if self.verbose: print('\tRefining using {!s}.'.format(self.name)) cmd_line_args, std_inpt_args = self._create_program_arguments( inpdb, inmtz, outdir, outfile, incif, flags) # Initialise CommandManager self.Refiner = CommandManager(self.program) # Set Command-Line Args self.Refiner.SetArguments(cmd_line_args) # Set Standard Input self.Refiner.SetInput(std_inpt_args) # Set Parameters self.Refiner.SetParameters(timeout=self.timeout) # RUN self.Refiner.Run() # Calculate runtime (seconds) self.runtime = self.Refiner.runtime if self.verbose: print('\tFinished refinement - post-processing structure.') try: # General post-process self._standard_post_process(inpdb, inmtz, outdir, outfile, incif, flags) # Could add autoprocessing here... self._post_process(inpdb, inmtz, outdir, outfile, incif, flags) finally: self.write_log_file() return self.outpdb, self.outmtz, self.outlog def _prepare_to_refine_structure(self, inpdb, inmtz, outdir, outfile, incif, flags): """Set up the generic file names""" # Process outputfile if '/' in outfile: raise ValueError('outfile must be a file, not a path') # Record Template and Outdir self.outtemplate = os.path.join(outdir, outfile) self.outdir = outdir # Record Filenames self.outpdb = self.outtemplate + '.pdb' self.outmtz = self.outtemplate + '.mtz' self.outcif = self.outtemplate + '.cif' self.outlog = self.outtemplate + '.log' def _standard_post_process(self, inpdb, inmtz, outdir, outfile, incif, flags): """Perform standard operations on the output files of the refinement""" if os.path.exists(self.outpdb): remove_modres_records(self.outpdb) return def write_log_file(self): """Write the log file""" if self.verbose: print('\tWriting refinement logfile.') with open(self.outlog, 'w') as logfile: # Write out the input command logfile.write('\nCOMMAND\n\n') logfile.write('\n'.join(self.Refiner.command)) logfile.write('\nINPUT\n\n') logfile.write(self.Refiner.inp) # Write out & err logfile.write('\nSTDOUT\n\n') logfile.write(self.Refiner.out) logfile.write('\nSTDERR\n\n') logfile.write(self.Refiner.err)