import olx import olex import io import os from olexFunctions import OlexFunctions OV = OlexFunctions() from ImageTools import ImageTools IT = ImageTools() import re import sys green = OV.GetParam('gui.green') red = OV.GetParam('gui.red') import gui debug = bool(OV.GetParam("olex2.debug", False)) olx.SetVar('show_restraints_table', "false") global cache_restraint_table cache_restraint_table = "" global filtered_off filtered_off = 0 olx.SetVar('restraint_filter', 2.0) def append_row(rows, observed, target, delta, sigma, restraint, atoms): global filtered_off filter_val = float(olx.GetVar('restraint_filter')) dos = round(delta / sigma, 1) if abs(dos) >= filter_val: rows.append([observed, target, round(delta, 3), round(sigma, 3), dos, restraint, atoms]) else: filtered_off += 1 return rows def parse_bond_restraints(string): rows = [] text = string.split('\n') number_restraints = int(text[0].split(":")[1]) for i in range(number_restraints): atom1 = text[2 + 4 * i].split()[1] atom2 = text[3 + 4 * i].strip() line = text[5 + 4 * i].split() target = float(line[0]) observed = float(line[1]) delta = float(line[2]) sigma = float(line[3]) restraint = "DFIX" atoms = "%s %s" % (atom1, atom2) rows = append_row(rows, observed, target, delta, sigma, restraint, atoms) return rows def parse_chirality_restraints(string): rows = [] text = string.split('\n') number_restraints = int(text[0].split(":")[1]) for i in range(number_restraints): atoms = find_bits(string, "chirality", "both_signs").strip().split() info = find_bits(string, "residual", "\n\n").strip().split() # rows.append([observed, target, delta, sigma, "CHIV", "%s %s" % (atom1, atom2)]) return rows def parse_bond_angle_restraints(string): rows = [] text = string.split('\n') number_restraints = int(text[0].split(":")[1]) for i in range(number_restraints): atom1 = text[2 + 5 * i].split()[1] atom2 = text[3 + 5 * i].strip() atom3 = text[4 + 5 * i].strip() line = text[6 + 5 * i].split() target = float(line[0]) observed = float(line[1]) delta = float(line[2]) sigma = float(line[3]) restraint = "ANGLE" atoms = "%s %s %s" % (atom1, atom2, atom3) rows = append_row(rows, observed, target, delta, sigma, restraint, atoms) return rows def parse_adp_similarity_restraints(string): rows = [] if not string: print("parse_ADP_similarity_restraints didn't receive a string. This is strange") return rows text = string.split('\n') number_restraints = int(text[0].split(":")[1]) for i in range(number_restraints): line = text[2 + 2 * i] atoms = [line.split()[1]] count = 1 line = text[2 + 2 * i + count] while "delta" not in line: atoms.append(line.strip()) count += 1 line = text[2 + 2 * i + count] atoms_string = "" for l in range(len(atoms)): atoms_string += " %s" % atoms[l] for j in range(6): line = text[5 + i * 6 + j].split() name = line[0] target = "-" observed = "-" delta = float(line[1]) sigma = float(line[2]) restraint = "RIGU" atoms = "%s" % (atoms_string) rows = append_row(rows, observed, target, delta, sigma, restraint, atoms) return rows def parse_isotropic_adp_restraints(string): rows = [] if not string: print("parse_ADP_similarity_restraints didn't receive a string. This is strange") return rows text = string.split('\n') number_restraints = int(text[0].split(":")[1]) for i in range(number_restraints): line = text[2 + i * 8] atoms = [line.split()[1]] count = 1 line = text[2 + i * 8 + count] while "delta" not in line: atoms.append(line.strip()) count += 1 line = text[2 + i + count] atoms_string = "" for l in range(len(atoms)): atoms_string += " %s" % atoms[l] line = text[4 + i * 8].split() # line = text[5 + i * 6 + j].split() name = line[0] target = "-" observed = "-" delta = float(line[1]) sigma = float(line[2]) restraint = "ISOR %s" % (name) atoms = "%s" % (atoms_string) rows = append_row(rows, observed, target, delta, sigma, restraint, atoms) i += 1 return rows def parse_bond_similarity_restraints(string): rows = [] text = string.split('\n') number_restraints = int(text[0].split(":")[1]) line = text[3] for i in range(3, len(text)): if "delta" in text[i]: continue line = text[i].split() add = 0 if line[0] == "bond": atoms = line[1].split('-') add = 1 else: atoms = line[0].split('-') atoms_string = " ".join(atoms) delta = float(line[1 + add]) sigma = float(line[2 + add]) observed = '-' target = '-' restraint = "SADI" atoms = "%s" % (atoms_string) rows = append_row(rows, observed, target, delta, sigma, restraint, atoms) return rows def parse_rigu_bond_restraints(string): rows = [] text = string.split('\n') number_restraints = int(text[0].split(":")[1]) target = "-" observed = "-" for i in range(number_restraints): atom1 = text[2 + 6 * i].split()[1] atom2 = text[3 + 6 * i].strip() for j in range(3): line = text[j + 5 + 6 * i].split() delta = float(line[0]) sigma = float(line[1]) restraint = "RIGU %s" % j atoms = "%s %s" % (atom1, atom2) rows = append_row(rows, observed, target, delta, sigma, restraint, atoms) return rows def mangle_fdb_data(tabledata): new_l = [] for l in tabledata: _ = l[-1:][0].split() new_l.append(l[0:-1] + [_[0]] + [" ".join(_[1:])]) return new_l def make_fvar_table(*kwds): fvar_table: str = "" header = """ """ footer = """""" filling = """FVAR:""" fvars = [] try: for i in range(20): fvars.append(olx.xf.rm.FVar(i)) except: pass for i, var in enumerate(fvars): filling += """""" + "%d: %s " % (i + 1, var) filling += "" fvar_table = header + filling + footer return fvar_table OV.registerFunction(make_fvar_table, False, "gui.restraints") def make_restraints_table(*kwds): global cache_restraint_table global filtered_off filtered_off = 0 filter_message = "No Restraints are shown" if olx.GetVar('show_restraints_table').lower() == 'false': top_line = gui.tools.TemplateProvider.get_template('restraints_top', force=debug) % {'filtered_off': filter_message} return top_line else: top_line = gui.tools.TemplateProvider.get_template('restraints_top', force=debug) % {'filtered_off': filter_message} retVal = top_line if cache_restraint_table and olx.GetVar('restraint_filter_changed','Flase') == "False": retVal = cache_restraint_table cache_restraint_table = "" return retVal software = OV.GetParam("snum.refinement.program") tabledata = [] if "xl" in software.lower(): import FragmentDB Ref = FragmentDB.refine_model_tasks.Refmod() lstfile = os.path.abspath(OV.FilePath() + os.path.sep + OV.FileName() + '.lst') if not os.path.exists(lstfile): print(".lst File not found!") return tabledata = mangle_fdb_data(Ref.fileparser(lstfile)) else: from cctbx_olex_adapter import OlexCctbxAdapter cctbx_adaptor = OlexCctbxAdapter() temp = io.StringIO() cctbx_adaptor.restraints_manager().show_sorted(cctbx_adaptor._xray_structure, f=temp) output = temp.getvalue() restraints_l = ["Bond restraints", "Bond similarity restraints", "Bond angle restraints", "ADP similarity restraints", "Rigu bond restraints", "Isotropic ADP restraints", "Chirality restraints", ] for restraint in restraints_l: if restraint in output: try: s = find_bits(output, restraint, "\n\n") bond_rows = globals()["parse_" + restraint.lower().replace(" ", "_")](s) tabledata += bond_rows except Exception as err: sys.stderr.formatExceptionInfo() _ = restraint.split() tabledata += [[0, 0, 0, 0, _[0].upper() + "_" + _[1].lower() + "_" + 'err', ""]] filter_message = "%i Restraints have been filtered" % filtered_off top_line = gui.tools.TemplateProvider.get_template('restraints_top', force=debug) % {'filtered_off': filter_message} cache_restraint_table = top_line + h_t.table_maker(tabledata) return cache_restraint_table OV.registerFunction(make_restraints_table, False, "gui.restraints") def find_bits(text, front, back): m = re.findall(r"%s(.*?)%s" % (front, back), text, re.DOTALL) return m[0] class html_Table(object): """ html table generator """ def __init__(self): try: # more than two colors here are too crystmas treelike: self.grade_1_colour = OV.GetParam('gui.skin.diagnostics.colour_grade1') #self.grade_1_colour = self.rgb2hex(IT.adjust_colour(grade_1_colour, luminosity=1.8)) self.grade_2_colour = OV.GetParam('gui.skin.diagnostics.colour_grade2') #self.grade_2_colour = self.rgb2hex(IT.adjust_colour(grade_2_colour, luminosity=1.8)) self.grade_3_colour = OV.GetParam('gui.skin.diagnostics.colour_grade3') #self.grade_3_colour = self.rgb2hex(IT.adjust_colour(grade_3_colour, luminosity=1.8)) self.grade_4_colour = OV.GetParam('gui.skin.diagnostics.colour_grade4') #self.grade_4_colour = self.rgb2hex(IT.adjust_colour(grade_4_colour, luminosity=1.8)) except(ImportError, NameError): self.grade_2_colour = '#FFD100' self.grade_4_colour = '#FF1030' def rgb2hex(self, rgb): """ return the hexadecimal string representation of an rgb colour """ return '#%02x%02x%02x' % rgb def table_maker(self, tabledata=None): """ builds a html table out of a datalist from the final cycle summary of a shelxl list file. """ if tabledata is None: tabledata = [] table = [] for line in tabledata: table.append(self.row(line)) footer = "" empty_data = """ There may be no restraints, they have been filtered or can not be evaluated. """ html = r""" {0}
Observed Target Dev Sig D/S Restr. Atoms
{1} """.format('\n'.join(table), footer) if not table: return empty_data return html def row(self, rowdata): """ creates a table row for the restraints list. :type rowdata: list """ restraints = ["SADI", "DFIX", "RIGU", "ISOR", "ANGLE"] td = [] error = False bgcolor = '' try: #if abs(float(rowdata[4])) > 2.5 * float(rowdata[3]): #bgcolor = r"""bgcolor='{}'""".format(self.grade_2_colour) #if abs(float(rowdata[4])) > 3.5 * float(rowdata[3]): #bgcolor = r"""bgcolor='{}'""".format(self.grade_4_colour) _ = abs(float(rowdata[4])) if _ > 2.5: bgcolor = r"""bgcolor='{}'""".format(self.grade_4_colour) elif _ > 1.5: bgcolor = r"""bgcolor='{}'""".format(self.grade_3_colour) elif _ > 0.5: bgcolor = r"""bgcolor='{}'""".format(self.grade_2_colour) else: bgcolor = r"""bgcolor='{}'""".format(self.grade_1_colour) except ValueError: print("Unknown restraint occured.") for num, item in enumerate(rowdata): try: # align right for numbers: float(item) if num < 2: # do not colorize the first two columns: td.append(r""" {} """.format(item)) else: if num == 4: td.append(r""" {1} """.format(bgcolor, item)) else: td.append(r""" {1:.3f} """.format(bgcolor, item)) except: if item.startswith('-'): # only a minus sign td.append(r""" {} """.format(item)) else: if num < 6: if "err" in item: td.append(r""" {} """.format(item) % (red)) error = True else: _ = item if " " in item: _ = item.split()[0] if _ in restraints: td.append(r""" {} """.format(item)) else: td.append(r"""{} """.format(item, item)) continue # align left for words: if not error: td.append(r""" {} Edit """.format(item, item, item)) if not td: row = " No (disagreeable) restraints found in .lst file. " else: row = " {} ".format(''.join(td)) return row def edit_restraints(self, restr): """ this method gets the atom list of a disagreeable restraint in olex2. The text string is then formated so that "editatom" can handle it. editatom opens an editor window with the respective atoms. :type restr: string like "SAME/SADI Co N11 Co N22" """ # separate SAME/SADI: restr = restr.replace('/', ' ') restrlist = restr.split() atoms = [] for i in restrlist: if i in ['xz', 'yz', 'xy', 'etc.', 'U11', 'U22', 'U33', 'U12', 'U13', 'U23']: continue else: # atoms.append(remove_partsymbol(i)) # Have to remove this, because new names needed for 'edit' atoms.append(i) OV.cmd('editatom {}'.format(' '.join(atoms))) def get_existing_fvar_dropdown_items(): FvarNum=0 while OV.GetFVar(FvarNum) is not None: FvarNum+=1 items = "" for i in range(FvarNum): i += 1 items += "%s;" %(i+1) return items OV.registerFunction(get_existing_fvar_dropdown_items, False, "gui.restraints") def set_mode_fit(): cmd = "mode fit -s" val_parts = olx.html.GetValue('SPLIT_PARTS', None) val_fvars = olx.html.GetValue('SPLIT_FVARS', None) val_restraints = olx.html.GetValue('SPLIT_RESTRAINTS', None) if val_restraints != "--": cmd += " %s" %val_restraints if val_parts != "auto": cmd += " -p=%s" % val_parts.split("/")[0].strip() if val_fvars != "auto": cmd += " -v=%s" % val_fvars olex.m(cmd) OV.registerFunction(set_mode_fit, False, "gui.restraints") h_t = html_Table() OV.registerFunction(h_t.edit_restraints, False, "gui")