#!/usr/bin/env ccp4-python
import copy
import pickle
import glob
import logging
import os
import shutil
import sys
# Hack to make sure we can find the modules we need
if __name__ == "__main__":
root = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-2])
sys.path.insert(0, os.path.join(root, "scripts"))
from ample.util import ample_util
from ample.util import mrbump_cmd
from ample.util import printTable
# FS [15/11/2018] -> New MRBUMP structure allows direct imports, wait for release then replace
mrbumpd = os.path.join(os.environ['CCP4'], "share", "mrbump", "include", "parsers")
sys.path.insert(0, mrbumpd)
import parse_arpwarp
import parse_buccaneer
import parse_phaser
TOP_KEEP = 3 # How many of the top shelxe/phaser results to keep for the gui
MRBUMP_RUNTIME = 172800 # allow 48 hours for each mrbump job
REBUILD_MAX_PERMITTED_RESOLUTION = 4.0
SHELXE_MAX_PERMITTED_RESOLUTION = 3.0
# Values to determine when job has succeeded - required at module level this may be set by AMPLE from
# the command line
SUCCESS_PHASER_TFZ = 8.0
SUCCESS_PHASER_LLG = 120
SUCCESS_RFREE = 0.4
SUCCESS_SHELXE_CC = 25.0
SUCCESS_SHELXE_ACL = 10
# We need a null logger so that we can be used without requiring a logger
[docs]class NullHandler(logging.Handler):
[docs] def emit(self, record):
pass
logger = logging.getLogger(__name__)
logger.addHandler(NullHandler())
[docs]class ResultsSummary(object):
"""
Summarise the results for a series of MRBUMP runs
"""
def __init__(self, results=None, results_pkl=None):
"""
Parameters
----------
results_pkl : file
A pickled AMPLE results dictionary
"""
self.results = []
self.pname = "archive"
self.pdir = None
self.success = False
if results_pkl and os.path.isfile(results_pkl):
with open(results_pkl) as f:
resd = pickle.load(f)
mkey = 'mrbump_results'
if mkey in resd and len(resd[mkey]):
self.results = resd[mkey]
elif results:
self.results = results
return
[docs] def analyseResult(self, result):
mrDir = result["MR_directory"]
# result.ensembleName = result.name[9:-6]
if result["MR_program"] == "PHASER":
if result["PHASER_pdbout"]:
phaserP = parse_phaser.PhaserPdbParser(result["PHASER_pdbout"])
result["PHASER_LLG"] = phaserP.LLG
result["PHASER_TFZ"] = phaserP.TFZ
phaserLog = os.path.join(mrDir, "{0}_loc0_ALL_{1}_UNMOD.log".format(result["MR_program"].lower(), result['ensemble_name']))
if os.path.isfile(phaserLog):
phaserP = parse_phaser.PhaserLogParser(phaserLog, noLLG=True)
# result.phaserLog = phaserLog
result["PHASER_time"] = phaserP.time
result["PHASER_killed"] = phaserP.killed
buccaneerLog = os.path.join(mrDir,
"build/shelxe/rebuild/buccaneer",
"buccaneer.log")
bp = parse_buccaneer.BuccaneerLogParser()
if os.path.isfile(buccaneerLog):
bp.parse(buccaneerLog)
result["SXRBUCC_final_Rfree"] = bp.finalRfree
result["SXRBUCC_final_Rfact"] = bp.finalRfact
arpLog = os.path.join(mrDir,
"build/shelxe/rebuild/arpwarp",
"arpwarp.log")
if os.path.isfile(arpLog):
ap = parse_arpwarp.ArpwarpLogParser()
ap.parse(arpLog)
result["SXRARP_final_Rfact"] = ap.finalRfact
result["SXRARP_final_Rfree"] = ap.finalRfree
return
[docs] def createDict(self):
d = {}
# our additional keys
d['ensemble_name'] = None
d['MR_program'] = None
d['name'] = None
d['Search_directory'] = None
d['MR_directory'] = None
d['Solution_Type'] = None
d['PHASER_LLG'] = None
d['PHASER_TFZ'] = None
d['PHASER_RFZ'] = None
d['PHASER_time'] = None
d['PHASER_killed'] = None
d['PHASER_pdbout'] = None
d['PHASER_mtzout'] = None
d['PHASER_logfile'] = None
d['PHASER_version'] = None
d['PHASER_error'] = None
d['MOLREP_score'] = None
d['MOLREP_time'] = None
d['MOLREP_pdbout'] = None
d['MOLREP_logfile'] = None
d['MOLREP_version'] = None
d['REFMAC_Rfact'] = None
d['REFMAC_Rfree'] = None
d['REFMAC_pdbout'] = None
d['REFMAC_mtzout'] = None
d['REFMAC_logfile'] = None
d['REFMAC_version'] = None
d['BUCC_final_Rfact'] = None
d['BUCC_final_Rfree'] = None
d['BUCC_pdbout'] = None
d['BUCC_mtzout'] = None
d['BUCC_logfile'] = None
d['BUCC_version'] = None
d['ARP_final_Rfact'] = None
d['ARP_final_Rfree'] = None
d['ARP_pdbout'] = None
d['ARP_mtzout'] = None
d['ARP_logfile'] = None
d['ARP_version'] = None
d['SHELXE_CC'] = None
d['SHELXE_ACL'] = None
d['SHELXE_MCL'] = None
d['SHELXE_NC'] = None
d['SHELXE_wMPE'] = None
d['SHELXE_os'] = None
d['SHELXE_time'] = None
d['SHELXE_pdbout'] = None
d['SHELXE_phsout'] = None
d['SHELXE_mtzout'] = None
d['SHELXE_logfile'] = None
d['SHELXE_version'] = None
d['SXRBUCC_version'] = None
d['SXRBUCC_final_Rfact'] = None
d['SXRBUCC_final_Rfree'] = None
d['SXRBUCC_pdbout'] = None
d['SXRBUCC_mtzout'] = None
d['SXRBUCC_logfile'] = None
d['SXRARP_version'] = None
d['SXRARP_final_Rfact'] = None
d['SXRARP_final_Rfree'] = None
d['SXRARP_pdbout'] = None
d['SXRARP_mtzout'] = None
d['SXRARP_logfile'] = None
return d
def _extractPurged(self, mrbump_dir):
"""Recreate a list of the jobs that have been purged"""
purged_results = {}
self.pdir = os.path.join(mrbump_dir, self.pname)
if not os.path.isdir(self.pdir):
os.mkdir(self.pdir)
pkls = glob.glob(os.path.join(self.pdir, "*.pkl"))
if pkls:
for p in pkls:
with open(p) as f:
d = pickle.load(f)
purged_results[d['ensemble_name']] = d
return purged_results
def _extractResults(self, mrbump_dir, archived_ensembles=None):
"""
Find the results from running MRBUMP and sort them
"""
mrbump_dir = os.path.abspath(mrbump_dir)
if not os.path.isdir(mrbump_dir):
logger.warn("extractResults - is not a valid directory: {0}".format(mrbump_dir))
return []
# Get a list of the ensembles (could get this from the amopt dictionary)
# For now we just use the submission scripts and assume all have .sh or .sub extension
ext = '.sh'
if sys.platform.startswith("win"):
ext = '.bat'
ensembles = [ os.path.splitext(os.path.basename(e))[0] for e in glob.glob(os.path.join(mrbump_dir, "*" + ext))]
if not len(ensembles):
# legacy - try .sub
ensembles = [ os.path.splitext(os.path.basename(e))[0] for e in glob.glob(os.path.join(mrbump_dir, "*.sub"))]
if not len(ensembles):
logger.warn("Could not extract any results from directory: {0}".format(mrbump_dir))
return []
# reset any results
results = []
failed = {} # dict mapping failures to what went wrong - need to process at the end
for ensemble in ensembles:
# Skip ones that we've archived
if archived_ensembles and ensemble in archived_ensembles:
continue
# Check job directory
jobDir = os.path.join(mrbump_dir, 'search_' + ensemble + '_mrbump')
if not os.path.isdir(jobDir):
jobDir = os.path.join( mrbump_dir, 'search_'+ensemble )
if not os.path.isdir(jobDir):
# As we call this every time we monitor a job running, we don't want to print this out all the time
# logger.debug("Missing job directory: {0}".format(jobDir))
failed[ensemble] = "no_job_directory"
continue
logger.debug(" -- checking directory for results: {0}".format(jobDir))
# Check if finished
if not os.path.exists(os.path.join(jobDir, "results", "finished.txt")):
logger.debug("Found unfinished job: {0}".format(jobDir))
failed[ensemble] = "unfinished"
continue
# Check resultsTable.dat
resultsDict = os.path.join(jobDir, "results", "resultsTable.pkl")
if os.path.isfile(resultsDict):
results += self.processMrbumpPkl(resultsDict)
else:
logger.debug(" -- Could not find results files: {0}".format(resultsDict))
failed[ensemble] = "missing-results-file"
continue
# Process the failed results
if failed:
results += self._processFailed(mrbump_dir, failed)
if not len(results):
logger.warn("Could not extract any results from directory: {0}".format(mrbump_dir))
self.results = results
return
[docs] @staticmethod
def jobSucceeded(job_dict):
success = False
if 'SHELXE_CC' in job_dict and job_dict['SHELXE_CC'] and float(job_dict['SHELXE_CC']) >= SUCCESS_SHELXE_CC and \
'SHELXE_ACL' in job_dict and job_dict['SHELXE_ACL'] and float(job_dict['SHELXE_ACL']) >= SUCCESS_SHELXE_ACL:
success = True
elif 'BUCC_final_Rfree' in job_dict and job_dict['BUCC_final_Rfree'] and float(job_dict['BUCC_final_Rfree']) <= SUCCESS_RFREE:
success = True
elif 'ARP_final_Rfree' in job_dict and job_dict['ARP_final_Rfree'] and float(job_dict['ARP_final_Rfree']) <= SUCCESS_RFREE:
success = True
elif 'REFMAC_Rfree' in job_dict and job_dict['REFMAC_Rfree'] and float(job_dict['REFMAC_Rfree']) <= SUCCESS_RFREE:
success = True
elif 'PHASER_LLG' in job_dict and 'PHASER_TFZ' in job_dict and job_dict['PHASER_LLG'] and job_dict['PHASER_TFZ'] and \
float(job_dict['PHASER_LLG']) >= SUCCESS_PHASER_LLG and float(job_dict['PHASER_TFZ']) >= SUCCESS_PHASER_TFZ:
success = True
return success
[docs] def processMrbumpPkl(self, resultsPkl):
"""Process dictionary
"""
with open(resultsPkl) as f:
rD = pickle.load(f)
if not rD:
return []
results = []
for name, d1 in rD.iteritems():
for mrprog, d2 in d1.iteritems():
# Check if all the entries are None - means job didn't run.
# Should probably think of a better way to spot that (Search_directory is always set)
if not any([v for k, v in d2.iteritems() if k != 'Search_directory']):
continue
# Add MR program as dictionary entry
d = copy.copy(d2)
del d['SearchModel_filename']
d['name'] = name
# name is e.g.: loc0_ALL_c1_tl100_r2_allatom_UNMOD
d['ensemble_name'] = name[9:-6]
d['MR_program'] = mrprog
# Hack for old versions
if 'JobDirectory' in d:
d['MR_directory'] = d['JobDirectory']
del d['JobDirectory']
d['Search_directory'] = os.sep.join(d['MR_directory'].split(os.sep)[:-5])
if 'final_Rfree' in d:
d['REFMAC_Rfree'] = d['final_Rfree']
d['REFMAC_Rfact'] = d['final_Rfact']
del d['final_Rfree']
del d['final_Rfact']
results.append(d)
return results
def _processFailed(self, mrbump_dir, failed):
"""Generate dictionaries for failed results
"""
results = []
for ensemble, reason in failed.iteritems():
d = self.createDict()
# name hard-coded
# d['name'] = "loc0_ALL_" + ensemble + "_UNMOD"
d['name'] = "loc0_ALL_" + ensemble + "_UNMOD"
d['ensemble_name'] = ensemble
d['Search_directory'] = os.path.join(mrbump_dir, 'search_' + ensemble + '_mrbump')
d['Solution_Type'] = reason
results.append(d)
logger.debug("Added {0} MRBUMP result failures".format(len(failed)))
return results
def _purgeFailed(self):
"""Remove the MRBUMP directories of any jobs that don't pass the keep criteria and archive their job dictionaries"""
completed = [r for r in self.results if not(job_unfinished(r))]
if completed:
to_keep = []
min_len = min(len(completed), TOP_KEEP)
for r in ResultsSummary.sortResultsStatic(completed, prioritise='SHELXE_CC')[:min_len]:
if r not in to_keep:
to_keep.append(r)
for r in ResultsSummary.sortResultsStatic(completed, prioritise='PHASER_TFZ')[:min_len]:
if r not in to_keep:
to_keep.append(r)
for r in completed:
if r not in to_keep:
pkl = os.path.join(self.pdir, "{0}.pkl".format(r['ensemble_name']))
with open(pkl, 'w') as f:
pickle.dump(r, f)
shutil.rmtree(r['Search_directory'])
[docs] def results_table(self, results):
resultsTable = []
keys = ['ensemble_name', 'MR_program', 'Solution_Type']
keys += _resultsKeys(results)
resultsTable.append(keys)
for r in results:
resultsTable.append([r[k] for k in keys])
return resultsTable
[docs] def sortResults(self, prioritise=False):
"""Wrapper function to allow calls with self"""
self.results = ResultsSummary.sortResultsStatic(self.results)
[docs] @staticmethod
def sortResultsStatic(results, prioritise=False):
"""Sort the results"""
SHELXE = False
BUCC = False
ARP = False
REFMAC = False
PHASER = False
for r in results:
if 'SHELXE_CC' in r and r['SHELXE_CC'] and float(r['SHELXE_CC']) > 0.0:
SHELXE = True
if 'BUCC_final_Rfact' in r and r['BUCC_final_Rfact'] and float(r['BUCC_final_Rfact']) < 1.0:
BUCC = True
if 'ARP_final_Rfree' in r and r['ARP_final_Rfree'] and float(r['ARP_final_Rfree']) < 1.0:
ARP = True
if 'REFMAC_Rfree' in r and r['REFMAC_Rfree'] and float(r['REFMAC_Rfree']) < 1.0:
REFMAC = True
if 'PHASER_TFZ' in r and r['PHASER_TFZ'] and float(r['PHASER_TFZ']) > 0.0:
PHASER = True
reverse = False
sortf = False
if SHELXE and prioritise != "PHASER_TFZ":
reverse = True
sortf = lambda x: float(0) if x['SHELXE_CC'] is None else float(x['SHELXE_CC'])
elif BUCC and not prioritise == "PHASER_TFZ":
sortf = lambda x: float('inf') if x['BUCC_final_Rfact'] is None else float(x['BUCC_final_Rfact'])
elif ARP and not prioritise == "PHASER_TFZ":
sortf = lambda x: float('inf') if x['ARP_final_Rfree'] is None else float(x['ARP_final_Rfree'])
elif REFMAC and not prioritise == "PHASER_TFZ":
sortf = lambda x: float('inf') if x['REFMAC_Rfree'] is None else float(x['REFMAC_Rfree'])
elif PHASER:
reverse = True
sortf = lambda x: float(0) if x['PHASER_TFZ'] is None else float(x['PHASER_TFZ'])
if sortf:
results.sort(key=sortf, reverse=reverse)
return results
[docs] def summariseResults(self, mrbump_dir, max_loglevel=logging.INFO):
"""Return a string summarising the results"""
results = self.extractResults(mrbump_dir, max_loglevel=max_loglevel)
if len(results):
return self.summaryString()
else:
return "\n!!! No results found in directory: {0}\n".format(mrbump_dir)
[docs] def summaryString(self):
"""Return a string suitable for printing the sorted results"""
resultsTable = self.results_table(self.results)
# Format the results
table = printTable.Table()
summary = table.pprint_table(resultsTable)
r = "\n\nOverall Summary:\n\n"
r += summary
# Hack need to think of a better way to do this when there are no valid results
top = self.results[0]
k = None
for p in ['Search_directory','MR_directory']:
if p in top.keys():
k = p
assert k,"Missing search directory key in results dictionary"
if top[k]:
r += '\nBest Molecular Replacement results so far are in:\n\n'
r += top[k]
r += '\n\n'
return r
[docs] def topFiles(self, num_results=3):
"""Return a list of dictionaries listing the top num_results PDB and MTZ files
Parameters
----------
num_results : int
How many of the top results to return
Returns
-------
topf : list
A list of dictionaries, one per result, with xyz, mtz and info keys
"""
topf = []
# list of PDB, MTZ, Explanation of file type - ordered by their desirability
poss = [ ('SXRARP', 'SXRARP_pdbout','SXRARP_mtzout', 'ARPWARP rebuild of SHELXE trace of MR result'),
('SXRBUCC', 'SXRBUCC_pdbout','SXRBUCC_mtzout', 'BUCCANEER rebuild of SHELXE trace of MR result'),
('SHELXE', 'SHELXE_pdbout','SHELXE_mtzout', 'SHELXE trace of MR result'),
('ARP', 'ARP_pdbout','ARP_mtzout', 'ARPWARP rebuild of MR result'),
('BUCC', 'BUCC_pdbout','BUCC_mtzout', 'BUCCANEER rebuild of MR result'),
('REFMAC,', 'REFMAC_pdbout','REFMAC_mtzout', 'REFMAC-refined MR result') ]
for result in self.results[0 : min(num_results, len(self.results)+1) ]:
for stype, pdb_key, mtz_key, source in poss:
if pdb_key in result and result[pdb_key] and mtz_key in result and result[mtz_key]:
# Don't check paths for now as it screws up unittests as files don't actually exist
#if not (os.path.isfile(result[pdb_key]) and os.path.isfile(result[mtz_key])): continue
topf.append({ 'name' : result['ensemble_name'],
'type' : stype,
'info' : source,
'pdb' : result[pdb_key],
'mtz' : result[mtz_key] })
break # Stop as soon as we find one
if len(topf):
return topf
#
# Module functions
#
def _resultsKeys(results):
keys = []
# Build up list of keys we want to print based on what we find in the results
if any([True for r in results if r['PHASER_LLG']]):
keys += ['PHASER_LLG']
if any([True for r in results if r['PHASER_TFZ']]):
keys += ['PHASER_TFZ']
if any([True for r in results if r['REFMAC_Rfree'] and r['REFMAC_Rfree'] < 1.0]):
keys += ['REFMAC_Rfact', 'REFMAC_Rfree']
if any([True for r in results if r['BUCC_final_Rfact'] and r['BUCC_final_Rfact'] < 1.0]):
keys += ['BUCC_final_Rfact', 'BUCC_final_Rfree']
if any([True for r in results if r['ARP_final_Rfact'] and r['ARP_final_Rfact'] < 1.0]):
keys += ['ARP_final_Rfact', 'ARP_final_Rfree']
if any([True for r in results if r['SHELXE_CC']]):
keys += ['SHELXE_CC', 'SHELXE_ACL']
if any([True for r in results if r['SXRBUCC_final_Rfact']]):
keys += ['SXRBUCC_final_Rfact', 'SXRBUCC_final_Rfree']
if any([True for r in results if r['SXRARP_final_Rfact']]):
keys += ['SXRARP_final_Rfact', 'SXRARP_final_Rfree']
return keys
[docs]def checkSuccess(script_path):
"""Check if a job ran successfully.
Parameters
----------
script_path : str
Path to the MrBUMP script
Returns
-------
bool
True if success
Notes
-----
Success is assumed as a SHELX CC score of >= SHELXSUCCESS
"""
directory, script = os.path.split(script_path)
scriptname = os.path.splitext(script)[0]
rfile = os.path.join(directory, 'search_' + scriptname + '_mrbump', 'results', 'resultsTable.pkl')
if os.path.isfile(rfile):
results = ResultsSummary().processMrbumpPkl(rfile)
best = ResultsSummary.sortResultsStatic(results)[0]
return ResultsSummary.jobSucceeded(best)
else:
return False
[docs]def finalSummary(amoptd):
"""Print a final summary of the job"""
mrbump_data = amoptd['mrbump_results']
if not mrbump_data:
return "Could not find any MRBUMP results in directory: {0}!".format(amoptd['mrbump_dir'])
if 'ensembles_data' in amoptd and not (amoptd['ideal_helices'] or amoptd['homologs'] or amoptd['single_model_mode']):
results = []
# Merge dictionaries together
ensembles_data = amoptd['ensembles_data']
for mrb in mrbump_data:
d = copy.copy(mrb)
for ed in ensembles_data:
if ed['name'] == d['ensemble_name']:
d.update(ed)
results.append(d)
keys = ['ensemble_name', 'Solution_Type', 'MR_program']
keys += _resultsKeys(results)
keys += ['subcluster_num_models', 'num_residues']
else:
results = mrbump_data
keys = ['name', 'Solution_Type', 'MR_program']
keys += _resultsKeys(results)
resultsTable = []
resultsTable.append(keys)
for result in results:
resultLine = []
for k in keys:
resultLine.append(result[k])
resultsTable.append(resultLine)
# Format the results
table = printTable.Table()
summary = table.pprint_table(resultsTable)
r = "\n\nOverall Summary:\n\n"
r += summary
if len(results) and "MR_directory" in results[0]:
r += '\nBest Molecular Replacement results so far are in:\n\n'
r += str(results[0]["MR_directory"])
r += '\n\n'
return r
[docs]def job_unfinished(job_dict):
if not 'Solution_Type' in job_dict: return True
return job_dict['Solution_Type'] == "unfinished" or job_dict['Solution_Type'] == "no_job_directory"
[docs]def purge_MRBUMP(amoptd):
"""Remove as much as possible from a MRBUMP directory whilst keeping valid results"""
mkey = 'mrbump_dir'
if mkey not in amoptd or amoptd[mkey] is None:
return
mrbump_dir = amoptd[mkey]
suffixes = ['.pdb', '.mtz', '.log', '.sh', '.mrbump']
if os.path.isdir(mrbump_dir):
for f in os.listdir(mrbump_dir):
_, suffix = os.path.splitext(f)
if suffix in suffixes:
os.remove(os.path.join(mrbump_dir, f))
return
[docs]def set_success_criteria(amoptd):
"""Set the module-level success criteria from an AMPLE job dictionary"""
for criteria in ['SHELXE_CC', 'SHELXE_ACL']:
amopt_prefix = 'early_terminate_'
module_prefix = 'SUCCESS_'
amopt_key = amopt_prefix + criteria
if amopt_key in amoptd and amoptd[amopt_key] is not None:
module_criteria = module_prefix + criteria
logger.debug('Updating MRBUMP success criteria \'%s\' to: %s', module_criteria, amoptd[amopt_key])
globals()[module_criteria] = amoptd[amopt_key]
[docs]def unfinished_scripts(amoptd):
"""See if there are any unfinished mrbump jobs in a mrbump directory and return a list of the scripts"""
if not 'mrbump_dir' in amoptd or amoptd['mrbump_dir'] is None or not os.path.isdir(amoptd['mrbump_dir']): return []
amoptd['mrbump_results'] = ResultsSummary().extractResults(amoptd['mrbump_dir'])
if not len(amoptd['mrbump_results']): return []
scripts = []
for r in [ r for r in amoptd['mrbump_results'] if job_unfinished(r) ]:
scripts.append(os.path.join(amoptd['mrbump_dir'], r['ensemble_name']+ample_util.SCRIPT_EXT))
return scripts
[docs]def write_mrbump_files(ensemble_pdbs, amoptd, job_time=MRBUMP_RUNTIME, ensemble_options=None, directory=None):
"""Write the MRBUMP job files for all the ensembles.
Arguments:
ensemble_pdbs -- list of the ensembles, each a single pdb file.
amoptd -- dictionary with job options.
job_time -- maximum permissible runtime (mainly used for batch queueing systems).
ensemble_options -- dictionary with ensemble-specific keywords e.g. ensemble_options[ensemble_name] = {'ncopies' : ncopies}
directory -- working directory to write files to.
"""
if not directory: directory = os.getcwd()
job_scripts = []
keyword_options = {}
for ensemble_pdb in ensemble_pdbs:
name = os.path.splitext(os.path.basename(ensemble_pdb))[0] # Get name from pdb path
# Get any options specific to this ensemble
if ensemble_options and name in ensemble_options: keyword_options = ensemble_options[name]
# Generate dictionary with all the options for this job and write to keyword file
keyword_dict = mrbump_cmd.keyword_dict(ensemble_pdb, name, amoptd, keyword_options)
keyword_file = os.path.join(directory,name+'.mrbump')
keyword_str = mrbump_cmd.mrbump_keyword_file(keyword_dict)
with open(keyword_file,'w') as f: f.write(keyword_str)
script = write_jobscript(name,
keyword_file,
amoptd,
directory = directory,
job_time = job_time)
job_scripts.append(script)
if not len(job_scripts):
raise RuntimeError("No job scripts created!")
return job_scripts
[docs]def write_jobscript(name, keyword_file, amoptd, directory=None, job_time=86400, extra_options={}):
"""
Create the script to run MrBump for this PDB.
"""
if not directory: directory = os.getcwd()
# Next the script to run mrbump
script_path = os.path.abspath(os.path.join(directory, name+ample_util.SCRIPT_EXT))
with open(script_path, "w") as job_script:
# Header
if not sys.platform.startswith("win"):
script_header = '#!/bin/bash\n'
script_header += '[[ ! -d $CCP4_SCR ]] && mkdir $CCP4_SCR\n\n'
job_script.write(script_header)
# Get the mrbump command-line
jobcmd = mrbump_cmd.mrbump_cmd(name, amoptd['mtz'], amoptd['mr_sequence'], keyword_file)
job_script.write(jobcmd)
# Make executable
os.chmod(script_path, 0o777)
logger.debug("Wrote MRBUMP script: {0}".format(script_path))
return script_path
if __name__ == "__main__":
if len(sys.argv) >= 2:
mrbump_dir = os.path.join(os.getcwd(), sys.argv[1])
else:
mrbump_dir = os.getcwd()
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
r = ResultsSummary()
print(r.summariseResults(mrbump_dir, max_loglevel=logging.DEBUG))