def generate_ligand(self, ligsmile, outdir, outfile, flags=[]): """Generate ligand PDB and CIF from smile string""" # Prepare standard settings self._prepare_to_generate_ligand(ligsmile, 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.outcif) and os.path.exists(self.outlog): if self.verbose: print('\tLigand already generated - DOING NOTHING') else: cmd_line_args, std_inpt_args = self._create_program_arguments( ligsmile, outdir, outfile, flags) # Initialise CommandManager self.builder = CommandManager(self.program) # Set Command-Line Args if cmd_line_args: self.builder.add_command_line_arguments(cmd_line_args) # Set Standard Input if std_inpt_args: self.builder.add_standard_input(std_inpt_args) # Set Parameters self.builder.set_timeout(timeout=self.timeout) # RUN self.builder.run() # Get runtime self.runtime = self.builder.runtime try: # Could add postprocess here pass finally: self.write_log_file() return self.outpdb, self.outcif, self.outlog
def run_refinement_pipeline(in_mtz, ref_pdb, out_dir, program='dimple'): """Run refinement of the input MTZ file against a reference PDB file""" print '*************************' print '*** Running Pipelines ***' print '*************************' if program == 'dimple': # Define output files out_pdb = os.path.join(out_dir, 'final.pdb') out_mtz = os.path.join(out_dir, 'final.mtz') # Create command manager for dimple cmd = CommandManager('dimple') cmd.add_command_line_arguments( ['--jelly', '5', in_mtz, ref_pdb, out_dir]) else: raise Exception("no stop that. you're doing it wrong.") print_run_and_raise_error_maybe(cmd) if not os.path.exists(out_pdb): raise Failure( 'running refinement with {} has failed -- {} does not exist'. format(program, out_pdb)) if not os.path.exists(out_mtz): raise Failure( 'running refinement with {} has failed -- {} does not exist'. format(program, out_mtz)) return out_pdb, out_mtz
def generate_symmetry_mates(pdbin, pdbout, sgno, cell): """Takes the input pdb and generates the unit cell from the point group symmetry""" if not pdbout.endswith('.pdb'): pdbout = pdbout + '.pdb' if not os.path.exists(pdbin): raise IOError('pdbin does not exist! {!s}'.format(pdbin)) if os.path.exists(pdbout): raise Exception('pdbout already exists! {!s}'.format(pdbout)) assert isinstance(sgno, int), 'SPACEGROUP MUST BE AN INTEGER! {!s}'.format(sgno) assert isinstance(cell, list), 'CELL MUST BE A LIST! {!s}'.format(cell) # Initialise Commander PDBSET = CommandManager('pdbset') # Set Command Arguments PDBSET.add_command_line_arguments('XYZIN', os.path.abspath(pdbin), 'XYZOUT', os.path.abspath(pdbout)) # Set inputs PDBSET.add_standard_input([ 'SYMGEN {!s}'.format(sgno), 'CELL {!s}'.format(' '.join(map(str, cell))), 'END' ]) # run! PDBSET.run() if not os.path.exists(pdbout): raise ExternalProgramError( 'PDBSET has failed to generate SYMMETRY mates. {!s}\nCOM: {!s}\nOUT: {!s}\nERR: {!s}' .format(pdbin, PDBSET.command, PDBSET.out, PDBSET.err)) return pdbout
def create_cryst_line(pdbin, pdbout, sg, cell): """Adds a cryst line to pdbin""" if not pdbout.endswith('.pdb'): pdbout = pdbout + '.pdb' if not os.path.exists(pdbin): raise IOError('pdbin does not exist! {!s}'.format(pdbin)) if os.path.exists(pdbout): raise Exception('pdbout already exists! {!s}'.format(pdbout)) # Initialise Commander PDBSET = CommandManager('pdbset') # Set Command Arguments PDBSET.add_command_line_arguments('XYZIN', os.path.abspath(pdbin), 'XYZOUT', os.path.abspath(pdbout)) # Set Stdin PDBSET.add_standard_input([ 'SPACEGROUP {!s}'.format(sg), 'CELL {!s}'.format(' '.join(map(str, cell))) ]) # run! PDBSET.run() if not os.path.exists(pdbout): raise ExternalProgramError( 'PDBSET has failed to create cryst line for {!s}\nOUT: {!s}\nERR: {!s}' .format(pdbin, PDBSET.out, PDBSET.err)) return PDBSET
def create_alpha_carbon_backbone(pdbin, pdbout): """Takes a pdb files and removes eveything except for the alpha carbons""" if not pdbout.endswith('.pdb'): pdbout = pdbout + '.pdb' if not os.path.exists(pdbin): raise IOError('pdbin does not exist! {!s}'.format(pdbin)) if os.path.exists(pdbout): raise Exception('pdbout already exists! {!s}'.format(pdbout)) # Initialise Commander PDBCUR = CommandManager('pdbcur') # Set Command Arguments PDBCUR.add_command_line_arguments('XYZIN', pdbin, 'XYZOUT', pdbout) # Set inputs PDBCUR.add_standard_input(['lvatom "CA[C]:*"', 'END']) # run! PDBCUR.run() if not os.path.exists(pdbout): raise ExternalProgramError( 'PDBCUR has failed to create carbon backbone. {!s}\nOUT: {!s}\nERR: {!s}' .format(pdbin, PDBCUR.out, PDBCUR.err)) return pdbout
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 extract_bfactor_statistics(pdb_file): """Analyse the b-factors in a pdb file and return a dictionary with all of the averages, rms deviations and Z-scores for the b-factors in a structure""" # Create a temporary file for the output summary table and pdb_file temp_handle, temp_path = tempfile.mkstemp(suffix='.table', prefix='baverage_') temp_handle2, temp_path2 = tempfile.mkstemp(suffix='.pdb', prefix='baverage_') BAVERAGE = CommandManager('baverage') BAVERAGE.add_command_line_arguments('XYZIN', pdb_file, 'RMSTAB', temp_path, 'XYZOUT', temp_path2) BAVERAGE.add_standard_input(['END']) BAVERAGE.run() if not os.path.exists(temp_path): raise ExternalProgramError( 'BAVERAGE has failed to calculate b-factor summary statistics for {!s}' .format(pdb_file)) # Process Table and Standard Out table_contents = open(temp_path, 'r').read().split('\n') if not table_contents: raise ExternalProgramError( 'BAVERAGE has failed to calculate b-factor summary statistics for {!s}' .format(pdb_file)) else: os.remove(temp_path) os.remove(temp_path2) return BAVERAGE, table_contents
def run_xia2(img_dir, out_dir, method='dials', verbose=True): """Run xia2 on the images in img_dir, and put the results in out_dir""" assert method in ['2d','3d','3dii','dials'], 'Invalid method provided' assert os.path.exists(img_dir), 'Image directory does not exist' if not os.path.exists(out_dir): os.mkdir(out_dir) # Convert to absolute path to allow folder changing img_dir = os.path.abspath(img_dir) out_dir = os.path.abspath(out_dir) # Store current directory cur_dir = os.getcwd() try: # Output logfile xia2_log = os.path.join(out_dir, 'xia2.log') # Got to directory to run MLFSOM os.chdir(out_dir) xia2 = CommandManager('xia2') xia2.add_command_line_arguments('-'+method, img_dir) if verbose: print('Running xia2 on {}').format(img_dir) rc = xia2.run() if rc != 0: print('STDOUT:') print(xia2.output) print('STDERR:') print(xia2.error) with open(xia2_log, 'a') as fh: fh.write('==================================================>\n') fh.write('xia2 log\n') fh.write('==================================================>\n') fh.write(xia2.output+'\n') fh.write('==================================================>\n') fh.write('xia2 errors\n') fh.write('==================================================>\n') fh.write(xia2.error+'\n') fh.write('==================================================>\n') finally: # Change back to original directory os.chdir(cur_dir) return xia2
def isolate_residue(inpdb, outpdb, resname): """Extract the residues identified by resname using pdbcur - i.e. 'UNL'""" PDBCUR = CommandManager('pdbcur') PDBCUR.add_command_line_arguments('XYZIN', inpdb, 'XYZOUT', outpdb) PDBCUR.add_standard_input(['lvresidue /*/*/({!s})'.format(resname), 'END']) PDBCUR.run() return PDBCUR
def __init__(self, pdb_file, mtz_file=None, cif_file=None, out_prefix=None, **kw_args): # Set defaults if not given if mtz_file is None: mtz_file = pdb_file.replace('.pdb', '.mtz') if out_prefix is None: out_prefix = os.path.splitext(pdb_file)[0] + '-refined' # Main files self.pdb_file = pdb_file self.mtz_file = mtz_file self.cif_file = cif_file # Eventual output prefix self.out_prefix = out_prefix self.out_pdb_file = self.out_prefix + '.pdb' self.out_mtz_file = self.out_prefix + '.mtz' self.out_log_file = self.out_prefix + '.log' # Validate input assert os.path.exists(self.pdb_file) assert os.path.exists(self.mtz_file) assert not os.path.exists( self.out_pdb_file), 'Output file already exists: {}'.format( self.out_pdb_file) assert not os.path.exists( self.out_mtz_file), 'Output file already exists: {}'.format( self.out_mtz_file) # Create temporary folder for refinement self.tmp_dir = tempfile.mkdtemp(prefix='refine-model-') self.tmp_pre = os.path.join(self.tmp_dir, 'refine') # Command object for refinement self.cmd = CommandManager(self.program) self.kw_args = kw_args # Setup, refine and post_process if self.auto is True: self.run()
def phenix_find_tls_groups(pdb_file): cmd = CommandManager('phenix.find_tls_groups') cmd.add_command_line_arguments(pdb_file) #cmd.print_settings() ret_code = cmd.run() if ret_code != 0: print cmd.output print cmd.error raise Exception('Failed to determine TLS groups: {}'.format(' '.join( cmd.program))) regex = re.compile("refinement\.refine\.adp \{([\s\S]*?)\}") tls_command = regex.findall(cmd.output)[0] tls_selections = [ s.strip() for s in tls_command.split('tls =') if s.strip() ] return tls_selections
def convert_intensities_to_amplitudes(mtzin, mtzout): """Takes an input mtz and converts the intensities to structure factors for model building""" mtzobj = MtzSummary(mtzin) # Copy data columns from new mtz file I, SIGI = mtzobj.label.i, mtzobj.label.sigi if not (I and SIGI): raise LabelError('No Intensities found in {!s}'.format(mtzin)) # TODO If rfree is present, retain rfree from the reference mtz # RFree = mtzobj.label.free # Initialise Commander CTRUNC = CommandManager('ctruncate') # Set command arguments CTRUNC.add_command_line_arguments('-mtzin', mtzin, '-mtzout', mtzout, '-colin', '/*/*/[{!s},{!s}]'.format(I, SIGI)) # Run! CTRUNC.run() if not os.path.exists(mtzout): raise ExternalProgramError( 'CTRUNCATE has failed to convert intensities to SFs. {!s}\nOUT: {!s}\nERR: {!s}' .format(mtzin, CTRUNC.out, CTRUNC.err)) return CTRUNC
def map_to_reference_using_symmetry(refpdb, movpdb, pdbout, conrad=5): """Transforms `movpdb` to the closest symmetry site to `refpdb` using csymmatch - Symmetry info must be contained in the header of the pdb file""" if not pdbout.endswith('.pdb'): pdbout = pdbout + '.pdb' if not os.path.exists(refpdb): raise IOError('refpdb does not exist! {!s}'.format(refpdb)) if not os.path.exists(movpdb): raise IOError('movpdb does not exist! {!s}'.format(movpdb)) if os.path.exists(pdbout): raise Exception('pdbout already exists! {!s}'.format(pdbout)) # Initialise Commander CSYMMATCH = CommandManager('csymmatch') # Set Command Arguments CSYMMATCH.add_command_line_arguments('-pdbin-ref', os.path.abspath(refpdb), '-pdbin', os.path.abspath(movpdb), '-pdbout', os.path.abspath(pdbout), '-connectivity-radius', str(conrad)) # run! CSYMMATCH.run() if not os.path.exists(pdbout): raise ExternalProgramError( 'CSYMMATCH has failed to map {!s} to {!s}.\nERR: {!s}'.format( movpdb, refpdb, CSYMMATCH.err)) return pdbout
def merge_pdb_files(pdb1, pdb2, pdbout): """Merge two PDB Files using CCP4s pdb_merge""" # Initialise Commander MERGER = CommandManager('pdb_merge') # Set command arguments MERGER.add_command_line_arguments('xyzin1', pdb1, 'xyzin2', pdb2, 'xyzout', pdbout) # Set inputs MERGER.add_standard_input('END') # run! MERGER.run() return MERGER
def run(cls, script): assert script.endswith(cls._file_type) c = CommandManager('pymol') c.add_command_line_arguments([ '-k', '-q', '-c', '-Q', '-s', script[:-len(cls._file_type)] + '.log', '-r', script ]) c.run() return c
def mask_map(mapin, maskpdb, mapout, border=1): """Takes mapin and masks around atoms in maskpdb""" # Masking object masker = CommandManager('mapmask') # Set input files masker.add_command_line_arguments( ['mapin', mapin, 'mapout', mapout, 'xyzin', maskpdb]) # Set stdin masker.add_standard_input(['BORDER {!s}'.format(border), 'END']) # Run! masker.run() # Report errors if masker.process.returncode != 0: raise RuntimeError('mapmask failed to mask map {!s}'.format(mapin)) # Return Command Managers for flexible handling of out & err return masker
def create_asu_map(mapin, mapout): """Takes mapin and masks to the asymmetric unit""" # Masking object masker = CommandManager('mapmask') # Set input files masker.add_command_line_arguments(['mapin', mapin, 'mapout', mapout]) # Set stdin masker.add_standard_input(['XYZLIM ASU', 'END']) # Run! masker.run() # Report errors if masker.process.returncode != 0: raise RuntimeError( 'mapmask failed to create asu map from {!s}'.format(mapin)) # Return Command Managers for flexible handling of out & err return masker
def fft_mtz_to_map(mtz_file, map_file, cols): """Converts an MTZ Format File to a MAP File (using fft as default)""" # Initialise writer = CommandManager('fft') # Set Program Arguments writer.add_command_line_arguments('hklin', mtz_file, 'mapout', map_file) # Set Program Input writer.add_standard_input( ['LABIN F1={!s} PHI={!s}'.format(cols['F'], cols['P']), 'END']) # RUN! writer.run() # Check Output if writer.process.returncode != 0: print('\nOUT\n\n' + writer.out) print('\nERR\n\n' + writer.err) raise RuntimeError( 'fft failed to generate map from {!s}'.format(mtz_file)) return writer
def isolate_residue_by_res_id(inpdb, outpdb, chain, resnum, model='*', inscode=''): """Isolate the residues identified by residue ids using pdbcur - i.e. '0/A/54.A/'""" if inscode: selection = '/{!s}/{!s}/{!s}.{!s}'.format(model, chain, resnum, inscode) else: selection = '/{!s}/{!s}/{!s}'.format(model, chain, resnum) PDBCUR = CommandManager('pdbcur') PDBCUR.add_command_line_arguments('XYZIN', inpdb, 'XYZOUT', outpdb) PDBCUR.add_standard_input(['lvresidue {!s}'.format(selection), 'END']) PDBCUR.run() return PDBCUR
def reindex_mtz_to_reference(in_mtz, out_mtz, reference_mtz, tolerance): """Reindex the data in one mtz to a reference mtz""" print '**************************' print '*** Running reindexing ***' print '**************************' cmd = CommandManager('pointless') cmd.add_command_line_arguments( ['hklin', in_mtz, 'hklref', reference_mtz, 'hklout', out_mtz]) cmd.add_standard_input(['tolerance {}'.format(tolerance)]) print_run_and_raise_error_maybe(cmd) if not os.path.exists(out_mtz): raise Failure( 'reindexing has failed -- {} does not exist'.format(out_mtz))
def remove_residue_by_res_id(inpdb, outpdb, chain, resnum, model='*', inscode='', removeSolvent=False): """Remove the residues identified by res info using pdbcur - i.e. 'UNL'""" if inscode: selection = '/{!s}/{!s}/{!s}.{!s}'.format(model, chain, resnum, inscode) else: selection = '/{!s}/{!s}/{!s}'.format(model, chain, resnum) std_input = ['delresidue {!s}'.format(selection) ] + (removeSolvent) * ['delsolvent'] + ['END'] PDBCUR = CommandManager('pdbcur') PDBCUR.add_command_line_arguments('XYZIN', inpdb, 'XYZOUT', outpdb) PDBCUR.add_standard_input(std_input) PDBCUR.run() return PDBCUR
def run_coot(script, graphical=False, noguano=True): """Runs coot with the provided script""" # Check that the script is valid (e.g. causes coot to exit at the end) validate_coot_script(script) # Stop coot droppings? coot_flags = ['--no-guano']*(noguano) # Run with/without graphics? if graphical: coot_flags.extend(['-script',script]) else: coot_flags.extend(['--no-graphics','-s',script]) # Initialise COOT = CommandManager('coot') # Load arguments COOT.add_command_line_arguments(*coot_flags) # Run! COOT.run() return COOT
def get_mtz_resolution(mtz_file): """Gets the max resolution from the file""" # Extract Contents of MTZ MTZDMP = CommandManager('mtzdmp') MTZDMP.add_command_line_arguments(mtz_file) MTZDMP.run() # Check for errors if MTZDMP.process.returncode != 0: raise RuntimeError( 'mtzdmp failed to read file {!s}:\nReturn: {!s}\nOut: {!s}'.format( mtz_file, MTZDMP.process.returncode, MTZDMP.output)) # Search for the Column Headings regex = re.compile('\* Resolution Range :.*\n.*\n.*\((.*)A \)\n') matches = regex.findall(MTZDMP.output) # Check for validity of matches assert matches, 'No Resolution Range found in MTZFile {!s}'.format( mtz_file) assert len( matches ) == 1, 'Too many matching lines found for Column Headings in MTZFile {!s}\n\t{!s}'.format( mtz_file, matches) # Return return map(float, matches[0].replace(' ', '').split('-'))
def merge_cif_libraries(incifs, outcif): """Take a list of cifs and merge into one cif""" assert isinstance(incifs, list), "'incifs' is not a list!" assert len(incifs) > 1, "'incifs' must be two or more files!" current = incifs.pop(0) to_be_deleted = [] for additional in incifs: # Create a file handle and path for the output temp_handle, temp_path = tempfile.mkstemp(suffix='.lib', prefix='libcheck_') to_be_deleted.append(temp_path) # Merge current and additional to temp_path LIBCHK = CommandManager('libcheck') LIBCHK.add_standard_input( '_DOC N', '_FILE_L {!s}'.format(current), '_FILE_L2 {!s}'.format(additional), '_FILE_O {!s}'.format(temp_path.replace('.lib', '')), '_END') LIBCHK.run() current = temp_path shutil.copy(current, outcif) for file in to_be_deleted: os.remove(file) assert os.path.exists(outcif), 'OUTPUT CIF DOES NOT EXIST! {!s}'.format( outcif) return outcif
def run_mlfsom(pdb_file, res_h, out_dir='mlfsom_out', n_images=180, osc=1.0, energy=12660, verbose=True): """Run MLFSOM on the given file.""" ftd_pre = ['1H87.pdb', 'example.com', 'example.mat', 'mlfsom.log', 'refined.pdb', 'pristine.mtz'] assert not os.path.exists(out_dir), 'output directory already exists!' assert os.path.exists(pdb_file) assert isinstance(n_images, int) # Store current directory cur_dir = os.getcwd() try: # Create a temporary directory for mlfsom to run in (and go to it) tmp_dir = tempfile.mkdtemp(prefix='mlfsom_') mlfsom_pdb = os.path.join(tmp_dir, 'refined.pdb') mlfsom_mtz = os.path.join(tmp_dir, 'pristine.mtz') mlfsom_log = os.path.join(tmp_dir, 'mlfsom.log') mlfsom_img = 'image_###.img' # Get the mlfsom tarball and move it to the temporary directory mlfsom_file = os.path.join(bamboo.resources.__path__[0], 'mlfsom.tar.gz') assert os.path.exists(mlfsom_file), 'MLFSOM tarball not found' shutil.copy(mlfsom_file, tmp_dir) mlfsom_file = os.path.join(tmp_dir, 'mlfsom.tar.gz') assert os.path.exists(mlfsom_file), 'MLFSOM tarball not in temporary directory' # Untar the file t = tarfile.open(mlfsom_file, 'r:gz') try: t.extractall(tmp_dir) finally: t.close() # Delete unnecessary files for f in ftd_pre: fp = os.path.join(tmp_dir, f) if os.path.exists(fp): os.remove(fp) # Move the input files in shutil.copy(pdb_file, mlfsom_pdb) # Got to directory to run MLFSOM os.chdir(tmp_dir) # Convert the pdb_file to structure factors ano_sfall = CommandManager('./ano_sfall.com') ano_sfall.add_command_line_arguments(os.path.basename(mlfsom_pdb)) ano_sfall.add_command_line_arguments('energy={}'.format(energy)) ano_sfall.add_command_line_arguments('{}A'.format(res_h)) if verbose: print('Running ./ano_sfall.com on {}').format(pdb_file) rc = ano_sfall.run() if rc != 0: print('STDOUT:') print(ano_sfall.output) print('STDERR:') print(ano_sfall.error) shutil.move('ideal_ano.mtz', mlfsom_mtz) with open(mlfsom_log, 'a') as fh: fh.write('==================================================>\n') fh.write('ano_sfall log\n') fh.write('==================================================>\n') fh.write(ano_sfall.output+'\n') fh.write('==================================================>\n') fh.write('ano_sfall errors\n') fh.write('==================================================>\n') fh.write(ano_sfall.error+'\n') fh.write('==================================================>\n') # Run MLFSOM on the resulting mtzfile mlfsom = CommandManager('./mlfsom.com') mlfsom.add_command_line_arguments(mlfsom_img) mlfsom.add_command_line_arguments('frames={}'.format(n_images)) mlfsom.add_command_line_arguments('osc={}'.format(osc)) if verbose: print('Running ./mlfsom.com on {}. This may take a while...').format(pdb_file) rc = mlfsom.run() if rc != 0: print('STDOUT:') print(mlfsom.output) print('STDERR:') print(mlfsom.error) with open(mlfsom_log, 'a') as fh: fh.write('==================================================>\n') fh.write('mlfsom log\n') fh.write('==================================================>\n') fh.write(mlfsom.output+'\n') fh.write('==================================================>\n') fh.write('mlfsom errors\n') fh.write('==================================================>\n') fh.write(mlfsom.error+'\n') fh.write('==================================================>\n') finally: # Change back to original directory os.chdir(cur_dir) # Delete temporary directory shutil.move(tmp_dir, out_dir) return ano_sfall, mlfsom
class BuilderObject(object): """Template Object for creating an Object to generate ligand restraints""" def __init__(self, time=True, verbose=True): self.allowed_args = allowed_builder_args self.ligname = DEFAULT_LIGAND_NAMES[0] # Settings self.time = time self.verbose = verbose self.runtime = -1.0 self.timeout = 1800 # Custom Init self._custom_init() def generate_ligand(self, ligsmile, outdir, outfile, flags=[]): """Generate ligand PDB and CIF from smile string""" # Prepare standard settings self._prepare_to_generate_ligand(ligsmile, 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.outcif) and os.path.exists(self.outlog): if self.verbose: print('\tLigand already generated - DOING NOTHING') else: cmd_line_args, std_inpt_args = self._create_program_arguments( ligsmile, outdir, outfile, flags) # Initialise CommandManager self.builder = CommandManager(self.program) # Set Command-Line Args if cmd_line_args: self.builder.add_command_line_arguments(cmd_line_args) # Set Standard Input if std_inpt_args: self.builder.add_standard_input(std_inpt_args) # Set Parameters self.builder.set_timeout(timeout=self.timeout) # RUN self.builder.run() # Get runtime self.runtime = self.builder.runtime try: # Could add postprocess here pass finally: self.write_log_file() return self.outpdb, self.outcif, self.outlog def _prepare_to_generate_ligand(self, ligsmile, 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 + '.pdb' self.outcif = self.outtemplate + '.cif' self.outlog = self.outtemplate + '.log' def write_log_file(self): """Write the log file""" with open(self.outlog, 'w') as logfile: # Write out the input command logfile.write('\nCOMMAND\n\n') logfile.write('\n'.join(self.builder.cmd_line_args) + '\n') logfile.write('\nINPUT\n\n') logfile.write('\n'.join(self.builder.std_inp_lines) + '\n') # Write out & err logfile.write('\nSTDOUT\n\n') logfile.write(self.builder.output) logfile.write('\nSTDERR\n\n') logfile.write(self.builder.error)
class _refiner(object): program = None auto = True def __init__(self, pdb_file, mtz_file=None, cif_file=None, out_prefix=None, **kw_args): # Set defaults if not given if mtz_file is None: mtz_file = pdb_file.replace('.pdb', '.mtz') if out_prefix is None: out_prefix = os.path.splitext(pdb_file)[0] + '-refined' # Main files self.pdb_file = pdb_file self.mtz_file = mtz_file self.cif_file = cif_file # Eventual output prefix self.out_prefix = out_prefix self.out_pdb_file = self.out_prefix + '.pdb' self.out_mtz_file = self.out_prefix + '.mtz' self.out_log_file = self.out_prefix + '.log' # Validate input assert os.path.exists(self.pdb_file) assert os.path.exists(self.mtz_file) assert not os.path.exists( self.out_pdb_file), 'Output file already exists: {}'.format( self.out_pdb_file) assert not os.path.exists( self.out_mtz_file), 'Output file already exists: {}'.format( self.out_mtz_file) # Create temporary folder for refinement self.tmp_dir = tempfile.mkdtemp(prefix='refine-model-') self.tmp_pre = os.path.join(self.tmp_dir, 'refine') # Command object for refinement self.cmd = CommandManager(self.program) self.kw_args = kw_args # Setup, refine and post_process if self.auto is True: self.run() def run(self): """...run refinement amd export files""" self.setup() ret = self.refine() self.export() return ret def setup(self): raise Exception('Dummy class -- not implemented') def refine(self): """...run the refinement""" self.cmd.print_settings() return self.cmd.run() def export(self): """Copy files to output destination""" # Find pdb file in the output folder tmp_pdb = glob.glob(self.tmp_pre + '*.pdb') assert tmp_pdb, 'No refined files found: {}'.format(self.tmp_dir) tmp_pdb = tmp_pdb[0] tmp_mtz = tmp_pdb.replace('.pdb', '.mtz') assert os.path.exists(tmp_pdb) assert os.path.exists(tmp_mtz) # Copy to output folder shutil.copy(tmp_pdb, self.out_pdb_file) shutil.copy(tmp_mtz, self.out_mtz_file) assert os.path.exists(self.out_pdb_file) assert os.path.exists(self.out_mtz_file) # Write the log to the output log file self.cmd.write_output(self.out_log_file) # Delete temporary directory shutil.rmtree(self.tmp_dir)
def run(params): # Identify any existing output directories current_dirs = sorted(glob.glob(params.output.dir_prefix + '*')) if not current_dirs: next_int = 1 else: current_nums = [ s.replace(params.output.dir_prefix, '') for s in current_dirs ] next_int = sorted(map(int, current_nums))[-1] + 1 # Create output directory name from int out_dir = params.output.dir_prefix + '{:04}'.format(next_int) # Create output directory os.mkdir(out_dir) # Create log object log = Log(log_file=os.path.join( out_dir, params.output.out_prefix + '.quick-refine.log'), verbose=params.settings.verbose) # Report if current_dirs: log('Found existing refinement directories: \n\t{}'.format( '\n\t'.join(current_dirs))) log('') log('Creating new output directory: {}'.format(out_dir)) # Validate input parameters log.subheading('Validating input parameters') assert params.input.pdb is not None, 'No PDB given for refinement' assert params.input.mtz is not None, 'No MTZ given for refinement' if os.path.islink(params.input.mtz): log('Converting mtz path to real path:') log('{} -> {}'.format(params.input.mtz, os.path.realpath(params.input.mtz))) params.input.mtz = os.path.realpath(params.input.mtz) # Link input log('Copying/linking files to refinement folder') shutil.copy(params.input.pdb, os.path.abspath(os.path.join(out_dir, 'input.pdb'))) rel_symlink(params.input.mtz, os.path.abspath(os.path.join(out_dir, 'input.mtz'))) # Copy parameter file to output folder if params.input.params: shutil.copy(params.input.params, os.path.abspath(os.path.join(out_dir, 'input.params'))) # Create output prefixes output_prefix = os.path.join(out_dir, params.output.out_prefix) log('Real output file path prefixes: {}'.format(output_prefix)) log('Link output file path prefixes: {}'.format(params.output.link_prefix)) # Create command objects log.subheading('Preparing command line input for refinement program') # PHENIX if params.options.program == 'phenix': cm = CommandManager('phenix.refine') # Command line args cm.add_command_line_arguments([params.input.pdb, params.input.mtz]) cm.add_command_line_arguments( ['output.prefix={}'.format(output_prefix)]) if params.input.cif: cm.add_command_line_arguments(params.input.cif) if params.input.params and os.path.exists(params.input.params): cm.add_command_line_arguments([params.input.params]) # REFMAC elif params.options.program == 'refmac': cm = CommandManager('refmac5') # Command line args cm.add_command_line_arguments( ['xyzin', params.input.pdb, 'hklin', params.input.mtz]) cm.add_command_line_arguments([ 'xyzout', output_prefix + '.pdb', 'hklout', output_prefix + '.mtz' ]) if params.input.cif: for cif in params.input.cif: cm.add_command_line_arguments(['libin', cif]) # Standard input if params.input.params: cm.add_standard_input(open(params.input.params).read().split('\n')) cm.add_standard_input(['END']) elif params.options.program == "buster": cm = CommandManager('refine') # Command line arguments # inputs cm.add_command_line_arguments( ['-p', params.input.pdb, '-m', params.input.mtz, '-d', out_dir]) if params.input.cif: for cif in params.input.cif: cm.add_command_line_arguments(['-l', cif]) if params.input.params: cm.add_command_line_arguments(['-Gelly', params.input.params]) # Pass additional command line arguments? if params.input.args: cm.add_command_line_arguments(params.input.args) # Report log(str(cm)) log.bar() log('running refinement... ({})'.format(cm.program[0])) out = cm.run() log.subheading('Refinement output') if not log.verbose: log('output written to log file ({} lines)'.format( cm.output.count('\n'))) log('\n' + cm.output, show=False) if out != 0: log.subheading('Refinement Errors') log(cm.error) log.subheading('Post-processing output files') if params.options.program == "buster": log.subheading('Renaming buster output files') shutil.move(src=os.path.join(out_dir, 'refine.pdb'), dst=output_prefix + '.pdb') shutil.move(src=os.path.join(out_dir, 'refine.mtz'), dst=output_prefix + '.mtz') # Find output files try: real_pdb = glob.glob(output_prefix + '*.pdb')[0] real_mtz = glob.glob(output_prefix + '*.mtz')[0] except: log('Refinement has failed - output files do not exist') log('{}: {}'.format(output_prefix + '*.pdb', glob.glob(output_prefix + '*.pdb'))) log('{}: {}'.format(output_prefix + '*.mtz', glob.glob(output_prefix + '*.mtz'))) raise # List of links to make at the end of the run link_file_pairs = [(real_pdb, params.output.link_prefix + '.pdb'), (real_mtz, params.output.link_prefix + '.mtz')] # Split conformations if params.options.split_conformations: params.split_conformations.settings.verbose = params.settings.verbose log.subheading('Splitting refined structure conformations') # Running split conformations out_files = split_conformations.split_conformations( filename=real_pdb, params=params.split_conformations, log=log) # Link output files to top for real_file in out_files: link_file = params.output.link_prefix + os.path.basename( real_file.replace(os.path.splitext(real_pdb)[0], '')) link_file_pairs.append([real_file, link_file]) # Link output files log.subheading('linking output files') for real_file, link_file in link_file_pairs: log('Linking {} -> {}'.format(link_file, real_file)) if not os.path.exists(real_file): log('file does not exist: {}'.format(real_file)) continue if os.path.exists(link_file) and os.path.islink(link_file): log('removing existing link: {}'.format(link_file)) os.unlink(link_file) if not os.path.exists(link_file): rel_symlink(real_file, link_file) log.heading('finished - refinement')
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
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