import shutil import olex import olex_fs import glob import olx import os import time import math import re import olex_core import sys import programSettings from subprocess import * import gui import htmlTools import HttpTools global _is_online _is_online = False import History import ExternalPrgParameters SPD, RPD = ExternalPrgParameters.get_program_dictionaries() from olexFunctions import OV import variableFunctions import MakeMovie import OlexVFS import threads_imp as olxth global cache cache = {} haveGUI = OV.HasGUI() if haveGUI: import olex_gui import Report import random def txt(): try: import uuid # This creates a custom unique filename determined by the the currently loaded in url output_file_name = "%s.txt"%uuid.uuid3(uuid.NAMESPACE_OID, '%s'%str(OV.FileFull())) # This is passed to the altered version of text creating the custom log instead of output.txt # Change: #  $spy.MakeHoverButton(toolbar-text, 'Text') to #  $spy.MakeHoverButton(toolbar-text, 'spy.txt\()') # in gui/blocks/snum-info.txt to make it default olx.Text(output_file_name) except ImportError as err: print("Could not initialise spy.txt() function: %s" %err) OV.registerFunction(txt) def expand(start, finish, increment=1): """ expand creates returns a list based on start, finish and increment So C1, C6 would produce: C1 C2 C3 C4 C5 C6 """ import string start_atom = str(start).translate(None, string.digits).lower() start_number = int(str(start).translate(None, string.ascii_letters)) finish_atom = str(finish).translate(None, string.digits).lower() finish_number = int(str(finish).translate(None, string.ascii_letters)) if (finish_atom != start_atom) or (start_number == finish_number): print("The start and end element types must be the same and the numbers different") return return_string = [] for x in range(start_number, finish_number+1, int(increment)): return_string.append('%s%d'%(start_atom,x)) return ' '.join(return_string) OV.registerFunction(expand) if __debug__: #gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS) #gc.set_debug(gc.DEBUG_STATS) #gc.set_debug(gc.DEBUG_SAVEALL | gc.DEBUG_STATS) def dump(): #a = gc.get_threshold() dump_garbage() #a = gc.garbage #b = gc.collect() OV.registerFunction(dump) def collect(generation=None): print(gc.get_count()) if generation != None: a = gc.collect(generation) else: a = gc.collect() print("%s garbage items collected" %a) OV.registerFunction(collect) def getObjectCount(): #a = gc.get_objects() a = get_all_objects() #a = [] print("Number of objects: %s" %len(a)) #print a[0] #print a[50] #print a[-10] #print "\n\n" a = [] gc.collect() return '' OV.registerFunction(getObjectCount) def dump_garbage(): """ show us what's the garbage about """ # force collection print("\nGARBAGE:") a = gc.collect() print("%s objects collected" %a) print("\nGARBAGE OBJECTS:") for x in gc.garbage: s = str(x) if len(s) > 80: s = s[:80] print(type(x),"\n ", s) if type(x).__name__ == 'function': print(x.__code__) #print x.func_name print('Size of garbage is: ',len(gc.garbage)) # Recursively expand slist's objects # into olist, using seen to track # already processed objects. def _getr(slist, olist, seen): for e in slist: if id(e) in seen: continue seen[id(e)] = None olist.append(e) tl = gc.get_referents(e) if tl: _getr(tl, olist, seen) # The public function. def get_all_objects(): """Return a list of all live Python objects, not including the list itself.""" gcl = gc.get_objects() olist = [] seen = {} # Just in case: seen[id(gcl)] = None seen[id(olist)] = None seen[id(seen)] = None # _getr does the real work. _getr(gcl, olist, seen) return olist # -*- Mode: Python; tab-width: 4 -*- import types def get_refcounts(): d = {} sys.modules # collect all classes for m in list(sys.modules.values()): for sym in dir(m): o = getattr (m, sym) if type(o) is type: d[o] = sys.getrefcount (o) # sort by refcount pairs = [(x[1],x[0]) for x in list(d.items())] pairs.sort() pairs.reverse() return pairs def print_top_100(): for n, c in get_refcounts()[:100]: print('%10d %s' % (n, c.__name__)) OV.registerFunction(print_top_100) #if headless: #from olexexc import * #else: #from olexexh import * #GuiFunctions.registerFunctions() class SpyVar(object): MatchedFragments = {} MatchedRms = [] class OlexRefinementModel(object): restraint_types = { 'dfix':'bond', 'dang':'bond', 'flat':'planarity', 'chiv':'chirality', 'sadi':'bond_similarity', 'simu':'adp_similarity', 'delu':'rigid_bond', 'rigu':'rigu', 'isor':'isotropic_adp', 'olex2.restraint.angle':'angle', 'olex2.restraint.dihedral':'dihedral', 'olex2.restraint.adp_u_eq':'fixed_u_eq_adp', 'olex2.restraint.adp_u_eq_similar':'adp_u_eq_similarity', 'olex2.restraint.adp_volume_similar':'adp_volume_similarity', } constraint_types = { 'eadp':'adp', 'exyz':'site', } def is_adp_restraint(self, r): return r in ( 'adp_similarity', 'adp_u_eq_similarity', 'adp_volume_similarity', 'rigid_bond', 'rigu', 'isotropic_adp', 'fixed_u_eq_adp') # restraint -> group of, min groups geom_restraints = { 'bond': (2, 1), 'bond_similarity': (2, 2), 'angle': (3, 1), 'dihedral': (4, 1), 'planarity': (4, 1), 'chirality': (4, 1), } def is_valid_geom(self, atoms, redundant_xyz, fixed_xyz): atom_set = {a[0] for a in atoms} atom_cnt = len(atoms) for r in redundant_xyz: ra = atom_set & r if ra: if len(ra) == atom_cnt: # all represent the same atom return False break return len(atom_set & fixed_xyz) < atom_cnt adp_constraints = {'eadp', 'olex2.constraint.rotating_adp', 'olex2.constraint.rotated_adp'} def __init__(self, need_connectivity=True): olex_refinement_model = OV.GetRefinementModel(need_connectivity) self._atoms = [] self._fixed_variables = {} self.atom_ids = [] asu = olex_refinement_model['aunit'] for residue in asu['residues']: for atom in residue['atoms']: self._atoms.append(atom) if residue['class'] != 'default': chainId = residue['chainId'] if chainId != '~': nl = "%s:%s_%s" %(chainId, atom['label'], residue['number']) else: nl = "%s_%s" %(atom['label'], residue['number']) atom['label'] = nl self.atom_ids.append(atom['aunit_id']) vars = olex_refinement_model['variables']['variables'] if len(vars) > 0: for var in vars[0]['references']: self._fixed_variables.setdefault(var['id'], []) self._fixed_variables[var['id']].append(var) self._cell = olex_refinement_model['aunit']['cell'] self.exptl = olex_refinement_model['exptl'] self._afix = olex_refinement_model['afix'] self.model= olex_refinement_model def atoms(self): return self._atoms def disorder_parts(self): return [atom['part'] for atom in self._atoms] #evaluates unique types, using charges if needed def get_unique_types(self, use_charges=False): rv = set() for a in self._atoms: et = str(a['type']) if use_charges: charge = a['charge'] if charge > 0: et = et + '+' if charge < 0: et = et + '-' if abs(charge) > 1: et += str(abs(charge)) rv.add(et) return rv def iterator(self, use_charges=False): for i, atom in enumerate(self._atoms): name = str(atom['label']) element_type = str(atom['type']) if use_charges: charge = atom['charge'] if charge > 0: element_type += '+' if charge < 0: element_type += '-' if abs(charge) > 1: element_type += str(abs(charge)) xyz = atom['crd'][0] occu = atom['occu'][0] adp = atom.get('adp') anharmonic_adp = atom.get('anharmonic_adp') if adp is None: uiso = atom.get('uiso')[0] u = (uiso,) else: u = adp[0] uiso_owner = atom.get('uisoOwner') if name[:1] != "Q": yield name, xyz, occu, u, anharmonic_adp, uiso_owner, element_type, self._fixed_variables.get(i) def disp_iterator(self): for i, atom in enumerate(self._atoms): disp = atom.get('disp', None) if disp: yield i, disp def afix_iterator(self): for afix in self._afix: mn = afix['afix'] m, n = divmod(mn, 10) pivot = afix['pivot'] dependent = afix['dependent'] pivot_neighbours = [ i for i in self._atoms[pivot]['neighbours'] if not i in dependent] if len(dependent) == 0: continue dependent_part = self._atoms[dependent[0]]['part'] #pivot_neighbours = None bond_length = afix['d'] uiso = afix['u'] yield m, n, pivot, dependent, pivot_neighbours, bond_length def restraints_iterator(self, pair_sym_table=None, shared_parameters=None): from libtbx.utils import flat_list from cctbx import sgtbx from smtbx.refinement.constraints import adp, site redundant_adp, redundant_xyz = {}, [] fixed_adp = [] # fixed or constrained fixed_xyz = set() adp_atoms = set() for i, a in enumerate(self._atoms): behaviour_of_variable = [True]*12 fixed_vars = self._fixed_variables.get(i) if fixed_vars is not None: for var in fixed_vars: behaviour_of_variable[var['index']] = False if not all(behaviour_of_variable[:3]): fixed_xyz.add(i) if not all(behaviour_of_variable[-6:]): fixed_adp.append(i) if a.get('adp') != None: adp_atoms.add(i) for adp_constraint in (self.adp_constraints): for constraint in self.model[adp_constraint]: if adp_constraint.startswith('olex2'): fixed_adp.append(constraint[0]) fixed_adp.append(constraint[1]) else: for i in constraint['atoms']: fixed_adp.append(i[1]) if shared_parameters: # filter out shared ADP for sp in shared_parameters: if isinstance(sp, adp.shared_u): for i in sp.indices[1:]: redundant_adp[i] = sp.indices[0] elif isinstance(sp, site.shared_site): al = None for i in sp.indices: for v in redundant_xyz: if i in v: al = v break if al: break if al: al += sp.indices else: redundant_xyz.append(set(sp.indices)) # for k,v in redundant_adp.items(): # if v in redundant_adp: # raise Exception("Cyclic constraint located for: %s and %s" \ # %(self._atoms[k]['label'], self._atoms[v]['label'])) for shelxl_restraint in self.restraint_types: restraints = self.model.get(shelxl_restraint, ()) restrained_set = set() filtered_restraints = [] for restraint in restraints: restraint_type = self.restraint_types[shelxl_restraint] if self.is_adp_restraint(restraint_type): i_seqs = [i[0] for i in restraint['atoms']] if not i_seqs: if restrained_set: i_seqs = adp_atoms - restrained_set - set(fixed_adp) if not i_seqs: continue restraint['atoms'] = [(x, None) for x in i_seqs] elif fixed_adp: all_atoms = adp_atoms - set(fixed_adp) if not all_atoms: continue restraint['atoms'] = [(x, None) for x in all_atoms] filtered_restraints.append(restraint) break else: new_i_seqs = [x for x in i_seqs if x not in restrained_set and x not in fixed_adp] if not new_i_seqs: continue restrained_set.update(new_i_seqs) restraint['atoms'] = [(x, None) for x in new_i_seqs] filtered_restraints.append(restraint) else: filtered_restraints.append(restraint) for restraint in filtered_restraints: restraint_type = self.restraint_types.get(shelxl_restraint) if restraint_type is None: continue i_seqs = [i[0] for i in restraint['atoms']] kwds = dict(i_seqs=i_seqs) if not self.is_adp_restraint(restraint_type) and restraint_type not in self.adp_constraints: restrain_def = self.geom_restraints.get(restraint_type) ac = len(restraint['atoms']) st = 0 filtered_atoms, distilled_atoms = [], [] while ac > 0: ga = restraint['atoms'][st:st+restrain_def[0]] if self.is_valid_geom(ga, redundant_xyz, fixed_xyz): filtered_atoms += ga else: distilled_atoms += ga st += restrain_def[0] ac -= restrain_def[0] if len(filtered_atoms) < restrain_def[0] * restrain_def[1]: if OV.IsDebugging(): print("Skipping geometrical restraint (all atoms have fixed coordinates): %s %s" %( restraint_type, " ".join([self._atoms[i[0]]['label'] for i in restraint['atoms']]))) continue elif distilled_atoms: if OV.IsDebugging(): print("Skipping %s in: %s %s" %( " ".join([self._atoms[i[0]]['label'] for i in distilled_atoms]), restraint_type, " ".join([self._atoms[i[0]]['label'] for i in restraint['atoms']]))) kwds['sym_ops'] = [ (sgtbx.rt_mx(flat_list(i[1][:-1]), i[1][-1]) if i[1] is not None else None) for i in filtered_atoms] if restraint_type in ('angle', 'dihedral'): esd_val = restraint['esd1']*180/math.pi else: esd_val = restraint['esd1'] kwds['weight'] = 1/math.pow(esd_val,2) elif redundant_adp: # filter out shared ADP i_seqs = [redundant_adp.get(i, i) for i in i_seqs] kwds['i_seqs'] =list(set(i_seqs)) value = restraint['value'] if restraint_type in ('adp_similarity', 'adp_u_eq_similarity', 'adp_volume_similarity', 'isotropic_adp', 'fixed_u_eq_adp'): kwds['sigma'] = restraint['esd1'] if restraint_type in ('adp_similarity', 'isotropic_adp'): kwds['sigma_terminal'] = restraint['esd2'] if restraint['esd2'] != 0 else None elif restraint_type == 'rigid_bond': kwds['sigma_12'] = restraint['esd1'] kwds['sigma_13'] = restraint['esd2'] if restraint['esd2'] != 0 else None elif restraint_type == 'rigu': kwds['sigma_12'] = restraint['esd1'] kwds['sigma_13'] = restraint['esd2'] if restraint['esd2'] != 0 else None if restraint_type == 'bond': kwds['distance_ideal'] = value elif restraint_type in ('angle', 'dihedral'): kwds['angle_ideal'] = value elif restraint_type == 'chirality': kwds['volume_ideal'] = value elif restraint_type in ('fixed_u_eq_adp',): kwds['u_eq_ideal'] = value elif restraint_type in ('bond_similarity'): kwds['weights'] = [kwds['weight']]*len(i_seqs) if restraint_type == 'bond_similarity': sym_ops = kwds['sym_ops'] kwds['i_seqs'] = [[i_seq for i_seq in i_seqs[i*2:(i+1)*2]] for i in range(int(len(i_seqs)/2))] kwds['sym_ops'] = [[sym_op for sym_op in sym_ops[i*2:(i+1)*2]] for i in range(int(len(sym_ops)/2))] if restraint_type in ('adp_similarity', 'isotropic_adp', 'rigid_bond', 'rigu'): kwds['connectivity'] = pair_sym_table.full_simple_connectivity() if 'weights' in kwds: del kwds['weight'] if restraint_type in ('bond', ): for i in range(int(len(i_seqs)/2)): yield restraint_type, dict( weight=kwds['weight'], distance_ideal=kwds['distance_ideal'], i_seqs=kwds['i_seqs'][i*2:(i+1)*2], sym_ops=kwds['sym_ops'][i*2:(i+1)*2]) elif restraint_type in ('angle', ): for i in range(int(len(i_seqs)/3)): yield restraint_type, dict( weight=kwds['weight'], angle_ideal=kwds['angle_ideal'], i_seqs=kwds['i_seqs'][i*3:(i+1)*3], sym_ops=kwds['sym_ops'][i*3:(i+1)*3]) elif restraint_type in ('dihedral', ): for i in range(int(len(i_seqs)/4)): yield restraint_type, dict( weight=kwds['weight'], angle_ideal=kwds['angle_ideal'], i_seqs=kwds['i_seqs'][i*4:(i+1)*4], sym_ops=kwds['sym_ops'][i*4:(i+1)*4]) elif restraint_type == 'chirality': # Expand each atom in the list to include the 3 neighbours for atom_restraint in restraint['atoms']: i_seqs = [] sym_ops = [] # looking for the pivot atom in the model atom = self._atoms[atom_restraint[0]] i_seqs.append(atom_restraint[0]) sym_ops.append( (sgtbx.rt_mx(flat_list(atom_restraint[1][:-1]), atom_restraint[1][-1]) if atom_restraint[1] is not None else None) ) pivot_name = atom['label'] # if symmetry related we have a tuple, not an int for neighbour in atom['neighbours']: if(type(neighbour)==type(())): neighbour_id=neighbour[0] else: neighbour_id=neighbour # now finding the type of the neighbour atombis = self._atoms[neighbour_id] if(atombis['type']!='H'): # only non hydrogen atom are considered i_seqs.append(neighbour_id) if(type(neighbour)==type(())): sym_ops.append( (sgtbx.rt_mx(flat_list(neighbour[2][:-1]), neighbour[2][-1])) ) else: sym_ops.append(None) if(len(i_seqs)==4): yield restraint_type, dict( i_seqs=i_seqs, sym_ops=sym_ops, volume_ideal=-1.0*kwds['volume_ideal'], # cctbx has opposite site compare to shelxl both_signs=False, weight=kwds['weight'], ) else: print("Warning: Invalid chirality (CHIV) restraint. "+ "%s needs exactly 3 neighbours"%pivot_name) # end loop over each atom of chiv restraint elif restraint_type == 'planarity': # The planarity restraint is implemented using the CHIV restraint # len(i_seqs)-3 CHIV restraints are necessary and used # list of atom often is ordered, shuffle the list to give a random set of tetrahedron # this step is not done in shelx shuffle_ids=[i for i in range(len(i_seqs))] random.seed('Use of a fixed seed for a consistent set of indices') random.shuffle(shuffle_ids) for i in range(len(i_seqs)-3): yield 'chirality', dict( i_seqs=[i_seqs[j] for j in shuffle_ids[i:i+4]], sym_ops=[kwds['sym_ops'][j] for j in shuffle_ids[i:i+4]], volume_ideal=0.0, both_signs=False, weight=kwds['weight'], ) else: yield restraint_type, kwds def same_iterator(self): groups = self.model.get('same', None) if not groups: return for group in groups: dependent = group['dependent'] if not dependent: continue # build 12 and 13 distances dis12 = set() dis13 = set() group_atoms = [x[0] for x in group['atoms']] idx_map = {} for idx, a_id in enumerate(group_atoms): idx_map[a_id] = idx for b_id in self._atoms[a_id]['neighbours']: # consider only AU atoms and inside the group if isinstance(b_id, tuple) or b_id not in group_atoms: continue if a_id > b_id: dis12.add((b_id, a_id)) else: dis12.add((a_id, b_id)) for c_id in self._atoms[b_id]['neighbours']: if isinstance(c_id, tuple) or c_id not in group_atoms or\ c_id == a_id or c_id == b_id: continue if a_id > c_id: dis13.add((c_id, a_id)) else: dis13.add((a_id, c_id)) for a_id, b_id in dis12: i_seqs = [[a_id, b_id]] for dependent_group in dependent: dependent_atoms = [x[0] for x in groups[dependent_group]['atoms']] i_seqs.append([dependent_atoms[idx_map[a_id]], dependent_atoms[idx_map[b_id]]]) kwds = {'i_seqs': i_seqs, 'weights': [1/math.pow(groups[dependent_group]['esd12'],2)]*len(i_seqs)} yield 'bond_similarity', kwds for a_id, b_id in dis13: i_seqs = [[a_id, b_id]] for dependent_group in dependent: dependent_atoms = [x[0] for x in groups[dependent_group]['atoms']] i_seqs.append([dependent_atoms[idx_map[a_id]], dependent_atoms[idx_map[b_id]]]) kwds = {'i_seqs': i_seqs, 'weights': [1/math.pow(groups[dependent_group]['esd13'],2)]*len(i_seqs)} yield 'bond_similarity', kwds def constraints_iterator(self): for shelxl_constraint in (self.constraint_types): for constraint in self.model[shelxl_constraint]: constraint_type = self.constraint_types.get(shelxl_constraint) if constraint_type is None: continue if constraint_type == "adp": i_seqs = [i[0] for i in constraint['atoms']] kwds = dict(i_seqs=i_seqs) else: kwds = {"i_seqs": constraint} yield constraint_type, kwds def getCell(self): return [self._cell[param][0] for param in ('a','b','c','alpha','beta','gamma')] def getCellErrors(self): return [self._cell[param][1] for param in ('a','b','c','alpha','beta','gamma')] def numberAtoms(self): return sum(atom['occu'][0] for atom in self.atoms()) def number_non_hydrogen_atoms(self): return sum(atom['occu'][0] for atom in self.atoms() if atom['type'] not in ('H','Q')) def currentFormula(self): curr_form = {} for atom in self.atoms(): atom_type = atom['type'] atom_occu = atom['occu'][0] curr_form.setdefault(atom_type, 0) curr_form[atom_type] += atom_occu return curr_form def getExpectedPeaks_and_AtomsPresent(self): cell_volume = float(olx.xf.au.GetAUVolume()) expected_atoms = cell_volume/17 present_atoms = self.number_non_hydrogen_atoms() expected_peaks = expected_atoms - present_atoms return int(round(expected_peaks)), int(round(present_atoms)) def getExpectedPeaks(self): return self.getExpectedPeaks_and_AtomsPresent()[0] def get_refine_ls_hydrogen_treatment(): afixes_present = [] afixes = {0:'refall', 1:'noref', 2:'refxyz', 3:'constr', 4:'constr', 5:'constr', 7:'constr', 8:'constr', } for atom in OlexRefinementModel().atoms(): if atom['type'] == 'H': afix = atom['afix'] n = int(afix[-1]) if len(afix) > 1: m = int(afix[:-1]) else: m = 0 if not afixes[n] in afixes_present: afixes_present.append(afixes[n]) if len(afixes_present) == 0: return 'undef' elif len(afixes_present) == 1: return afixes_present[0] else: return 'mixed' OV.registerFunction(get_refine_ls_hydrogen_treatment) def OnMatchStart(argStr): OV.write_to_olex('match.htm', "RMS (Å) Matched Fragments
") SpyVar.MatchedFragments = {} SpyVar.MatchedRms = [] return "" if haveGUI: OV.registerCallback('startmatch',OnMatchStart) def OnMatchFound(rms, fragA, fragB): import string fragA = "'%s'" %fragA.replace(",", " ") fragB = "'%s'" %fragB.replace(",", " ") fragL = string.ascii_uppercase if len(SpyVar.MatchedFragments) > 16: return if fragA not in SpyVar.MatchedFragments: idA = fragL[len(SpyVar.MatchedFragments)] SpyVar.MatchedFragments.setdefault(fragA, {'fragID':idA}) else: idA = SpyVar.MatchedFragments[fragA].get('fragID') if fragB not in SpyVar.MatchedFragments: idB = fragL[len(SpyVar.MatchedFragments)] SpyVar.MatchedFragments.setdefault(fragB, {'fragID':idB}) else: idB = SpyVar.MatchedFragments[fragB].get('fragID') rms = float(rms) SpyVar.MatchedRms.append(rms) outStr = "" try: outStr += olex.readImage('match.htm') except: pass outStr+='' if rms < 0.2: outStr += '%.4f ' %(rms) elif rms < 1: outStr += '%.4f ' %(rms) elif rms < 2: outStr += '%.4f ' %(rms) else: outStr += '%.4f ' %(rms) outStr+=' %s ' %(fragA, idA) outStr+='%s ' %(fragB, idB) outStr+="
" OV.write_to_olex('match.htm',outStr) if haveGUI: OV.registerCallback('onmatch',OnMatchFound) def SetFormulaFromInput(): formula = OV.GetControlValue('SET_FORMULA') if not formula: return f = formula.split() Z = float(olx.xf.au.GetZ()) argStr = "" for element in f: try: n = int(element[1:])*Z el = element[:1] except: n = int(element[2:])*Z el = element[:2] argStr += "%s:%i," %(el, n) argStr = argStr.strip(',') argStr = "'%s'" %argStr olx.xf.SetFormula(argStr) return "" if haveGUI: OV.registerFunction(SetFormulaFromInput) def ChooseLabelContent(cmd): x = dict([(k, True) for k in cmd.split()]) if olx.GetVar('olex2.label_h', 'false') == 'true': if not x: x['l'] = True x['h'] = True if olx.GetVar('olex2.label_i', 'false') == 'true': if not x: x['l'] = True x['i'] = True olx.Labels(**x) OV.registerFunction(ChooseLabelContent) def FindZOfHeaviestAtomInFormula(): from PeriodicTable import PT retVal = 0 pt = PT.PeriodicTable() f = olx.xf.GetFormula('list') if not f: return retVal f = f.split(',') largestZ = 0 largestEle = "" for element in f: ele = element.split(":")[0] Z = int(pt[ele].get('Z')) if Z > largestZ: largestZ = Z largestEle = ele retVal = (largestZ,largestEle) return retVal OV.registerFunction(FindZOfHeaviestAtomInFormula) def get_auto_q_peaks(): ctrl_name = 'SET_SNUM_REFINEMENT_MAX_PEAKS' manual_q = OV.GetParam('snum.refinement.manual_q_peak_override',0) if manual_q: if OV.IsControl(ctrl_name): OV.SetControlBG(ctrl_name,'#ffeeee', check=False) OV.SetControlValue(ctrl_name,manual_q, check=False) return manual_q heavy = OlexRefinementModel().getExpectedPeaks() if heavy <= 0: heavy = 0 else: heavy += int(round(heavy*0.2)) hydrogen = int(olx.HAddCount()) q = heavy + hydrogen if q == 0: q = 5 OV.SetVar('auto_q',q) return q def FindZOfHeaviestAtomInFormua(): #for compatibility of old AC versions return FindZOfHeaviestAtomInFormula() def SetAtomicVolumeInSnumPhil(totalcount): cell_volume = 0 Z = 1 Z_prime = float(olx.xf.au.GetZprime()) try: cell_volume = float(olx.xf.au.GetCellVolume()) except: pass try: Z = float(olx.xf.au.GetZ()) except: pass if cell_volume and totalcount: atomic_volume = (cell_volume)/(totalcount * Z) OV.SetParam('snum.solution.current_atomic_volume','%.1f' %atomic_volume) else: OV.SetParam('snum.solution.current_atomic_volume',None) def GetHklFileList(): reflection_file_extensions = ["hkl", "hkp", "raw", 'hklf5', 'hkc'] g = OV.ListFiles(OV.FilePath(), ';'.join(reflection_file_extensions)) g.sort() try: a = OV.HKLSrc() if a and (a[0] == "'" or a[0] == '"'): a = a[1:-1] except: a = "" if not os.path.exists(a) and not g: print("There is no reflection file or the reflection file is not accessible") reflection_files = [] file_names = set() for item in g: fn = OV.FileName(item) file_names.add(fn) reflection_files.append("%s.%s<-%s" %(fn, OV.FileExt(item), item)) history_hkl = os.path.join(OV.StrDir(), "history.hkl") if a: if a == history_hkl: reflection_files.insert(0, "Reverted from History<-%s" %(a)) elif a not in g: reflection_files.insert(0, "%s<-%s" %( (a[:15] + '..' + a[-15:]) if len(a) > 30 else a, a)) elif len(reflection_files) > 1 and OV.FileName() not in file_names: reflection_files.insert(0, "None<-") return ';'.join(reflection_files) def GetHklFileValue(): try: a = OV.HKLSrc() if not a: return "" history_hkl = os.path.join(OV.StrDir(), "history.hkl") if a == history_hkl: return "Reverted from History" path_toks = os.path.split(a) if OV.FilePath() == path_toks[0]: return path_toks[1] return (a[:15] + '..' + a[-15:]) if len(a) > 30 else a except: return "" if haveGUI: OV.registerFunction(GetHklFileList) OV.registerFunction(GetHklFileValue) def GetRcolour(R1): retVal = "" try: R1 = float(R1) if R1 > 0.20: if OV.HasGUI(): retVal=OV.GetParam('gui.red') else: retVal="#b40000" elif R1 >0.10: if OV.HasGUI(): retVal=OV.GetParam('gui.orange') else: retVal="#ff8f00" else: if OV.HasGUI(): retVal=OV.GetParam('gui.green') else: retVal = "#00b400" except: retVal='grey' return str(retVal) def setMainToolbarTabButtons(btn, state=""): isCif = OV.IsFileType('cif') if isCif and btn != 'report': state = 'inactive' btns = [("solve", "solution-settings"), ("refine", "refinement-settings"), ("report","report-settings")] for item in btns: if item[0] == btn: if not state: state = OV.GetItemState(item[1]) if state == '-1': state = "off" elif state == '0': state = "on" #OV.CopyVFSFile("cbtn-%s2%s.png" %(item[0],state),"cbtn-%s2.png" %item[0]) OV.SetImage("IMG_CBTN-%s2" %btn.upper(),"cbtn-%s2%s.png" %(item[0], state)) OV.SetImage("IMG_BTN-%s2" %btn.upper(),"btn-%s2%s.png" %(item[0], state)) OV.SetVar('gui_MainToolbarTabButtonActive',btn) elif state != 'inactive' and not isCif: OV.CopyVFSFile("cbtn-%s2off.png" %item[0],"cbtn-%s2.png" %item[0]) return "Done" if haveGUI: OV.registerFunction(setMainToolbarTabButtons) def setAllMainToolbarTabButtons(): isCif = OV.IsFileType('cif') btns = [("solve", "solution-settings"), ("refine", "refinement-settings"), ("report","report-settings")] for item in btns: btn = item[0] if isCif and btn != 'report': state = 'inactive' if OV.IsHtmlItem(item[1]) == 'true': OV.SetItemState(item[1],'-1') else: state = '' #state = 'off' if not state: #if OV.IsControl(item[1]): if OV.IsHtmlItem(item[1]) == 'true': try: state = OV.GetItemState(item[1]) except RuntimeError: pass if state == '-1': state = "off" elif state == '0': state = "on" elif state == '1': state = "off" else: state = 'off' #try: #OV.CopyVFSFile("cbtn-%s%s.png" %(btn,state),"cbtn-%s.png" %btn) #except: #olex.m('skin default_new') if state == 'on': OV.SetVar('gui_MainToolbarTabButtonActive',btn) return "Done" if haveGUI: OV.registerFunction(setAllMainToolbarTabButtons) def onRefinementProgramChange(prg_name, method=None, scope='snum'): if prg_name == 'Auto': OV.SetParam('%s.refinement.method' %scope, 'Auto') return prg = RPD.programs[prg_name] if not method: method = sortDefaultMethod(prg) if not OV.IsFileType('cif'): if method == 'Least Squares' and olx.LSM() == 'CGLS': method = 'CGLS' # work-around for bug #26 OV.SetParam("%s.refinement.program" %scope, prg_name) OV.SetParam('user.refinement.default_program', prg_name) OV.SetParam("%s.refinement.method" %scope, method) onRefinementMethodChange(prg_name, method) def onRefinementMethodChange(prg_name, method): if method in RPD.programs[prg_name].methods: programSettings.doProgramSettings(prg_name, method) OV.SetParam('user.refinement.default_method', method) else: print("Please choose a valid method for the refinement program %s" %prg_name) OV.registerFunction(onRefinementMethodChange) def onSolutionProgramChange(prg_name, method=None, scope='snum'): if prg_name == "Auto": OV.SetParam('%s.solution.method' %scope, 'Auto') return if prg_name != 'Unknown': prg = SPD.programs[prg_name] if method is None or not method: method = sortDefaultMethod(prg) if method == 'Direct Methods' and olx.Ins('PATT') != 'n/a': method = 'Patterson Method' # work-around for bug #48 OV.SetParam("%s.solution.program" %scope, prg_name) OV.SetParam("%s.solution.method" %scope, method) OV.SetParam('user.solution.default_program', prg_name) cl = OV.GetParam("snum.solution.%s.command_line" %prg_name) if cl: cl = "Warning: %s" %cl gui.get_default_notification(cl, txt_col="red_text") onSolutionMethodChange(prg_name, method) def onSolutionMethodChange(prg_name, method): if method in SPD.programs[prg_name].methods: programSettings.doProgramSettings(prg_name, method) OV.SetParam('user.solution.default_method', method) else: print("Please choose a valid method for the solution program %s" %prg_name) return OV.registerFunction(onSolutionMethodChange) def sortDefaultMethod(prg): methods = [] for method in prg: order = method.order methods.append((order, method)) methods.sort() default = methods[0][1].name return default def get_solution_programs(scope='snum'): global available_solution_programs if available_solution_programs is None: p = [] for prg in SPD: a = which_program(prg) if not a: continue p.append(prg.name) p.sort() available_solution_programs = p else: p = available_solution_programs retval = ';'.join(p) if scope != 'snum': retval = 'Auto;' + retval return retval OV.registerFunction(get_solution_programs) def get_solution_methods(prg, scope='snum'): retval = "" if prg == '?' or prg == 'Unknown': return retval if prg == 'Auto': OV.SetParam("%s.solution.method" %scope,'Auto') return 'Auto' p = [] for method in SPD.programs[prg]: p.append(method.name) p.sort() for item in p: retval += "%s;" %item return retval OV.registerFunction(get_solution_methods) def which_program(prg): if "olex2" in prg.name.lower(): return True if prg.name in SPD or prg.name in RPD: exec_l = prg.execs else: exec_l = ["%s.exe" %prg, "%s" %prg, "%s" %prg.lower()] prg = None for item in exec_l: a = olx.file.Which(item) if a and os.path.isfile(a): prg = a break if 'wingx' in a.lower(): print("%s seems to be part of a WinGX installation. These ShelX executable cannot be used with Olex" %item) return None return prg OV.registerFunction(which_program) def getmap(mapName): if not OV.IsFileType('cif') and mapName != 'report': return '#map_%s' %mapName else: return '' if haveGUI: OV.registerFunction(getmap) available_refinement_programs = None available_solution_programs = None def get_refinement_programs(scope='snum'): global available_refinement_programs if available_refinement_programs is None: p = [] for prg in RPD: a = which_program(prg) if not a: continue p.append(prg.name) p.sort() available_refinement_programs = p else: p = available_refinement_programs retval = ';'.join(p) if scope != 'snum': retval = 'Auto;' + retval OV.SetControlItems('SET_snum_refinement_PROGRAM', retval) return retval OV.registerFunction(get_refinement_programs) # Refinement methods that are not offered unless # user.refinement.show_experimental is set. They are registered as ordinary # methods, so the filter is here rather than in ExternalPrgParameters: a method # that is not in RPD at all cannot be selected by a script or reloaded from a # structure that was refined with it. experimental_refinement_methods = ('MLF', 'MLI') def get_refinement_methods(prg, scope='snum'): retval = "" if prg == '?' or prg == 'Unknown': return retval if prg == 'Auto': OV.SetParam("%s.refinement.method" %scope,'Auto') return 'Auto' p = [x.name for x in RPD.programs[prg]] p.sort() # The one already selected is always listed, whatever the switch says. # Dropping it would leave the combo showing a value that is not among its # items, and the next thing to touch the control would quietly refine with # something else. show_experimental = bool(OV.GetParam('user.refinement.show_experimental')) current = OV.GetParam("%s.refinement.method" %scope) for item in p: if (item in experimental_refinement_methods and not show_experimental and item != current): continue display = RPD.programs[prg].methods[item].display retval += "%s<-%s;" %(display,item) OV.SetControlItems(f'SET_{scope}_refinement_METHOD', retval) return retval OV.registerFunction(get_refinement_methods) def QPeaksSlide(value): val = int(value) * 5 if val >= 0: val = 100 - val else: val = -100 - val return val OV.registerFunction(QPeaksSlide) def UisoSelectSlide(value): val = int(value) * 5 if val >= 0: val = 100 - val val = val * 0.001 val = "> %.3f" %val else: val = val * 0.001 * -1 val = "< %.3f" %val # print val return val OV.registerFunction(UisoSelectSlide) def createRMSDisplay(outStr): for rms in SpyVar.MatchedRms: if rms < 0.2: outStr += '%.4f ' %(rms) elif rms < 1: outStr += '%.4f ' %(rms) elif rms < 2: outStr += '%.4f ' %(rms) else: outStr += '%.4f ' %(rms) return outStr def haveSelection(): retVal = False res = OV.olex_function('sel()') if res == "": retVal = False else: retVal = True return retVal def install_plugin(plugin, args): user_alert_uninstall_plugin = OV.FindValue('user_alert_uninstall_plugin') if not plugin: return poke = olx.IsPluginInstalled("%s" %plugin) if poke == 'false': try: olex.m("installplugin %s" %plugin) pass except: print("The plugin %s does not exist") return if user_alert_uninstall_plugin[0] == 'R': delete = user_alert_uninstall_plugin[-1] elif user_alert_uninstall_plugin == 'Y': delete = OV.Alert('Olex2', "This will delete all files and folders of plugin '%s'. Are you sure you want to continue?" %plugin, 'YNIR', "(Don't show this warning again)") else: returnspy.install_plugin if 'Y' in delete: olex.m("installplugin %s" %plugin) pass if 'R' in delete: user_alert_uninstall_plugin = 'RY' self.setVariables('alert') variableFunctions.save_user_parameters('alert') OV.registerMacro(install_plugin, "") def runSadabs(): olx.User("'%s'" %OV.FilePath()) olx.Exec("sadabs") #olx.WaitFor('process') # uncomment me!http://dimas.dur.ac.uk/olex-distro-odac/1.0-alpha/Durham-OLEX2-Demo/AutoChem%20Installer.exe OV.registerFunction(runSadabs) def getKey(key_directory=None, specific_key = None): if sys.platform[:3] != 'win': return None keyPath = "%s/Olex2u/OD/%s" %(os.environ['ALLUSERSPROFILE'], OV.GetTag()) if not key_directory: key_directory = keyPath if specific_key: g = glob.glob(r"%s/%s.%s" %(key_directory, specific_key, "priv")) for item in g: return item.split("\\")[-1:][0] import glob g = glob.glob(r"%s/*.%s" %(key_directory, "priv")) for item in g: keyname = item.split("\\")[-1:][0] return keyname.split(".")[0] def getKeys(key_directory): kl = [] import glob g = glob.glob(r"%s/*.%s" %(key_directory, "priv")) for item in g: keyname = item.split("\\")[-1:][0] kl.append(keyname.split(".")[0]) return kl def check_for_recent_update(): try: return olx.has_recently_updated except: version = OV.GetSVNVersion() try: V = OV.FindValue('last_version','0') last_version = int(V) except Exception as err: print("Alert: Reset parameter 'last_version'") last_version = 0 OV.SetVar('last_version','0') if version > last_version: olx.has_recently_updated = True else: olx.has_recently_updated = False OV.SetVar('last_version',str(version)) OV.StoreParameter('last_version') return olx.has_recently_updated def GetOptionalHyphenString(txt): txt = txt.replace ("/", "/" + "\u200B") txt = txt.replace ("\\", "\\" + "\u200B") txt = txt.replace ("\\", "\\" + " ") return txt OV.registerFunction(GetOptionalHyphenString) def GetTwinLawAndBASF(html=False): def fmt_law(x, tol=1e-9): if abs(x - round(x)) < tol: return str(int(round(x))) return f"{x:.3f}" olex_refinement_model = OV.GetRefinementModel(False) curr_law = None basf_list = olex_refinement_model['hklf'].get('basf', []) if not basf_list: basf_list = olex_refinement_model.get('twin', {}).get('basf', []) basf_count = len(basf_list) if 'twin' in olex_refinement_model: c = olex_refinement_model['twin']['matrix'] curr_law = [] for row in c: for el in row: curr_law.append(el) curr_law = tuple(curr_law) txt = "" if curr_law: txt = "[" + ", ".join(fmt_law(x) for x in curr_law) + "]" basf = [] if olx.IsFileType("ires") != "false": try: for i in range(basf_count): v = olx.xf.rm.BASF(i) if '(' not in v: v = ".3f" %float(v) basf.append(v) except: for i in range(basf_count): basf_val = olx.Lst("basf_%s" %(i+1)) if basf_val == 'n/a': break basf.append(basf_val) if (len(basf) != basf_count): basf = ["%.3f" %x for x in basf_list] if not txt and not basf: return "" if basf: if txt: txt += ", " txt += "BASF [" sz = len(basf) if sz < 3: i, ln = 0, 10 while i < sz: txt += "%s" %(';'.join(basf[i:min(i+ln, len(basf))])) i += ln if i >= sz: break else: txt += ';' if html: txt += "
" else: txt += "%s" %(';'.join(basf[0:3])) if html: txt += "..." else: txt += "..." txt += "]" if html: if curr_law: txt = "TWIN%s" %( OV.GetParam('gui.green_text').hexadecimal, txt) else: txt = "HKLF %s %s" %( OV.GetParam('gui.green_text').hexadecimal, olx.HKLF(), txt) return txt OV.registerFunction(GetTwinLawAndBASF) def HklStatsAnalysis(): import olex_core stats = olex_core.GetHklStat() OV.registerFunction(HklStatsAnalysis) def InstalledPlugins(): import olex_core l = olex_core.GetPluginList() if l is None: l = [] return list(l) def AvailablePlugins(): plugins = {'ODSkin': {'display':'Oxford Diffraction Skin', 'blurb':'A custom-made visual design for Oxford Diffraction'}, } plugins = { } s = "
" green = OV.GetParam('gui.green') red = OV.GetParam('gui.red') for plugin in plugins: display = plugins[plugin].get('display', plugin) blurb = plugins[plugin].get('blurb', plugin) if olx.IsPluginInstalled("%s" %plugin) == 'true': s += "%s Uninstall
%s

" %(display, plugin, green, blurb) else: s += "%s Install
%s

" %(display, plugin, red, blurb) return s OV.registerFunction(AvailablePlugins) def AvailableSkins(): skins = {'OD':{'display':'Oxford Diffraction Skin'}, 'HP':{'display':'Grey'}, 'default':{'display':'Default'}} s = "
" for skin in skins: if OV.FindValue('gui_skin_name') == skin: s += "%s
" %(skin, skins[skin].get('display', skin)) else: s += "%s
" %(skin, skins[skin].get('display', skin)) return s if haveGUI: OV.registerFunction(AvailableSkins) def AvailableExternalPrograms(prgType): if prgType == 'refinement': dict = RPD elif prgType == 'solution': dict = SPD p = {} for prg in dict: a = which_program(prg) if not a: continue p.setdefault(prg.name,a) return p def AvailableExternalProgramsHtml(): d = {} d.setdefault('refinement', AvailableExternalPrograms('refinement')) d.setdefault('solution', AvailableExternalPrograms('solution')) def getReportTitleSrc(): from PIL import Image from PIL import ImageDraw import base64 from ImageTools import ImageTools IT = ImageTools() width = OV.GetParam('gui.report.width') height = OV.GetParam('gui.report.title.height') colour = OV.GetParam('gui.report.title.colour').rgb font_name = OV.GetParam('gui.report.title.font_name') font_size = OV.GetParam('gui.report.title.font_size') font_colour = OV.GetParam('gui.report.title.font_colour') sNum = OV.GetParam('snum.report.title') IM = Image.new('RGBA', (width, height), colour) draw = ImageDraw.Draw(IM) IT.write_text_to_draw(draw, sNum, align='right', max_width=width, font_name=font_name, font_size=font_size, font_colour=font_colour) ## This bits would insert a logo into the header, but it doesn't look good. #imagePath = OV.GetParam('snum.report.image') #imagePath = "%s/etc/CIF/styles/logo.png" %OV.BaseDir() #im = Image.open(imagePath) #imHeight = height #oSize = im.size #nWidth = int(oSize[0]*(imHeight/oSize[1])) #im = im.resize((nWidth, imHeight), Image.BICUBIC) #IM.paste(im, (0,0), im) p = "%s/report_tmp.png" %OV.DataDir() IM.save(p, "PNG") rFile = open(p, 'rb').read() data = base64.b64encode(rFile) retVal ='data:image/png;base64,' + data return retVal OV.registerFunction(getReportTitleSrc) def dealWithReportImage(): from ImageTools import ImageTools IT = ImageTools() image_name = OV.GetParam('snum.report.image') if image_name == "No Image": # OV.SetParam('snum.report.image',None) return elif image_name == "SCREENSHOT": olex.m('showq a false') olex.m('showq b false') olex.m('pict -pq screenshot.png 1') filefull = "%s/screenshot.png" %OV.FilePath() IT.trim_image(im=filefull, padding=2, border=0.2, border_col = "#ababab") OV.SetParam('snum.report.image',"screenshot.png") OV.registerFunction(dealWithReportImage) def getReportImageSrc(): imagePath = OV.GetParam('snum.report.image') if OV.FilePath(imagePath) == OV.FilePath(): return olx.file.GetName(imagePath) else: return 'file:///%s' %imagePath OV.registerFunction(getReportImageSrc) def getReportExtraCIFItems(name_td_class, value_td_class, type='html'): cf_name = OV.file_ChangeExt(OV.FileFull(), 'cif') rv = '' if not os.path.exists(cf_name): return rv try: import iotbx with open(cf_name, "rUb") as fo: reader = iotbx.cif.reader(file_object=fo) models = [] for k, v in reader.model().items(): if k.lower() != 'global': models.append(v) if len(models) > 1: return rv flack = models[0].get("_refine_ls_abs_structure_Flack", None) if flack: if type == 'html': rv = "Flack parameter%s"\ %(name_td_class,value_td_class,flack) else: rv = "Flack parameter & %s\\" % flack.replace('-', '@@-@@') except Exception as err: print(err) return rv OV.registerFunction(getReportExtraCIFItems) def get_text_from_vfs(item): return OV.get_txt_from_vfs(item) OV.registerFunction(get_text_from_vfs) def getReportPhilItem(philItem=None): item = OV.GetParam(philItem) if not item: philItemU = philItem.replace('snum', 'user') item = OV.GetParam(philItemU) if item: OV.SetParam(philItem, item) return item OV.registerFunction(getReportPhilItem) def getReportImageData(size='w400', imageName=None): from PIL import Image from PIL import PngImagePlugin import io import base64 from PIL import ImageDraw from PIL import EpsImagePlugin import io make_border = OV.GetParam('snum.report.image_border') size_type = size[:1] size = int(size[1:]) if imageName is None: imageName = 'snum.report.image' if not OV.HasGUI(): return "No Image available in Headless Mode!" if "snum.report" in imageName: imagePath = OV.GetParam(imageName) if not imagePath: imageNameU = imageName.replace('snum', 'user') imagePath = OV.GetParam(imageNameU) if imagePath: OV.SetParam(imageName, imagePath) if imagePath == "Live Picture": err = """You need DrawPlus installed for this feature""" try: model = olex.f("JSON()") if model == False: return err base = os.path.join(olex.f(OV.GetParam('user.modules.location')), "modules") dp_base = os.path.join(base, "DrawPlus") with open(os.path.join(dp_base, "template.lip"), 'r') as rFile: rv = rFile.read() rv += "" %(model) rv += "" %( olex.f("ExportColors('', 'current')")) return rv except Exception as e: #print str(e) return err if imagePath == "No Image" or not imagePath: return "" if "Dir()" in imagePath: # data/base/str imagePath = olex.f(imagePath) if type(imagePath) != list: imagePath_l = [imagePath] else: imagePath_l = imagePath for imagePath in imagePath_l: IM = Image.open(imagePath) oSize = IM.size if size_type == "w": if oSize[1] != size: nHeight = int(oSize[1]*(size/oSize[0])) nWidth = size IM = IM.resize((nWidth, nHeight), Image.BICUBIC) elif size_type == "h": if oSize[0] != size: nHeight = size nWidth = int(oSize[0]*(size/oSize[1])) IM = IM.resize((nWidth, nHeight), Image.BICUBIC) if make_border: from ImageTools import ImageTools draw = ImageDraw.Draw(IM) fill = '#ababab' width, height = IM.size for i in range(make_border): draw.line((0,0,width-1,0), fill = fill) draw.line((0,height -1,width-1,height -1), fill = fill) draw.line((0,0,0,height - 1), fill = fill) draw.line((width -1,0,width-1,height -1), fill = fill) out = io.BytesIO() IM.save(out, "PNG") data = base64.b64encode(out.getvalue()) html = b''' '''%(bytes(size//2), os.path.split(imagePath)[1].encode(), bytes(size//2), data) return html OV.registerFunction(getReportImageData) def getFileContents(p): if "snum.report" in p: p = OV.GetParam(p) if not p: return if not os.path.exists(p): return "%s does not exist" %p return open(p, 'rb').read() OV.registerFunction(getFileContents) def stopDebugging(): try: import wingdbstub wingdbstub.debugger.ProgramQuit() except: pass return OV.registerFunction(stopDebugging) def StoreSingleParameter(var, args): if var: OV.StoreParameter(var) OV.registerMacro(StoreSingleParameter, "") def reset_file_in_OFS(fileName,txt=" ",copyToDisk = False): OV.reset_file_in_OFS(fileName=fileName, txt=txt, copyToDisk=copyToDisk) OV.registerFunction(reset_file_in_OFS) def GetCurrentSelection(): return OV.GetCurrentSelection() OV.registerFunction(GetCurrentSelection) def getAllHelpBoxes(): import glob import re boxes = [] for htmfile in OV.ListFiles("%s/etc/gui/*.htm" %OV.BaseDir()): rFile = open(htmfile,'r') f = rFile.read() rFile.close() ## find all occurances of strings between help_ext=..; . These should be comma separated things to highlight. regex = re.compile(r"help_ext= (.*?) ;", re.X) l = regex.findall(f) if l: for item in l: boxes.append(item) return boxes def test_help_boxes(): import htmlTools boxes = getAllHelpBoxes() for box in boxes: htmlTools.make_help_box({'name':box}) OV.registerFunction(test_help_boxes) def olex_fs_copy(src_file, dst_file): txt = olex_fs.ReadFile(src_file) olex_fs.NewFile(dst_file,txt) OV.registerFunction(olex_fs_copy) def revert_to_original(): History.hist.revert_to_original() OV.registerFunction(revert_to_original) def fade_in(speed=0): speed = OV.GetParam('user.use_fader') if speed == 0: return olex.m("fade 1 0 -%s" %speed) olex.m('waitfor fade') olex.m("ceiling off") OV.registerFunction(fade_in) def fade_out(speed=0): speed = OV.GetParam('user.use_fader') if speed == 0: return olex.m("fader.InitFG()") olex.m("fader.visible(true)") olex.m("fade 0 1 %s" %speed) olex.m("waitfor fade") OV.registerFunction(fade_out) def StringsAreEqual(str1, str2): return str1 == str2 OV.registerFunction(StringsAreEqual) def StringsAreNotEqual(str1, str2): if str1 == str2: return False else: return True OV.registerFunction(StringsAreNotEqual) def check_for_selection(need_selection=True): res = haveSelection() if not res and need_selection: print("\n++ This action requires a selection of atoms!") return False else: return True OV.registerFunction(check_for_selection) def round_to_n_digits(f, n=2): n = int(n) if len(f) < n: return f try: f = float(f) return "%.*f" %(n,f) except: return f OV.registerFunction(round_to_n_digits) def standardise_path(path): return OV.standardizePath(path) OV.registerFunction(standardise_path) def getCellHTML(): crystal_systems = { 'Triclinic':('a', 'b', 'c', 'α', 'β', 'γ'), 'Monoclinic':('a', 'b', 'c', 'β'), 'Orthorhombic':('a', 'b', 'c'), 'Tetragonal':('a', 'c',), 'Hexagonal':('a', 'c'), 'Trigonal':('a', 'c'), 'Cubic':('a',), } cell_param_value_pairs = dict(list(zip( ('a', 'b', 'c', 'α', 'β', 'γ'), ('_cell_length_a','_cell_length_b','_cell_length_c','_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma')))) cell = {} for param, value in list(cell_param_value_pairs.items()): if param in ('a','b','c'): cell[param] = dict( value = '%%%s%%' %value, unit = ' Å' ) else: cell[param] = dict( value = '%%%s%%' %value, unit = '°' ) cell_html = dict((param, '%s = %s%s, ' %(param,cell[param]['value'],cell[param]['unit'])) for param in list(cell.keys())) crystal_system = OV.olex_function('sg(%s)') html = ''.join(cell_html[param] for param in crystal_systems[crystal_system]) return html OV.registerFunction(getCellHTML) def formatted_date_from_timestamp(dte,date_format=None): if not date_format: date_format = OV.GetParam('snum.report.date_format') from datetime import date from datetime import datetime if not dte: return "No Date" if "-" in dte: if len(dte.split("-")[0]) == 4: try: dte = datetime.strptime(dte, "%Y-%m-%d") dte = dte.strftime(date_format) return dte except: return dte if "." in dte: dte = OV.GetParam(dte) if not dte: return None try: dte = float(dte) except: return "Not A Date" dte = date.fromtimestamp(dte) return dte.strftime(date_format) OV.registerFunction(formatted_date_from_timestamp) if not haveGUI: def tbxs(name): print("This is not available in Headless Olex") return "" #OV.registerFunction(tbxs) def SetMasking(v): if type(v) == bool: v = str(v).lower() OV.SetControlValue('SNUM_REFINEMENT_USE_SOLVENT_MASK', v) if v == 'true': olx.AddIns('ABIN', q=True) else: olx.DelIns('ABIN') OV.SetParam('snum.refinement.use_solvent_mask', v) OV.registerFunction(SetMasking) # def GetHttpFile(URL, file_name, dest): from datetime import datetime import olex try: print("--> Downloading %s%s\n\n" %(URL, file_name), end=' ') if not os.path.exists(dest): os.makedirs(dest) uc = HttpTools.make_url_call(URL + file_name) ts = datetime.strptime(uc.headers["Last-Modified"], '%Y.%m.%d %H:%M:%S') server_ft = time.mktime(ts.timetuple()) fn = os.path.join(dest, file_name) if os.path.exists(fn): mt = os.path.getmtime(fn) if mt == server_ft: print("Skipping %s - file is up-to-date" %file_name) return fn total_sz = int(uc.headers["Content-Length"]) with open(fn, "wb") as of: read_sz = 0 while True: bf = uc.read(1024*1024) if not bf: break read_sz += len(bf) of.write(bf) status = "\r%10d [%3.2f%%]" % (read_sz, read_sz * 100. / total_sz) status = status + chr(32)*(len(status)+1) olex.post(status) os.utime(fn, (server_ft, server_ft)) print('Done\n') return fn except Exception as err: print("Failed to download %s: %s" %(file_name, err)) return None OV.registerFunction(GetHttpFile) def EditIns(): stats_var_name = "merge_stats_updated" OV.SetVar(stats_var_name, "false") if olx.EditIns() != "true": return import olex_core olex_core.GetHklStat() programSettings.doProgramSettings( OV.GetParam('snum.refinement.program'), OV.GetParam('snum.refinement.method')) if olx.IsFileType("ires") == "true": OV.SetParam("snum.refinement.use_solvent_mask", olx.Ins("ABIN") != "n/a") if OV.GetVar(stats_var_name) == "true": from Analysis import HOS_instance HOS_instance.make_HOS() OV.UpdateHtml() olx.Focus() OV.registerFunction(EditIns) def FixMACQuotes(text): if text: return text.replace("\u2018", "'")\ .replace("\u2014", "-")\ .replace("\u2019", "'")\ .replace("\u201c", "\"")\ .replace("\u201d", "\"") return text def debugInVSC(): cd = os.getcwd() try: os.chdir(os.path.join(olx.BaseDir(), "util", "pyUtil")) import ptvsd sys.argv = [olx.app.GetArg(0)] # 5678 is the default attach port in the VS Code debug configurations print("Waiting for debugger attach") ptvsd.enable_attach(address=('localhost', 5678), redirect_output=False) ptvsd.wait_for_attach() breakpoint() except Exception as x: print(x) sys.stdout.formatExceptionInfo() finally: os.chdir(cd) OV.registerFunction(debugInVSC) def debugInEclipse(): sfn = os.path.join(olx.BaseDir(), ".pydevd") if not os.path.exists(sfn): print("Please created setting file with path to pydevd:") print(sfn) return try: for py_dev_path in open(sfn, "r").readlines(): py_dev_path = py_dev_path.strip() if not os.path.exists(py_dev_path): pass sys.path.append(py_dev_path) import pydevd pydevd.settrace() break except: print("Failed to attach the debugger") OV.registerFunction(debugInEclipse) def pip(package:str): import sys import os sys.stdout.isatty = lambda: False sys.stdout.encoding = sys.getdefaultencoding() # Also fix stdin for pip's interactive check if sys.stdin and not hasattr(sys.stdin, 'isatty'): sys.stdin.isatty = lambda: False import numpy as np import scipy as sp import PIL as PIL import locale np_version = np.__version__ sp_version = sp.__version__ PIL_version = PIL.__version__ print(f"numpy version: {np_version}, scipy version: {sp_version} will be enforced") dd = OV.DataDir() c_fn = os.path.join(dd, "pip_constraints.txt") print("Using constraints file: ", c_fn) with open(c_fn, "w") as c_f: c_f.write(f"scipy=={sp_version}\nnumpy=={np_version}\npillow=={PIL_version}") from pip._internal import main as pipmain saved_locale = locale.getlocale(locale.LC_CTYPE) os_get_terminal_size = os.get_terminal_size try: def get_terminal_size(handle=None): return 100,100 os.get_terminal_size = get_terminal_size # 3.8 will still go to site-packages, whereas later - to versioned one if sys.version_info.major >= 3 and sys.version_info.minor > 8: py_version = "-%s%s" %(sys.version_info.major, sys.version_info.minor) else: py_version = "" pipmain(['install', f'--target={dd}/site-packages%s' %py_version, package,"-c", f"{c_fn}", "--no-input", "--disable-pip-version-check"]) #print(f"{locale.getlocale(locale.LC_ALL)}") # reset imports - to allow new imports without restart import importlib importlib.invalidate_caches() except Exception as e: print("\nFailed to install package %s: %s" %(package, e)) finally: os.get_terminal_size = os_get_terminal_size locale.setlocale(locale.LC_CTYPE, saved_locale) OV.registerFunction(pip, False) #----------------------------------------------------------------------------- # Polymers #----------------------------------------------------------------------------- def IsPolymer(): """Whether the renderer traced a backbone through the loaded structure. Set by on_polymer_loaded below and cleared by on_polymer_absent, so the answer rests on a backbone actually having been traced rather than on a residue count: a structure carrying RESI instructions but no peptide chain does not qualify. Held in a snum parameter, so it belongs to the structure. Compared as text rather than passed to bool(). GetParam returns whatever is in olx.structure_params when the value has been set this session, and that can be the string it was written as - at which point bool('False') is True, which is the wrong answer with no way to notice it. """ try: return str(OV.GetParam('snum.is_polymer')).lower() in ('true', '1') except Exception: return False OV.registerFunction(IsPolymer) def on_polymer_absent(): """No backbone was traced. Called from the renderer on every model change. The flag is stored with the structure, so leaving it alone here is not neutral: a small molecule that was once mistaken for a polymer keeps saying it is one, in its own settings file, across sessions. Only written when it is actually set, since this runs on every model change and a write means touching the structure's phil. """ try: if IsPolymer(): OV.SetParam('snum.is_polymer', False) except Exception as e: print("on_polymer_absent: %s" % str(e)) OV.registerFunction(on_polymer_absent) def on_polymer_loaded(): """Pick refinement settings suited to a polymer. Called from the renderer. Idempotent, and it never overrides a choice: each setting is moved only while it still holds the value it is given by default, so a user who picks something else keeps it, and the repeated calls that come with every model change do nothing after the first. These are snum parameters, so they are saved with the structure and reach no other one. """ try: OV.SetParam('snum.is_polymer', True) if OV.GetParam('snum.refinement.method') == 'Gauss-Newton': OV.SetParam('snum.refinement.method', 'CGLS-J') olx.Echo("Polymer: refining with CGLS-J, which does not form the " "normal matrix. 'Gauss-Newton' in the refinement settings " "restores the usual method.") # The final full-matrix build that standard uncertainties need is the # one step whose memory scales with the square of the parameter count, # which is exactly what CGLS-J was chosen to avoid. Off while the model # is being worked on; turn it back on for a structure to be published. if OV.GetParam('snum.refinement.cgls.standard_uncertainties'): OV.SetParam('snum.refinement.cgls.standard_uncertainties', False) olx.Echo(" standard uncertainties are off: switch them on in the " "refinement settings for a final run.") # Half of a protein crystal is disordered solvent, and a model without # it is wrong at low angle in a way the refinement cannot fix by moving # atoms - so it absorbs the residual into the ADPs instead. Measured on # lysozyme: with the solvent unmodelled the ADPs go negative in the # second cycle, and dropping the 0.7% of reflections beyond 5 A - the # ones the solvent dominates - is enough on its own to keep them # positive and let R1 fall. The mask is the proper fix and Olex2 # already has it. if not OV.GetParam('snum.refinement.use_solvent_mask'): OV.SetParam('snum.refinement.use_solvent_mask', True) olx.Echo(" solvent mask on: without a bulk-solvent model the " "low-angle residual ends up in the ADPs.") # Once per structure. Without restraints an anisotropic protein diverges # in the first cycle, and the entry it came from carries none. if (OV.GetParam('snum.auto_protein_restraints') and not OV.GetParam('snum.protein_restraints_done')): OV.SetParam('snum.protein_restraints_done', True) import ProteinRestraints ProteinRestraints.restrain() # The renderer draws a cartoon by itself above a residue count, but knows # nothing of the representation and colour this user settled on. Scheduled # rather than called: this runs from inside CreateObjects, which is in the # middle of building the very objects a representation change would # rebuild. Every default in user.cartoon is the value the renderer already # holds, so a user who has changed nothing pays for no rebuild. olx.Schedule(0, "spy.cartoon.apply_stored()", g=True) except Exception as e: print("on_polymer_loaded: %s" % str(e)) OV.registerFunction(on_polymer_loaded)