import sys
import olex
import olx
import olex_core
import os
import olexex
import OlexVFS
import gui
import olex
from ArgumentParser import ArgumentParser
from History import hist
from olexex import OlexRefinementModel
from olexFunctions import OV, SilentException
debug = OV.IsDebugging()
green = OV.GetParam('gui.green')
red = OV.GetParam('gui.red')
orange = OV.GetParam('gui.orange')
white = "#ffffff"
black = "#000000"
table = OV.GetVar('HtmlTableFirstcolColour')
import ExternalPrgParameters
from CifInfo import MergeCif
import time
import shutil
# The listeners expect a function
class ListenerManager(object):
def __init__(self):
self.onStart_listeners = []
self.onEnd_listeners = []
def register_listener(self, listener,event):
if event == "onEnd":
for l in self.onEnd_listeners:
if type(l.__self__) == type(listener.__self__):
return False
self.onEnd_listeners.append(listener)
elif event == "onStart":
for l in self.onStart_listeners:
if type(l.__self__) == type(listener.__self__):
return False
self.onStart_listeners.append(listener)
def startRun(self, caller):
for item in self.onStart_listeners:
item(caller)
def endRun(self, caller):
for item in self.onEnd_listeners:
item(caller)
LM = ListenerManager()
class RunPrg(ArgumentParser):
running = None
def __init__(self):
super(RunPrg, self).__init__()
self.demote = False
self.SPD, self.RPD = ExternalPrgParameters.get_program_dictionaries()
self.terminate = False
self.interrupted = False
self.tidy = False
self.method = None
self.Ralpha = 0
self.Nqual = 0
self.CFOM = 0
self.HasGUI = OV.HasGUI()
self.make_unique_names = False
self.isAllQ = False #If all atoms are q-peaks, this will be assigned to True
self.his_file = None
self.please_run_auto_vss = False
self.demo_mode = OV.FindValue('autochem_demo_mode',False)
self.broadcast_mode = OV.FindValue('broadcast_mode',False)
if self.demo_mode:
OV.demo_mode = True
if self.HasGUI:
from Analysis import PrgAnalysis
self.PrgAnalysis = PrgAnalysis
OV.registerFunction(self.run_auto_vss,False,'runprg')
self.params = olx.phil_handler.get_python_object()
OV.SetVar('SlideQPeaksVal','0') # reset q peak slider to display all peaks
if not self.filename:
print("No structure loaded")
return
self.original_filename = self.filename
olx.Stop('listen')
self.shelx_alias = OV.FileName().replace(' ', '').lower()
os.environ['FORT_BUFFERED'] = 'TRUE'
self.post_prg_output_html_message = ""
def __del__(self):
if self.method is not None and \
hasattr(self.method, "unregisterCallback") and \
callable(self.method.unregisterCallback):
self.method.unregisterCallback()
def run(self):
import gui
stopwatch = olx.stopwatch
gui.set_notification(OV.GetVar('gui_notification'))
OV.SetVar('gui_notification', "Refining...;%s;%s" %(green,white))
if RunPrg.running:
OV.SetVar('gui_notification', "Already running. Please wait...")
print("Already running. Please wait...")
return
RunPrg.running = self
if OV.IsRemoteMode():
res_file = os.path.join(self.filePath, self.curr_file)+".res"
if os.path.exists(res_file):
os.remove(res_file)
caught_exception = None
try:
evt = stopwatch.start_scope("Running %s" %self.program.name)
res = self.method.run(self)
evt.stop()
if not res:
return False
if not self.method.failure:
stopwatch.run(self.runAfterProcess)
return True
except Exception as e:
e_str = str(e)
if ("stoks.size() == scatterer" not in e_str)\
and ("Error during building of normal equations using OpenMP" not in e_str)\
and ("fsci != sc_map.end()" not in e_str):
sys.stdout.formatExceptionInfo()
else:
print("Error!: ")
caught_exception = e
finally:
stopwatch.run(self.endRun)
sys.stdout.refresh = False
sys.stdout.graph = False
RunPrg.running = False
if self.please_run_auto_vss:
self.run_auto_vss()
stopwatch.log()
if caught_exception:
raise SilentException(caught_exception)
def run_auto_vss(self):
OV.paramStack.push('snum.refinement.max_cycles')
OV.paramStack.push('snum.refinement.max_peaks')
olx.Freeze(True)
try:
olex.m('compaq')
olex.m('compaq -a')
olx.VSS(True)
olex.m('compaq')
olex.m('refine 2 10')
olex.m('compaq')
olx.ATA()
olex.m('refine 2 10')
finally:
olx.Freeze(False)
OV.paramStack.pop(2)
def setup_masking(self, clean=False):
prg = OV.GetParam("snum.refinement.recompute_mask_before_refinement_prg")
if prg == "Platon" and olx.HKLF() == '5' and OV.GetParam('snum.refinement.recompute_mask_before_refinement') == True and OV.GetParam('snum.refinement.use_solvent_mask') == True:
OV.SetParam("snum.refinement.use_solvent_mask", False)
olex.m('delins ABIN')
olex.m('delins list 8')
olex.m('addins list 8')
olex.m('refine')
olex.m('file')
olex.m('addins ABIN')
olex.m('delins list 8')
OV.SetParam("snum.refinement.use_solvent_mask", True)
return
#if OV.GetParam("snum.refinement.use_solvent_mask") and OV.GetParam('snum.refinement.recompute_mask_before_refinement'):
#OV.SetVar('current_mask_sqf', "")
### If the original filename already ends in _sq (i.e. the files come from outside Olex2, things get very confusing. Maybe one way of dealing with it is to leave the original files all untouched, and rename sNum to the filename without the _sq bit, alongside with the HKLSrc(). But will metadata get lost? Should all files get copied/renamed?
#fn = OV.HKLSrc()
#nfn = fn.replace("_sq.hkl", '.hkl')
#if "_sq.hkl" in fn:
#olx.file.Copy(fn, nfn)
#nf = OV.FileFull().replace("_sq.", ".")
#olex.m(f"file {nf}")
#olex.m(f"reap {nf}")
### This looks misleading -- the 'original' filename refer to renamings once the masking process has started.
#self.original_filename = nfn
#OV.HKLSrc(nfn)
if clean:
from pathlib import Path
# Define the folder and pattern
folder_path = Path(OV.FilePath())
prg = OV.GetParam("snum.refinement.recompute_mask_before_refinement_prg")
if prg.lower() == 'platon':
patterns = ["*_sq.*", "*_sqd.*"]
for pattern in patterns:
for file in folder_path.glob(pattern):
file.unlink()
print(f"Deleted: {file}")
else:
pattern = "*.fab"
for file in folder_path.glob(pattern):
if "_sq" not in file.name:
file.unlink()
print(f"Deleted: {file}")
else:
print(f"Skippted: {file}")
def which_shelx(self, type="xl"):
a = olexex.which_program(type)
if a == "":
OV.Alert("Error", "ShelX %s is not found on this system.\nPlease make sure that the ShelX executable files can be found on system PATH." %type, "O")
OV.Cursor()
self.terminate = True
return a
def doBroadcast(self):
ext = "res"
copy_from = "%s/%s.%s" %(self.tempPath, self.shelx_alias, ext)
copy_to = "%s/listen.res" %(self.datadir)
if os.path.isfile(copy_from):
if copy_from.lower() != copy_to.lower():
shutil.copyfile(copy_from, copy_to)
def doFileResInsMagic(self):
file_lock = OV.createFileLock(os.path.join(self.filePath, self.original_filename))
try:
extensions = ['res', 'lst', 'cif', 'fcf', 'mat', 'pdb', 'lxt']
if "xt" in self.program.name.lower():
extensions.append('hkl')
if "srv" in self.program.name.lower():
extensions.append('npy')
extensions.append('log')
if self.broadcast_mode:
self.doBroadcast()
for ext in extensions:
if "xt" in self.program.name.lower() and ext != 'lst' and ext != 'lxt':
copy_from = "%s/%s_a.%s" %(self.tempPath, self.shelx_alias, ext)
else:
copy_from = "%s/%s.%s" %(self.tempPath, self.shelx_alias, ext)
copy_to = "%s/%s.%s" %(self.filePath, self.original_filename, ext)
if os.path.isfile(copy_from) and\
copy_from.lower() != copy_to.lower(): # could this ever be true??
shutil.copyfile(copy_from, copy_to)
finally:
OV.deleteFileLock(file_lock)
def doHistoryCreation(self, type="normal"):
return
def IsClientMode(self):
from method_imp import Method_client_refinement
return OV.IsClientMode() and\
self.method is not None and\
isinstance(self.method, Method_client_refinement)
def setupFiles(self):
olx.User("%s" %OV.FilePath())
self.filePath = OV.FilePath()
self.fileName = OV.FileName()
self.tempPath = os.path.join(OV.StrDir(), "temp")
self.curr_file = OV.FileName()
fin_file = os.path.join(self.tempPath,
self.curr_file.replace(' ', '').lower()) + ".fin"
if os.path.exists(fin_file):
os.remove(fin_file)
# just save snum phil with current settings
if self.IsClientMode():
str_dir = OV.StrDir()
if not os.path.exists(str_dir):
os.mkdir(str_dir)
snum_phil_fn = os.path.join(str_dir, OV.ModelSrc()) + ".phil"
olx.phil_handler.save_param_file(
file_name=snum_phil_fn,
scope_name='snum', diff_only=True)
## clear temp folder to avoid problems
if os.path.exists(self.tempPath) and \
self.program.name != "olex2.refine" and\
not self.IsClientMode():
old_temp_files = os.listdir(self.tempPath)
for file_n in old_temp_files:
try:
if "_.res" or "_.hkl" not in file_n:
os.remove(r'%s/%s' %(self.tempPath,file_n))
except OSError:
continue
self.hkl_src = OV.HKLSrc()
if OV.GetParam('snum.refinement.recompute_mask_before_refinement_prg') == "Platon" and not OV.GetParam('snum.refinement.recompute_mask_before_refinement'):
self.hkl_src = f"{os.path.splitext(OV.FileFull())[0]}_sq.hkl"
if not os.path.exists(self.hkl_src):
self.hkl_src = os.path.splitext(OV.FileFull())[0] + '.hkl'
if os.path.exists(self.hkl_src):
OV.HKLSrc(self.hkl_src)
print("HKL Source Filename reset to default file!")
else:
raise Exception("Please choose a reflection file")
self.hkl_src_name = os.path.splitext(os.path.basename(self.hkl_src))[0]
if self.program.name == "olex2.refine" or self.IsClientMode():
return
if not os.path.exists(self.tempPath):
os.mkdir(self.tempPath)
if olx.xf.GetIncludedFiles():
files = [(os.path.join(self.filePath, x),os.path.join(self.tempPath, x))
for x in olx.xf.GetIncludedFiles().split('\n')]
else:
files = []
files.append((self.hkl_src,
os.path.join(self.tempPath, self.shelx_alias) + ".hkl"))
files.append((os.path.join(self.filePath, self.curr_file) + ".ins",
os.path.join(self.tempPath, self.shelx_alias) + ".ins"))
files.append((os.path.splitext(self.hkl_src)[0] + ".fab",
os.path.join(self.tempPath, self.curr_file) + ".fab"))
for f in files:
if os.path.exists(f[0]) and not os.path.exists(f[1]):
shutil.copyfile(f[0], f[1])
def runAfterProcess(self):
if self.IsClientMode():
self.method.runAfterProcess(self)
return
if self.program.name != "olex2.refine":
if self.program.name != "olex2.refine":
olx.stopwatch.run(self.doFileResInsMagic)
if self.HasGUI:
olx.Freeze(True)
olx.stopwatch.run(OV.reloadStructureAtreap, self.filePath, self.curr_file, update_gui=False)
if self.HasGUI:
olx.Freeze(False)
# XT changes the HKL file - so it *will* match the file name
if 'xt' not in self.program.name.lower():
OV.HKLSrc(self.hkl_src)
else:
if self.broadcast_mode:
olx.stopwatch.run(self.doBroadcast)
lstFile = '%s/%s.lst' %(self.filePath, self.original_filename)
if os.path.exists(lstFile):
os.remove(lstFile)
olx.DelIns("TREF")
if self.params.snum.refinement.auto.max_peaks:
max_peaks = olexex.OlexRefinementModel().getExpectedPeaks()
if max_peaks <= 5:
self.params.snum.refinement.auto.pruneQ = 0.5
self.params.snum.refinement.auto.assignQ = 6.0
OV.SetParam('snum.refinement.auto.pruneQ', 0.5)
OV.SetParam('snum.refinement.auto.assignQ', 6.0)
else:
self.params.snum.refinement.auto.pruneQ = 1.5
self.params.snum.refinement.auto.assignQ = 2.0
OV.SetParam('snum.refinement.auto.pruneQ', 1.5)
OV.SetParam('snum.refinement.auto.assignQ', 2.0)
def getProgramMethod(self, fun):
if fun == 'refine':
self.prgType = prgType = 'refinement'
prgDict = self.RPD
prg = self.params.snum.refinement.program
method = self.params.snum.refinement.method
else:
self.prgType = prgType = 'solution'
prgDict = self.SPD
prg = self.params.snum.solution.program
method = self.params.snum.solution.method
try:
program = prgDict.programs[prg]
except KeyError:
raise Exception("Please choose a valid %s program" %prgType)
try:
prgMethod = program.methods[method]
except KeyError:
raise Exception("Please choose a valid method for the %s program %s" %(prgType, prg))
return program, prgMethod
def startRun(self):
OV.CreateBitmap('%s' %self.bitmap)
LM.startRun(self)
def endRun(self):
self.method.unregisterCallback()
OV.DeleteBitmap('%s' %self.bitmap)
OV.Cursor()
LM.endRun(self)
def post_prg_html(self):
if not OV.HasGUI():
return
import gui.tools
typ = self.prgType.lower()
if typ=='refinement':
return
extra_msg = ""
if typ == "refinement":
extra_msg = "$spy.MakeHoverButton('small-Assign@refinement','ATA(1)')"
elif typ == "solution" and self.program.name.lower() != "shelxt":
extra_msg = gui.tools.TemplateProvider.get_template('run_auto_vss_box', force=debug)
message = "
%s | %s | " %(self.post_prg_output_html_message, extra_msg)
d = {
'program_output_type':"PROGRAM_OUTPUT_%s" %self.prgType.upper(),
'program_output_name':self.program.name,
'program_output_content': message
}
t = gui.tools.TemplateProvider.get_template('program_output', force=debug)%d
f_name = OV.FileName() + "_%s_output.html" %self.prgType
OlexVFS.write_to_olex(f_name, t)
# olx.html.Update()
class RunSolutionPrg(RunPrg):
def __init__(self):
RunPrg.__init__(self)
self.bitmap = 'solve'
self.program, self.method = self.getProgramMethod('solve')
self.run()
def run(self):
if int(olx.xf.au.GetAtomCount()) != 0:
if OV.HasGUI():
if OV.GetParam('user.alert_solve_anyway') == 'Y':
r = OV.Alert("Solve", "Are you sure you want to solve this again?",
'YNIR', "(Don't show this warning again)")
if "R" in r:
OV.SetParam('user.alert_solve_anyway', 'N')
if "Y" not in r: # N/C
self.terminate = True
return
OV.SetParam('snum.refinement.data_parameter_ratio', 0)
OV.SetParam('snum.NoSpherA2.use_aspherical', False)
self.startRun()
OV.SetParam('snum.refinement.auto.invert',True)
if OV.IsFileType('cif'):
OV.Reap('%s/%s.ins' %(self.filepath,self.filename))
self.setupSolve()
if self.terminate: return
self.setupFiles()
if self.terminate:
self.endRun()
self.endHook()
return
if self.params.snum.solution.graphical_output and self.HasGUI:
self.method.observe(self)
RunPrg.run(self)
def runAfterProcess(self):
olx.UpdateWght(0.1)
OV.SetParam('snum.refinement.suggested_weight','0.1 0')
OV.SetParam('snum.refinement.update_weight', False)
RunPrg.runAfterProcess(self)
self.method.post_solution(self)
self.post_prg_html()
self.doHistoryCreation()
OV.SetParam('snum.current_process_diagnostics','solution')
def setupSolve(self):
try:
self.sg = '\'' + olex.f(r'sg(%n)') + '\''
except:
self.sg = ""
self.formula = olx.xf.GetFormula()
if not self.formula:
if self.HasGUI:
import olex_gui
r = olex_gui.GetUserInput(1, "Please enter the structure composition", "")
if not r:
self.terminate = True
return
self.formula = r
else:
print('Please provide the structure composition')
self.terminate = True
if "olex2" not in self.program.name:
self.shelx = self.which_shelx(self.program)
args = self.method.pre_solution(self)
if args:
olex.m('reset ' + args)
else:
olx.Reset()
def doHistoryCreation(self):
OV.SetParam('snum.refinement.last_R1', 'Solution')
OV.SetParam('snum.refinement.last_wR2', 'Solution')
if self.IsClientMode():
return None
self.his_file = hist.create_history(solution=True)
OV.SetParam('snum.solution.current_history', self.his_file)
return self.his_file
class RunRefinementPrg(RunPrg):
running = None
def __init__(self):
RunPrg.__init__(self)
self.bitmap = 'refine'
self.program, self.method = self.getProgramMethod('refine')
if self.program is None or self.method is None:
return
if OV.IsClientMode():
from method_imp.client import Method_client_refinement
self.method = Method_client_refinement()
self.refinement_observer_timer = 0
self.refinement_has_failed = []
# may need to check self.program.name for ShelXl to make cleaner...
use_convergence = OV.GetParam("user.refinement.shelxl_convergence_use")
OV.registerCallback("procout", self.refinement_observer)
if use_convergence:
cl = RunRefinementPrg.convergency_listener()
OV.registerCallback("procout", cl.listen_for_convergency)
self.run()
OV.unregisterCallback("procout", self.refinement_observer)
if use_convergence:
OV.unregisterCallback("procout", cl.listen_for_convergency)
if self.refinement_has_failed:
bg = red
fg = white
msg = " | ".join(self.refinement_has_failed)
if "warning" in msg.lower():
bg = orange
gui.set_notification("%s;%s;%s" % (msg, bg, fg))
elif self.IsClientMode():
rc_fn = os.path.join(OV.StrDir(), "refinement.check")
if os.path.exists(rc_fn):
gui.set_notification(open(rc_fn, "r").read())
elif not OV.IsNoSpherA2():
gui.get_default_notification(txt="Refinement Finished",
txt_col='green_text')
else:
gui.get_default_notification(
txt="Refinement Finished
Please Cite NoSpherA2: DOI 10.1039/D0SC05526C",
txt_col='green_text')
def reset_params(self):
OV.SetParam('snum.refinement.hooft_str', "")
OV.SetParam('snum.refinement.flack_str', "")
OV.SetParam('snum.refinement.parson_str', "")
def run_pre_run_macro(self):
macro = OV.GetVar('pre_run_macro')
OV.SetVar("pre_run_macro", "")
if not macro:
return
else:
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
mac = macro.split(">>")
for cmd in mac:
olex.m(cmd)
print("> -- %s" % cmd.strip())
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
def run(self):
self.setup_masking()
self.run_pre_run_macro()
if RunRefinementPrg.running:
print("Already running. Please wait...")
return False
RunRefinementPrg.running = self
self.reset_params()
use_aspherical = OV.IsNoSpherA2() and not self.IsClientMode()
result = False
try:
if use_aspherical == True:
make_fcf_only = OV.GetParam('snum.NoSpherA2.make_fcf_only')
if make_fcf_only == True:
from aaff import make_fcf
result = make_fcf(self)
else:
result = olx.stopwatch.run(self.method.deal_with_AAFF, self)
else:
olx.stopwatch.run(self.startRun)
try:
olx.stopwatch.run(self.setupRefine)
OV.File(os.path.join(OV.FilePath(), self.original_filename) + ".ins")
self.setupFiles()
except Exception as err:
sys.stderr.formatExceptionInfo()
self.endRun()
return False
if self.terminate:
self.endRun()
return
if self.params.snum.refinement.graphical_output and self.HasGUI:
self.method.observe(self)
olx.stopwatch.run(RunPrg.run, self)
except Exception as err:
sys.stderr.formatExceptionInfo()
self.terminate = True
finally:
if result == False:
self.terminate = True
if use_aspherical == True:
self.refinement_has_failed.append("Error during NoSpherA2")
# remove res if failed but only for remote run
RunRefinementPrg.running = None
def setupRefine(self):
self.terminate = self.method.pre_refinement(self)
if self.terminate:
return
self.shelx = self.which_shelx(self.program)
if self.params.snum.refinement.auto.assignQ:
_ = olexex.get_auto_q_peaks()
self.params.snum.refinement.max_peaks = _
OV.SetParam('snum.refinement.max_peaks', _)
import programSettings
programSettings.onMaxPeaksChange(_)
if olx.LSM().upper() == "CGLS" and olx.Ins("ACTA") != "n/a":
olx.DelIns("ACTA")
def doAutoTidyBefore(self):
olx.Clean('-npd -aq=0.1 -at')
if self.params.snum.refinement.auto.assignQ:
olx.Sel('atoms where xatom.peak>%s' %self.params.snum.refinement.auto.assignQ)
olx.Name('sel C')
if self.params.snum.refinement.auto.pruneU:
i = 0
uref = 0
for i in range(int(olx.xf.au.GetAtomCount())):
ueq = float(olx.xf.au.GetAtomUiso(i))
if uref:
if uref == ueq:
continue
else:
olx.Sel('atoms where xatom.uiso>%s' %self.params.snum.refinement.auto.pruneU)
olx.Kill('sel')
break
else:
uref = ueq
try:
pass
olx.Clean('-npd -aq=0.1 -at')
except:
pass
def doAutoTidyAfter(self):
auto = self.params.snum.refinement.auto
olx.Clean('-npd -aq=0.1 -at')
if self.tidy:
olx.Sel('atoms where xatom.uiso>0.07')
olx.Sel('atoms where xatom.peak<2&&xatom.peak>0')
olx.Kill('sel')
if self.isAllQ:
olx.Sel('atoms where xatom.uiso>0.07')
olx.Kill('sel')
if auto.pruneQ:
olx.Sel('atoms where xatom.peak<%.3f&&xatom.peak>0' %float(auto.pruneQ))
olx.Kill('sel')
#olx.ShowQ('a true') # uncomment me!
#olx.ShowQ('b true') # uncomment me!
if auto.pruneU:
olx.Sel('atoms where xatom.uiso>%s' %auto.pruneU)
olx.Kill('sel')
if auto.assignQ:
olx.Sel('atoms where xatom.peak>%s' %auto.assignQ)
olx.Name('sel C')
olx.Sel('-u')
if auto.assemble == True:
olx.Compaq(a=True)
olx.Move()
else:
pass
olx.Clean('-npd -aq=0.1 -at')
def runAfterProcess(self):
if self.terminate:
return
RunPrg.runAfterProcess(self)
evt = olx.stopwatch.start_scope("Post-refinement")
self.method.post_refinement(self)
delete_stale_fcf()
self.post_prg_html()
self.doHistoryCreation()
evt.stop()
if self.R1 == 'n/a':
return
if self.params.snum.refinement.auto.tidy:
self.doAutoTidyAfter()
OV.File()
if OV.GetParam('snum.refinement.check_absolute_structure_after_refinement') and\
not OV.IsEDRefinement():
try:
olx.stopwatch.run(self.isInversionNeeded, force=self.params.snum.refinement.auto.invert)
except Exception as e:
print("Could not determine whether structure inversion is needed: %s" % e)
if self.program.name == "olex2.refine" and not self.IsClientMode():
evt = olx.stopwatch.start_scope("Checks")
from refinement_checks import RefinementChecks
rc = RefinementChecks(self.cctbx)
if OV.GetParam('snum.refinement.check_PDF'):
try:
rc.check_PDF(force=self.params.snum.refinement.auto.remove_anharm)
except Exception as e:
print("Could not check PDF: %s" % e)
rc.check_disp()
rc.check_occu()
rc.check_mu() #This is the L-M mu!
evt.stop()
self.refinement_has_failed = rc.refinement_has_failed
OV.SetParam('snum.init.skip_routine', False)
OV.SetParam('snum.current_process_diagnostics','refinement')
if self.params.snum.refinement.cifmerge_after_refinement:
evt = olx.stopwatch.start_scope("CifMerge")
try:
MergeCif(edit=False, force_create=False, evaluate_conflicts=False)
except Exception as e:
if debug:
sys.stdout.formatExceptionInfo()
print("Failed in CifMerge: '%s'" %str(e))
evt.stop()
class convergency_listener(object):
done = False
convergence_value = 1e3
def __init__(self) -> None:
self.convergence_value = OV.GetParam("user.refinement.shelxl_convergence")
def listen_for_convergency(self, line):
if self.done or self.convergence_value < 0:
return
#if "Max. shift = " in line:
if "Maximum = " in line:
try:
max_shift = float(line.split("Maximum = ")[1].split()[0])
if abs(max_shift) <= self.convergence_value:
try:
self.done = True
OV.writeShelxFinFile()
olx.Echo("Refinement has converged, writing .fin file", m="warning")
except:
pass
except:
pass
def refinement_observer(self, msg):
if self.refinement_observer_timer == 0:
self.refinement_observer_timer = time.time()
#if time.time() - self.refinement_observer_timer < 2:
#return
if "BAD AFIX CONNECTIVITY" in msg or "ATOM FOR AFIX" in msg:
self.refinement_has_failed.append("Hydrogens")
elif "REFINEMNET UNSTABLE" in msg:
self.refinement_has_failed.append("Unstable")
elif "???????" in msg:
self.refinement_has_failed.append("ShelXL Crashed!")
elif "** " in msg:
import re
regex = re.compile(r"\*\*(.*?)\*\*")
m = regex.findall(msg)
if m:
self.refinement_has_failed.append(m[0].strip())
def doHistoryCreation(self):
R1 = 0
self.his_file = ""
wR2 = 0
if olx.IsVar('cctbx_R1') == 'true':
R1 = float(olx.GetVar('cctbx_R1'))
olx.UnsetVar('cctbx_R1')
wR2 = float(olx.GetVar('cctbx_wR2'))
olx.UnsetVar('cctbx_wR2')
else:
try:
R1 = float(olx.Lst('R1'))
wR2 = float(olx.Lst('wR2'))
except:
pass
if R1:
OV.SetParam('snum.refinement.last_R1', str(R1))
OV.SetParam('snum.refinement.last_wR2',wR2)
if not (self.params.snum.init.skip_routine or self.IsClientMode()):
try:
self.his_file = hist.create_history()
except Exception as ex:
sys.stderr.write("History could not be created\n")
if debug:
sys.stderr.formatExceptionInfo()
elif not self.IsClientMode():
print("Skipping History")
self.R1 = R1
self.wR2 = wR2
else:
self.R1 = self.wR2 = "n/a"
self.his_file = None
print("The refinement has failed, no R value was returned by the refinement")
return self.his_file, self.R1
def isInversionNeeded(self, force=False):
if self.params.snum.init.skip_routine:
print ("Skipping absolute structure validation")
return
if olex_core.SGInfo()['Centrosymmetric'] == 1: return
from libtbx.utils import format_float_with_standard_uncertainty
from cctbx import sgtbx
if debug:
print("Checking absolute structure...")
inversion_needed = False
possible_racemic_twin = False
inversion_warning = "WARNING: Structure should be inverted (inv -f), unless there is a good reason not to do so."
racemic_twin_warning = "WARNING: Structure may be an inversion twin"
output = []
flack = OV.GetParam('snum.refinement.flack_str')
# check if the nversion twin refinement...
if not flack:
from cctbx.array_family import flex
rm = olexex.OlexRefinementModel()
twinning = rm.model.get('twin')
if twinning is not None:
twin_law = sgtbx.rot_mx([int(twinning['matrix'][j][i])
for i in range(3) for j in range(3)])
if twin_law.as_double() == sgtbx.rot_mx((-1,0,0,0,-1,0,0,0,-1)):
flack = olx.xf.rm.BASF(0)
OV.SetParam('snum.refinement.flack_str', flack)
parson = OV.GetParam('snum.refinement.parson_str')
hooft = self.method.getHooft()
if hooft and hasattr(hooft, 'p3_racemic_twin'):
if (hooft.p3_racemic_twin is not None and
round(hooft.p3_racemic_twin, 3) == 1):
possible_racemic_twin = True
elif hooft.p2_false is not None and round(hooft.p2_false, 3) == 1:
inversion_needed = True
s = format_float_with_standard_uncertainty(
hooft.hooft_y, hooft.sigma_y)
output.append("Hooft y: %s" %s)
elif flack or parson:
value = parson
if not value:
value = flack
fs = value.split("(")
val = float(fs[0])
if val != 0:
error = float(fs[1][:-1])
temp = val
while abs(temp) < 1.0:
temp *= 10
error /= 10
if val > 0.8 and val-error > 0.5:
inversion_needed = True
if parson:
output.append("Parson's q: %s" %parson)
if flack:
output.append("Flack x: %s" %flack)
print(', '.join(output))
if force and inversion_needed:
olex.m('Inv -f')
OV.File('%s.res' %OV.FileName())
OV.SetParam('snum.refinement.auto.invert',False)
print("The Structure has been inverted")
elif inversion_needed:
print(inversion_warning)
if possible_racemic_twin:
if (hooft.olex2_adaptor.twin_components is not None and
hooft.olex2_adaptor.twin_components[0].twin_law.as_double() != sgtbx.rot_mx((-1,0,0,0,-1,0,0,0,-1))):
print(racemic_twin_warning)
def AnalyseRefinementSource():
file_name = OV.ModelSrc()
ins_file_name = olx.file.ChangeExt(file_name, 'ins')
res_file_name = olx.file.ChangeExt(file_name, 'res')
hkl_file_name = olx.file.ChangeExt(file_name, 'hkl')
if olx.IsFileType('cif') == 'true':
if os.path.exists(ins_file_name) or os.path.exists(res_file_name):
olex.m('reap "%s"' %ins_file_name)
hkl_file_name = os.path.join(os.getcwd(), hkl_file_name)
if os.path.exists(hkl_file_name):
olx.HKLSrc(hkl_file_name)
return True
else:
return False
fn = os.path.normpath("%s/%s" %(olx.FilePath(), olx.xf.DataName(olx.xf.CurrentData())))
ins_file_name = fn + '.ins'
res_file_name = fn + '.res'
hkl_file_name = fn + '.hkl'
olex.m("export '%s'" %hkl_file_name)
if os.path.exists(res_file_name):
olex.m('reap "%s"' %res_file_name)
print('Loaded RES file extracted from CIF')
else:
OV.File("%s" %ins_file_name)
olex.m('reap "%s"' %ins_file_name)
olex.m("free xyz,Uiso")
print('Loaded INS file generated from CIF')
if os.path.exists(hkl_file_name):
olx.HKLSrc(hkl_file_name)
else:
print('HKL file is not in the CIF')
return False
return True
OV.registerFunction(AnalyseRefinementSource)
OV.registerFunction(RunRefinementPrg)
OV.registerFunction(RunSolutionPrg)
def delete_stale_fcf():
fcf = os.path.join(OV.FilePath(), OV.FileName() + '.fcf')
res = os.path.join(OV.FilePath(), OV.FileName() + '.res')
if os.path.exists(res) and os.path.exists(fcf):
diff = abs(os.path.getmtime(fcf) - os.path.getmtime(res))
# modified within 10 seconds
if diff < 10:
return False
else:
os.remove(fcf)
print("Deleted stale fcf: %s (%ss old)" %(fcf, int(diff)))
if OV.HasGUI():
import gui
gui.set_notification("Stalefcf filehas been deleted.")
return True