import os from Method import Method, Method_refinement, Method_solution import phil_interface from olexFunctions import OV import olex import olx import glob import OlexVFS import ntpath import cctbx_olex_adapter as COA class Method_shelx(Method): def do_run(self, RunPrgObject): """Runs any SHELX refinement/solution program """ print('STARTING SHELX %s with %s' %( RunPrgObject.program.program_type, self.name)) prgName = olx.file.GetName(RunPrgObject.shelx) #olex.m("User '%s'" %RunPrgObject.tempPath) olx.User("%s" %RunPrgObject.tempPath) xl_ins_filename = RunPrgObject.shelx_alias # This is super ugly but what can I do? # This really be a function rather than a separate file but I can not get it to work yet? if prgName.split('.')[0].lower() in ('shelxs', 'xs', 'shelxs86', 'shelxs13', 'shelxd', 'xm'): lines_in = None with open(xl_ins_filename.lower()+'.ins', 'r') as x: lines_in = x.readlines() lines_out = [] sfac = [] unit_idx = None for line in lines_in: l = line.upper() if l.startswith('DISP') or l.startswith('REM'): continue if l.startswith('SFAC'): toks = l.split() if len(toks) > 2: try: # is expanded SFAC? float(toks[2]) sfac.append(toks[1]) except: sfac += toks[1:] continue elif l.startswith('UNIT'): unit_idx = len(lines_out) lines_out.append(line) if unit_idx is not None: lines_out.insert(unit_idx, 'SFAC ' + ' '.join(sfac) + '\n') with open(xl_ins_filename.lower()+'.ins', 'w') as x: for l in lines_out: x.write(l) commands = [xl_ins_filename.lower()] #This is correct!!!!!! #sys.stdout.graph = RunPrgObject.Graph() if self.command_line_options: commands += self.command_line_options.split() success = olx.Exec(prgName, *commands, q=(not RunPrgObject.params.snum.shelx_output)) if not success: raise RuntimeError( 'you may be using an outdated version of %s' %(prgName)) olx.WaitFor('process') # uncomment me! additions = ['', '_a', '_b', '_c', '_d', '_e'] self.failure = True for add in additions: p = "%s%s.res" %(xl_ins_filename, add) if os.path.exists(p): if os.path.getsize(p) != 0: self.failure = False break olx.User(RunPrgObject.filePath) class Method_shelx_solution(Method_shelx, Method_solution): """Inherits methods specific to shelx solution programs """ def observe(self, RunPrgObject): import Analysis self.observer = Analysis.ShelXS_graph(RunPrgObject.program, RunPrgObject.method) OV.registerCallback("procout", self.observer.observe) class Method_shelx_refinement(Method_shelx, Method_refinement): """Inherits methods specific to shelx refinement programs """ def __init__(self, phil_object): Method.__init__(self, phil_object) self.cif = {} def pre_refinement(self, RunPrgObject): if OV.GetParam("snum.refinement.use_solvent_mask"): import cctbx_olex_adapter from smtbx import masks from libtbx import easy_pickle #from iotbx.shelx import hklf modified_hkl_path = "%s/%s-mask.hkl" %(OV.FilePath(), OV.FileName()) fab_path = "" if OV.HKLSrc(): fab_path = ".".join(OV.HKLSrc().split(".")[:-1]) + ".fab" _ = OV.GetParam("snum.refinement.recompute_mask_before_refinement_prg") method = "smbtx" if _ == "Platon": method = "SQUEEZE" f_mask = None # backward compatibility - just in case if not OV.HKLSrc() == modified_hkl_path: olx.SetVar('snum.masks.original_hklsrc', OV.HKLSrc()) else: olx.SetVar('snum.masks.original_hklsrc', '') if OV.GetParam("snum.refinement.recompute_mask_before_refinement") or not os.path.exists(fab_path): if OV.HKLSrc() == modified_hkl_path: _ = "You can't calculate a mask on an already masked file!" OlexVFS.write('mask_notification.htm',_,1) raise Exception(_) if method == "SQUEEZE": olex.m("spy.OlexPlaton(q,.ins)") fn = OV.HKLSrc().replace(".", "_sq.") if os.path.exists(fn): OV.HKLSrc(fn) Method_refinement.pre_refinement(self, RunPrgObject) return else: if "_sq" in OV.HKLSrc(): fn = OV.HKLSrc().replace("_sq.", ".") if not os.path.exists(fn): import shutil shutil.copy2(OV.HKLSrc(), fn) OV.HKLSrc(fn) COA.OlexCctbxMasks() if olx.current_mask.flood_fill.n_voids() > 0: f_mask = olx.current_mask.f_mask() else: _ = "There are no voids!" print(_) OV.SetParam("snum.refinement.use_solvent_mask", False) olex.m('delins ABIN') OlexVFS.write_to_olex('mask_notification.htm',_,1) if f_mask is not None: COA.write_fab(f_mask, fab_path) Method_refinement.pre_refinement(self, RunPrgObject) def post_refinement(self, RunPrgObject): before_mask = olx.GetVar('snum.masks.original_hklsrc', '') if before_mask: olx.UnsetVar('snum.masks.original_hklsrc') if OV.HKLSrc() != before_mask: OV.HKLSrc(before_mask) OV.File() suggested_weight = olx.Ins('weight1') if suggested_weight != 'n/a': if len(suggested_weight.split()) == 1: suggested_weight += ' 0' OV.SetParam('snum.refinement.suggested_weight', suggested_weight) self.gather_refinement_information() self.writeRefinementInfoIntoRes(self.cif) params = { 'snum.refinement.max_peak' : 'peak', 'snum.refinement.max_hole' : 'hole', 'snum.refinement.max_shift_site' : 'max_shift', 'snum.refinement.max_shift_site_atom' : 'max_shift_object', 'snum.refinement.max_shift_over_esd' : 'max_shift/esd', 'snum.refinement.max_shift_over_esd_atom' : 'max_shift/esd_object', 'snum.refinement.max_shift_u' : 'max_dU', 'snum.refinement.max_shift_u_atom' : 'max_dU_object', 'snum.refinement.flack_str' : 'flack', 'snum.refinement.parson_str' : 'parson', 'snum.refinement.goof' : "s", } for k,v in params.items(): v = olx.Lst(v) if v == 'n/a': v = "" OV.SetParam(k, v) try: parameters = float(olx.Lst('param_n')) data = float(olx.Lst('ref_4sig')) ratio = data/parameters OV.SetParam('snum.refinement.data_parameter_ratio', ratio) OV.SetParam('snum.refinement.parameters', parameters) except: OV.SetParam('snum.refinement.data_parameter_ratio', None) def gather_refinement_information(self): cif = {} cif.setdefault('_refine_ls_R_factor_all', olx.Lst('R1all')) cif.setdefault('_refine_ls_R_factor_gt', olx.Lst('R1')) cif.setdefault('_refine_ls_wR_factor_ref', olx.Lst('wR2')) cif.setdefault('_refine_ls_goodness_of_fit_ref', olx.Lst('s')) cif.setdefault('_refine_ls_shift/su_max', olx.Lst('max_shift/esd')) cif.setdefault('_refine_ls_shift/su_mean', olx.Lst('mean_shift/esd')) cif.setdefault('_reflns_number_total', olx.Lst('ref_total')) cif.setdefault('_reflns_number_gt', olx.Lst('ref_4sig')) cif.setdefault('_refine_ls_number_parameters', olx.Lst('param_n')) cif.setdefault('_refine_ls_number_restraints', olx.Lst('restraints_n')) parsons_q = olx.Lst('parson') if parsons_q == "n/a": cif['_refine_ls_abs_structure_Flack'] = olx.Lst('flack') else: cif['_refine_ls_abs_structure_Flack'] = parsons_q cif.setdefault('_refine_diff_density_max', olx.Lst('peak')) cif.setdefault('_refine_diff_density_min', olx.Lst('hole')) self.cif = cif def observe(self, RunPrgObject): import Analysis self.observer = Analysis.ShelXL_graph(RunPrgObject.program, RunPrgObject.method) OV.registerCallback("procout", self.observer.observe) class Method_shelxt(Method_shelx_solution): def pre_solution(self, RunPrgObject): pass # OlexVFS.delete("solution_output.htm") def post_solution(self, RunPrgObject): if not OV.HasGUI(): return import gui.tools debug = OV.IsDebugging() f = os.path.join(OV.StrDir(), "temp", OV.FileName() + '.lxt') if os.path.exists(f): f = open(f, 'r').readlines() else: return res_l = [] i = 0 for line in f: if "Rweak" not in line: i += 1 continue for j in range(len(f) -i): if "Assign" not in f[i+j]: res_l.append(f[i+j]) else: break s_blank = gui.tools.TemplateProvider.get_template('xt_output_table', force=debug) href = res_l[0][37:50].strip() d = { 'td1':"%s" %res_l[0][0:6].strip(), 'td2':"%s" %res_l[0][7:12].strip(), 'td3':"%s" %res_l[0][13:20].strip(), 'td4':"%s" %res_l[0][21:37].strip(), 'td5':"%s" %href, 'td6':"%s" %res_l[0][49:58].strip() } s = s_blank%d g = glob.glob(os.path.join(OV.StrDir(), "temp", "*.res")) i = 0 for item in g: short_p = ntpath.basename(item) if len(g) == 1: s = "ShelXT returned one solution: %s" %short_p break hkl = olx.file.ChangeExt(item, 'hkl') sg = "%s" %(res_l[i+1][37:50].strip()) href = ''' %s''' %(item, OV.FileName(), hkl, OV.FileName(), OV.FileFull(), sg) orientation = res_l[i+1][21:37].strip() flack = res_l[i+1][50:58].strip() R1 = res_l[i+1][0:6].strip() Rweak = res_l[i+1][7:12].strip() Alpha = res_l[i+1][13:20].strip() if not flack: flack = "---" else: try: if 0.4 < float(flack) < 0.6: flack = "%s" %flack elif -0.1 < float(flack) < 0.1: flack = "%s" %flack elif float(flack) < -0.2: flack = "%s" %flack except: flack = "---" d = { 'td1':"%s" %R1, 'td2':"%s" %Rweak, 'td3':"%s" %Alpha, 'td4':"%s" %orientation, 'td5':"%s" %href, 'td6':"%s" %flack } s += s_blank %d i += 1 RunPrgObject.post_prg_output_html_message = s olex.m('delins list') olex.m('addins list 4') olex.m('compaq -a') class Method_shelx_direct_methods(Method_shelx_solution): def post_solution(self, RunPrgObject): Method_shelx_solution.post_solution(self, RunPrgObject) self.get_XS_TREF_solution_indicators(RunPrgObject) if not OV.HasGUI(): return import gui.tools RunPrgObject.post_prg_output_html_message = "Ralpha=%s, Nqual=%s, CFOM=%s" %(RunPrgObject.Ralpha,RunPrgObject.Nqual,RunPrgObject.CFOM) if OV.GetParam('user.solution.run_auto_vss'): RunPrgObject.please_run_auto_vss = True def get_XS_TREF_solution_indicators(self, RunPrgObject): """Gets the TREF solution indicators from the .lst file and prints values in Olex2. """ lstPath = "%s/%s.lst" %(OV.FilePath(), OV.FileName()) if os.path.exists(lstPath): import lst_reader lstValues = lst_reader.reader(path=lstPath).values() RunPrgObject.Ralpha = lstValues.get('Ralpha','') RunPrgObject.Nqual = lstValues.get('Nqual','') RunPrgObject.CFOM = lstValues.get('CFOM','') class Method_shelxd(Method_shelx_solution): def calculate_defaults(self): """Defines controls in Olex2 for each argument in self.args and then calculates sensible default values for PLOP and FIND based on the cell volume. """ Method.calculate_defaults(self) # Define controls in Olex2 #volume = float(olex.f("Cell(volume)")) volume = float(olx.xf.au.GetCellVolume()) n = int(volume/18) * 0.7 nmin = int(n * 0.8) nmid = int(n * 1.2) nmax = int(n * 1.4) try: OV.SetVar('settings_find_na', nmin) OV.SetVar('settings_plop_a', nmin) OV.SetVar('settings_plop_b', nmid) OV.SetVar('settings_plop_c', nmax) except: pass def extraHtml(self): """Makes the HTML for a button to interrupt ShelXD. """ import htmlTools button_d = { 'name':'STOP_DUAL_SPACE', 'value':'STOP', 'width':50, 'height':28, 'onclick':r'spy.stopProcess()', } button_html = htmlTools.make_input_button(button_d) html = ''' %s%s ''' %(htmlTools.make_table_first_col(), button_html) return html def pre_solution(self, RunPrgObject): args = Method_shelx_solution.pre_solution(self, RunPrgObject) volume = float(olx.xf.au.GetCellVolume()) n = int(volume/18) * 0.7 nmin = int(n * 0.8) nmax = int(n * 1.2) nmaxx = int(n * 1.4) if 'FIND' not in args: args += 'FIND %i\n' %nmin if 'PLOP' not in args: args += 'PLOP %i %i %i\n' %(nmin, nmax, nmaxx) if 'MIND' not in args: args += 'MIND 1 -0.1\n' if 'NTRY' not in args: args += 'NTRY 100\n' return args def do_run(self, RunPrgObject): """Makes Olex listen to the temporary directory before running the executable so that intermediate solutions will be displayed onscreen. """ listen_file = '%s/%s.res' %(RunPrgObject.tempPath,RunPrgObject.hkl_src_name) OV.Listen(listen_file) Method_shelx_solution.do_run(self, RunPrgObject) def post_solution(self, RunPrgObject): """Stops listening to the temporary directory """ olex.m("stop listen") Method_shelx_solution.post_solution(self, RunPrgObject) for i in range(int(olx.xf.au.GetAtomCount())): olx.xf.au.SetAtomU(i, "0.06") shelxs_phil_str = """ esel .optional=True { values { Emin=1.2 .type=float Emax=5 .type=float dU=0.05 .type=float renorm=.7 .type=float axis=0 .type=int } default=False .type=bool } egen .optional=True { values { d_min=None .type=float d_max=None .type=float } default=False .type=bool } grid .optional=True { values { sl=None .type=float sa=None .type=float sd=None .type=float dl=None .type=float da=None .type=float dd=None .type=float } default=False .type=bool } command_line .optional=False .caption='Command line' { values { Options='' .type=str } default=True .type=bool } """ direct_methods_phil = phil_interface.parse(""" name = 'Direct Methods' .type=str display = 'Direct' .type=str atom_sites_solution=direct .type=str instructions { tref { values { np = 500 .type=int nE = None .type=int kapscal = None .type=float ntan = None .type=int wn = None .type=float } default = True .type=bool } init .optional=True { values { nn=None .type=int nf=None .type=int s_plus=0.8 .type=float s_minus=0.2 .type=float wr=0.2 .type=float } default = False .type=bool } phan .optional=True { values { steps = 10 .type=int cool = 0.9 .type=float Boltz = None .type=float ns = None .type=int mtpr = 40 .type=int mnqr = 10 .type=int } default = False .type=bool } %s } """ %shelxs_phil_str, process_includes=True) shelxt_phil_str = phil_interface.parse(""" name = 'Intrinsic Phasing' .type=str display = 'Intrinsic Phasing' .type=str atom_sites_solution=dual .type=str instructions { command_line .optional=False .caption='Command line' { values { Options='' .type=str } default=True .type=bool } } """, process_includes=True) patterson_phil = phil_interface.parse(""" name = 'Patterson Method' .type=str display = 'Patterson' .type=str atom_sites_solution=heavy .type=str instructions { patt { values { nv=None .type=int dmin=None .type=float resl=None .type=float Nsup=None .type=int Zmin=None .type=int maxat=None .type=int } default=True .type=bool } vect .optional=True { values { X=None .type=float Y=None .type=float Z=None .type=float } default=False .type=bool } %s } """ %shelxs_phil_str, process_includes=True) #TEXP na [#] nH [0] Ek [1.5] texp_phil = phil_interface.parse(""" name = 'Structure Expansion' .type=str display = 'Structure Expansion' .type=str atom_sites_solution=heavy .type=str instructions { texp { values { na=1 .type=int nH=1 .type=int Ek=1.5 .type=float } default=True .type=bool } tref .optional=True { values { np = 500 .type=int nE = None .type=int kapscal = None .type=float ntan = None .type=int wn = None .type=float } default=False .type=bool } esel .optional=True { values { Emin=1.2 .type=float Emax=5 .type=float dU=0.05 .type=float renorm=.7 .type=float axis=0 .type=int } default=False .type=bool } command_line .optional=False .caption='Command line' { values { Options='' .type=str } default=True .type=bool } } """, process_includes=True) dual_space_phil = phil_interface.parse(""" name = 'Dual Space' .type=str display = 'Dual Space' .type=str atom_sites_solution=dual .type=str instructions { ntry .optional=True { values { ntry=100 .type=int } default=True .type=bool } find .optional=True { values { na=0 .type=int ncy=None .type=int } default=True .type=bool } mind .optional=True { values { mdis=1.0 .type=float mdeq=2.2 .type=float } default=True .type=bool } plop .optional=True { values { a=None .type=int .caption=1 b=None .type=int .caption=2 c=None .type=int .caption=3 d=None .type=int .caption=4 e=None .type=int .caption=5 f=None .type=int .caption=6 g=None .type=int .caption=7 h=None .type=int .caption=8 i=None .type=int .caption=9 j=None .type=int .caption=10 } default=True .type=bool } command_line .optional=False .caption='Command line' { values { Options='' .type=str } default=True .type=bool } } """) shelxl_phil_str = """ plan .optional=True { values { npeaks=20 .type=int d1=None .type=float d2=None .type=float } default=True .type=bool } fmap .optional=True { values { code=2 .type=int axis=None .type=int(value_min=1, value_max=3) nl=53 .type=int } default=True .type=bool } temp .optional=True { values { T=None .type=int } default=False .type=bool } command_line .optional=False .caption='Command line' { values { Options='' .type=str } default=True .type=bool } """ def get_LS_phil(): return phil_interface.parse(""" name = 'Least Squares' .type=str display = "L.S." .type=str instructions { ls .caption = 'L.S.' { name='L.S.' .type=str values { nls=4 .type=int nrf=0 .type=int nextra=0 .type=int } default=True .type=bool } %s acta .optional=True { values { two_theta_full=None .caption=2thetafull .type=float } default=False .type=bool } } """ %shelxl_phil_str, process_includes=True) def get_CGLS_phil(): return phil_interface.parse(""" name = CGLS .type=str display = CGLS .type=str instructions { cgls { values { nls=4 .type=int nrf=0 .type=int nextra=0 .type=int } default=True .type=bool } %s } """ %shelxl_phil_str, process_includes=True) def post_solution_html(d): if not OV.HasGUI(): return import gui.tools debug = OV.IsDebugging() t = gui.tools.TemplateProvider.get_template('program_output', force=debug)%d f_name = OV.FileName() + "_solution_output.html" OlexVFS.write_to_olex(f_name, t) olx.html.Update()