Source code for GSASII.GSASIIrestrGUI

# -*- coding: utf-8 -*-
#GSASIIrestr - restraint GUI routines
'''Restraint GUI routines follow.
'''
from __future__ import division, print_function
import wx
import wx.grid as wg
import numpy as np
import numpy.ma as ma
import os.path
from . import GSASIIpath
from . import GSASIImath as G2mth
from . import GSASIIlattice as G2lat
from . import GSASIIspc as G2spc
from . import GSASIIdataGUI as G2gd
from . import GSASIIplot as G2plt
from . import GSASIIdata as G2data
from . import GSASIIctrlGUI as G2G
from . import GSASIIphsGUI as G2phsGUI
from . import GSASIIobj as G2obj
from . import GSASIIconstrGUI as G2cnstG
from . import GSASIIexprGUI as G2exG

try:
    wx.NewIdRef
    wx.NewId = wx.NewIdRef
except AttributeError:
    pass

try:
    VERY_LIGHT_GREY = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)
    VERY_YELLOW = wx.Colour(255,255,0)
    WACV = wx.ALIGN_CENTER_VERTICAL
except:
    pass
TabSelectionIdDict = {}

################################################################################
#####  Restraints
################################################################################           
[docs] def GetSelectedRows(widget,lbl='edit',G2frame=None): '''Returns a list of selected rows. Rows can be selected, blocks of cells or individual cells can be selected. The column for selected cells is ignored. ''' try: rows = widget.GetSelectedRows() if rows: return rows top = widget.GetSelectionBlockTopLeft() bot = widget.GetSelectionBlockBottomRight() if top and bot: rows = range(top[0][0],bot[0][0]+1) if rows: return rows rows = sorted(list(set([cell[0] for cell in widget.GetSelectedCells()]))) if rows: return rows choices = ["{}: {}".format(widget.GetRowLabelValue(i),widget.GetCellValue(i,0)) for i in range(widget.GetNumberRows())] try: dlg = G2G.G2MultiChoiceDialog(G2frame,'Restraints to '+lbl, 'Select restraints',choices) if dlg.ShowModal() != wx.ID_OK: return return dlg.GetSelections() finally: dlg.Destroy() except: return
[docs] def UpdateRestraints(G2frame,data,phaseName): '''Respond to selection of the Restraints item on the data tree ''' # global Pages def getMacroFile(macName): defDir = os.path.join(GSASIIpath.path2GSAS2,'inputs','GSASIImacros') if not os.path.exists(defDir): # patch 3/2024 for svn dir organization defDir = os.path.join(GSASIIpath.path2GSAS2,'GSASIImacros') if not os.path.exists(defDir): print('Warning: GSASIImacros directory not found') return dlg = wx.FileDialog(G2frame,message='Choose '+macName+' restraint macro file', defaultDir=defDir,defaultFile="",wildcard="GSAS-II macro file (*.mac)|*.mac", style=wx.FD_OPEN | wx.FD_CHANGE_DIR) try: macro = '' if dlg.ShowModal() == wx.ID_OK: macfile = dlg.GetPath() macro = open(macfile,'r') head = macro.readline() if macName not in head: print (head) print ('**** ERROR - wrong restraint macro file selected, try again ****') macro = [] finally: dlg.Destroy() return macro #advanced past 1st line def getMOGULFile(): colNums = [0,2,3,5,6,7] # default location for these fields: # Type, Fragment, Classification, Query value, Mean, Std. dev. # but potentially overridden below dlg = wx.FileDialog(G2frame,message='Choose MOGUL csv file', defaultDir='.',defaultFile="",wildcard="MOGUL csv file (*.csv)|*.csv", style=wx.FD_OPEN | wx.FD_CHANGE_DIR) try: mogul = '' if dlg.ShowModal() == wx.ID_OK: csvfile = dlg.GetPath() mogul = open(csvfile,'r') head = mogul.readline() if 'Type' not in head: print ('Note: header line is\n',head) print ('**** ERROR - file selected is not a MOGUL csv file, try again ****') mogul = [] else: for i,k in enumerate(('Type','Fragment','Classification', 'Query value','Mean','Std. dev.')): try: colNums[i] = head.split(',').index(k) except ValueError: pass finally: dlg.Destroy() return mogul,colNums #file pointer advanced past 1st line & col pointers def OnPlotAARestraint(event): page = G2frame.restrBook.GetSelection() if 'Torsion' in G2frame.restrBook.GetPageText(page): torNames = [] torNames += list(restrData['Torsion']['Coeff'].keys()) dlg = wx.SingleChoiceDialog(G2frame,'Select','Torsion data',torNames) try: if dlg.ShowModal() == wx.ID_OK: torName = torNames[dlg.GetSelection()] torsion = G2data.torsionDist[torName] torCoeff = restrData['Torsion']['Coeff'][torName] torList = restrData['Torsion']['Torsions'] Names = [] Angles = [] for i,[indx,ops,cofName,esd] in enumerate(torList): if cofName == torName: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '('+atoms[2][1]+atoms[2][0].strip()+atoms[2][2]+')' for atom in atoms: name += ' '+atom[3] XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) angle = G2mth.getRestTorsion(XYZ,Amat) Angles.append(angle) Names.append(name) G2plt.PlotTorsion(G2frame,phaseName,torsion,torName,Names,np.array(Angles),torCoeff) finally: dlg.Destroy() elif 'Rama' in G2frame.restrBook.GetPageText(page): ramaNames = ['All',] ramaNames += list(restrData['Rama']['Coeff'].keys()) dlg = wx.SingleChoiceDialog(G2frame,'Select','Ramachandran data',ramaNames) try: if dlg.ShowModal() == wx.ID_OK: ramaName = ramaNames[dlg.GetSelection()] rama = G2data.ramachandranDist[ramaName] ramaCoeff = [] if ramaName != 'All': ramaCoeff = restrData['Rama']['Coeff'][ramaName] ramaList = restrData['Rama']['Ramas'] Names = [] PhiPsi = [] for i,[indx,ops,cofName,esd] in enumerate(ramaList): if cofName == ramaName or (ramaName == 'All' and '-1' in cofName): atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '('+atoms[3][1]+atoms[3][0].strip()+atoms[3][2]+')' for atom in atoms: name += ' '+atom[3] XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) phi,psi = G2mth.getRestRama(XYZ,Amat) PhiPsi.append([phi,psi]) Names.append(name) G2plt.PlotRama(G2frame,phaseName,rama,ramaName,Names,np.array(PhiPsi),ramaCoeff) finally: dlg.Destroy() def SetupParmDict(G2frame): '''Creates a parameter dict with variable names as keys and numerical values (only) ''' G2cnstG.CheckAllScalePhaseFractions(G2frame,refine=False) try: parmDict,varyList = G2frame.MakeLSParmDict() except: print('Error retrieving parameters') return {} return {i:parmDict[i][0] for i in parmDict} def OnAddRestraint(event): '''Adds a restraint depending on which tab is currently displayed''' page = G2frame.restrBook.GetSelection() if 'Bond' in G2frame.restrBook.GetPageText(page): AddBondRestraint(restrData['Bond']) elif 'Angle' in G2frame.restrBook.GetPageText(page): AddAngleRestraint(restrData['Angle']) elif 'Plane' in G2frame.restrBook.GetPageText(page): AddPlaneRestraint(restrData['Plane']) elif 'Chem' in G2frame.restrBook.GetPageText(page): AddChemCompRestraint(restrData['ChemComp']) elif 'Texture' in G2frame.restrBook.GetPageText(page): AddTextureRestraint(restrData['Texture']) elif 'Spin RB' in G2frame.restrBook.GetPageText(page): AddSpinRBRestraint(restrData['SpinRB']) elif 'Moments' in G2frame.restrBook.GetPageText(page): AddMomentRestraint(restrData['Moments']) elif 'General' in G2frame.restrBook.GetPageText(page): parmDict = SetupParmDict(G2frame) dlg = G2exG.ExpressionDialog(G2frame,parmDict, header="Create a restraint expression", fit=False,wildCard=G2frame.testSeqRefineMode()) restobj = dlg.Show(True) if restobj: restrData['General']['General'].append([restobj,0.0,1.0]) wx.CallAfter(UpdateGeneralRestr,restrData['General']) def OnAddAARestraint(event): page = G2frame.restrBook.GetSelection() if 'Bond' in G2frame.restrBook.GetPageText(page): AddAABondRestraint(restrData['Bond']) elif 'Angle' in G2frame.restrBook.GetPageText(page): AddAAAngleRestraint(restrData['Angle']) elif 'Plane' in G2frame.restrBook.GetPageText(page): AddAAPlaneRestraint(restrData['Plane']) elif 'Chiral' in G2frame.restrBook.GetPageText(page): AddAAChiralRestraint(restrData['Chiral']) elif 'Torsion' in G2frame.restrBook.GetPageText(page): AddAATorsionRestraint(restrData['Torsion']) elif 'Rama' in G2frame.restrBook.GetPageText(page): AddAARamaRestraint(restrData['Rama']) def OnUseMogul(event): page = G2frame.restrBook.GetSelection() if 'Bond' in G2frame.restrBook.GetPageText(page): AddMogulBondRestraint(restrData['Bond']) elif 'Angle' in G2frame.restrBook.GetPageText(page): AddMogulAngleRestraint(restrData['Angle']) def makeChains(Names,Ids): Chains = {} atoms = zip(Names,Ids) for name,Id in atoms: items = name.split(' ',2) rnum,res = items[0].split(':') rnum = int(rnum) if items[1] not in Chains: Residues = {} Chains[items[1]] = Residues if rnum not in Residues: Residues[rnum] = [[],[]] if items[2][3] in [' ','A']: Residues[rnum][0].append([res,items[2],Id]) if items[2][3] in [' ','B']: Residues[rnum][1].append([res,items[2],Id]) return Chains def AddBondRestraint(bondRestData): Lists = {'origin':[],'target':[]} for listName in ['origin','target']: dlg = G2G.G2MultiChoiceDialog(G2frame,'Bond restraint '+listName+' for '+General['Name'], 'Select bond restraint '+listName+' atoms',Names) if dlg.ShowModal() == wx.ID_OK: sel = dlg.GetSelections() for x in sel: if 'all' in Names[x]: allType = Types[x] for name,Type,coords,Id in zip(Names,Types,Coords,Ids): if Type == allType and 'all' not in name: Lists[listName].append([Id,Type,coords]) else: Lists[listName].append([Ids[x],Types[x],Coords[x],]) else: return if len(Lists['origin']) and len(Lists['target']): bond = 1.54 dlg = G2G.SingleFloatDialog(G2frame,'Distance','Enter restraint distance for bond',bond,[0.01,4.],'%.4f') if dlg.ShowModal() == wx.ID_OK: bond = dlg.GetValue() dlg.Destroy() Factor = bondRestData['Range'] dlg = wx.ProgressDialog("Generating bond restraints","Processed origin atoms",len(Lists['origin']), style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME) try: bondlst = G2mth.searchBondRestr(Lists['origin'],Lists['target'], bond,Factor,General['Type'],SGData,Amat,0.01,dlg) for newBond in bondlst: if newBond not in bondRestData['Bonds']: bondRestData['Bonds'].append(newBond) finally: dlg.Destroy() UpdateBondRestr(bondRestData) def AddAABondRestraint(bondRestData): macro = getMacroFile('bond') if not macro: return macStr = macro.readline() atoms = zip(Names,Coords,Ids) Factor = bondRestData['Range'] while macStr: items = macStr.split() if 'F' in items[0]: restrData['Bond']['wtFactor'] = float(items[1]) elif 'S' in items[0]: oIds = [] oCoords = [] oDis = [] tIds = [] tCoords = [] tDis = [] res = items[1] dist = float(items[2]) esd = float(items[3]) oAtm,tAtm = items[4:6] for Name,coords,Id in atoms: names = Name.split(' ',2) if res == '*' or res in names[0]: if oAtm.ljust(3) == names[2][:3]: oIds.append(Id) oCoords.append(np.array(coords)) oDis.append(names[2][3]) if tAtm.ljust(3) == names[2][:3]: tIds.append(Id) tCoords.append(np.array(coords)) tDis.append(names[2][3]) for i,[oId,oCoord,odis] in enumerate(zip(oIds,oCoords,oDis)): for tId,tCoord,tdis in list(zip(tIds,tCoords,tDis))[i:]: if odis+tdis in ['AB','BA']: continue obsd = np.sqrt(np.sum(np.inner(Amat,tCoord-oCoord)**2)) if dist/Factor < obsd < dist*Factor: newBond = [[oId,tId],['1','1'],dist,esd] if newBond not in bondRestData['Bonds']: bondRestData['Bonds'].append(newBond) macStr = macro.readline() macro.close() print(' Found %d bond restraints'%len(bondRestData['Bonds'])) UpdateBondRestr(bondRestData) def AddMogulBondRestraint(bondRestData): mogul,colNums = getMOGULFile() badNames = [] badLines = [] badCount = 0 for line in mogul: items = line.split(',') if 'bond' == items[colNums[0]]: oName,tName = items[colNums[1]].split() try: oInd = Names.index(oName) except: badCount += 1 badNames.append(oName) continue try: tInd = Names.index(tName) except: badCount += 1 badNames.append(tName) continue try: if items[colNums[2]] != 'No hits': dist = float(items[colNums[4]]) esd = float(items[colNums[5]]) else: dist = float(items[colNums[3]]) esd = 0.02 except: print(f'Error reading line {line.strip()!r}') badLines.append(line.strip()[:30]) continue newBond = [[Ids[oInd],Ids[tInd]],['1','1'],dist,esd] if newBond not in bondRestData['Bonds']: bondRestData['Bonds'].append(newBond) UpdateBondRestr(bondRestData) msg = '' if badNames: msg += f'{badCount} restraints were skipped because these atom(s) were not found: {" ".join(set(badNames))}' if badLines: lines = "\n".join(badLines) msg += f'{len(badLines)} restraints were skipped because these lines(s) could not be read:\n{lines}. ' if msg: wx.GetApp().Yield() G2G.G2MessageBox(G2frame,msg,'Read problems') def AddAngleRestraint(angleRestData): Radii = dict(zip(General['AtomTypes'],zip(General['BondRadii'],General['AngleRadii']))) Lists = {'A-atom':[],'B-atom':[],'C-atom':[]} for listName in ['A-atom','B-atom']: dlg = G2G.G2MultiChoiceDialog(G2frame,'Select '+listName+' for angle A-B-C for '+General['Name'] , 'Select angle restraint '+listName,Names) if dlg.ShowModal() == wx.ID_OK: sel = dlg.GetSelections() for x in sel: if 'all' in Names[x]: allType = Types[x] for name,Type,coords,Id in zip(Names,Types,Coords,Ids): if Type == allType and 'all' not in name: if 'A' in listName: Lists[listName].append(Type) else: Lists[listName].append([Id,Type,coords]) else: if 'A' in listName: Lists[listName].append(Types[x]) else: Lists[listName].append([Ids[x],Types[x],Coords[x],]) else: return targAtoms = [[Ids[x+iBeg],Types[x+iBeg],Coords[x+iBeg]] for x in range(len(Names[iBeg:]))] if len(Lists['B-atom']): value = 109.54 dlg = G2G.SingleFloatDialog(G2frame,'Angle','Enter restraint angle ',value,[30.,180.],'%.2f') if dlg.ShowModal() == wx.ID_OK: value = dlg.GetValue() dlg.Destroy() Factor = angleRestData['Range'] indices = (-2,-1,0,1,2) Units = np.array([[h,k,l] for h in indices for k in indices for l in indices]) VectA = [] for Oid,Otype,Ocoord in Lists['B-atom']: IndBlist = [] VectB = [] for Tid,Ttype,Tcoord in targAtoms: result = G2spc.GenAtom(Tcoord,SGData,All=False,Move=False) BsumR = (Radii[Otype][0]+Radii[Ttype][0])*Factor AsumR = (Radii[Otype][1]+Radii[Ttype][1])*Factor for Txyz,Top,Tunit,Spn in result: Dx = (Txyz-Ocoord)+Units dx = np.inner(Amat,Dx) dist = ma.masked_less(np.sqrt(np.sum(dx**2,axis=0)),0.5) IndB = ma.nonzero(ma.masked_greater(dist,BsumR)) if np.any(IndB): for indb in IndB: for i in range(len(indb)): if str(dx.T[indb][i]) not in IndBlist: IndBlist.append(str(dx.T[indb][i])) unit = Units[indb][i]+Tunit if np.any(unit): Topstr = '%d+%d,%d,%d'%(Top,unit[0],unit[1],unit[2]) else: Topstr = str(Top) Dist = ma.getdata(dist[indb])[i] if (Dist-AsumR) <= 0.: VectB.append([Oid,'1',Ocoord,Ttype,Tid,Topstr,Tcoord,Dist]) VectA.append(VectB) for Vects in VectA: for i,vecta in enumerate(Vects): for vectb in Vects[:i]: if vecta[3] in Lists['A-atom']: ids = [vecta[4],vecta[0],vectb[4]] ops = [vecta[5],vecta[1],vectb[5]] angle = [ids,ops,value,1.0] if angle not in angleRestData['Angles']: angleRestData['Angles'].append(angle) UpdateAngleRestr(angleRestData) def AddAAAngleRestraint(angleRestData): macro = getMacroFile('angle') if not macro: return Chains = makeChains(Names,Ids) macStr = macro.readline() while macStr: items = macStr.split() if 'F' in items[0]: restrData['Angle']['wtFactor'] = float(items[1]) elif 'S' in items[0]: Res = items[1] Value = float(items[2]) Esd = float(items[3]) Atms = items[4:7] pAtms = ['','',''] for i,atm in enumerate(Atms): if '+' in atm: pAtms[i] = atm.strip('+') ids = [0,0,0] chains = list(Chains.keys()) chains.sort() for chain in chains: residues = list(Chains[chain].keys()) residues.sort() for residue in residues: for ires in [0,1]: if Res != '*': #works with disordered res for res,name,Id in Chains[chain][residue][ires]: if Res == res: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue else: try: for res,name,Id in Chains[chain][residue][ires]: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue for res,name,Id in Chains[chain][residue+1][ires]: try: ipos = pAtms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue except KeyError: continue if all(ids): angle = [list(ids),['1','1','1'],Value,Esd] if angle not in angleRestData['Angles']: angleRestData['Angles'].append(angle) ids = [0,0,0] macStr = macro.readline() macro.close() print(' Found %d angle restraints'%len(angleRestData['Angles'])) UpdateAngleRestr(angleRestData) def AddMogulAngleRestraint(angleRestData): mogul,colNums = getMOGULFile() badLines = [] for line in mogul: items = line.split(',') if 'angle' == items[colNums[0]]: try: aName,bName,cName = items[colNums[1]].split() aInd = Names.index(aName) bInd = Names.index(bName) cInd = Names.index(cName) if items[colNums[2]] != 'No hits': angle = float(items[colNums[4]]) esd = float(items[colNums[5]]) else: angle = float(items[colNums[3]]) esd = 2.00 newAngle = [[Ids[aInd],Ids[bInd],Ids[cInd]],['1','1','1'],angle,esd] if newAngle not in angleRestData['Angles']: angleRestData['Angles'].append(newAngle) except: badLines.append(line.strip()[:30]) print(f'Error reading line {line.strip()!r}') UpdateAngleRestr(angleRestData) msg = '' if badLines: lines = "\n".join(badLines) msg += f'{len(badLines)} restraints were skipped because these lines(s) could not be read:\n{lines}' if msg: wx.GetApp().Yield() G2G.G2MessageBox(G2frame,msg,'Read problems') def AddPlaneRestraint(restrData): ids = [] dlg = G2G.G2MultiChoiceDialog(G2frame,'Select 4 or more atoms for plane in '+General['Name'], 'Select 4+ atoms',Names[iBeg:]) if dlg.ShowModal() == wx.ID_OK: sel = dlg.GetSelections() if len(sel) > 3: for x in sel: ids.append(Ids[x+iBeg]) ops = ['1' for i in range(len(sel))] plane = [ids,ops,0.0,0.01] if plane not in restrData['Planes']: restrData['Planes'].append(plane) else: print ('**** ERROR - not enough atoms for a plane restraint - try again ****') UpdatePlaneRestr(restrData) def AddAAPlaneRestraint(planeRestData): macro = getMacroFile('plane') if not macro: return Chains = makeChains(Names,Ids) macStr = macro.readline() while macStr: items = macStr.split() if 'F' in items[0]: restrData['Plane']['wtFactor'] = float(items[1]) elif 'S' in items[0]: Res = items[1] Esd = float(items[2]) Atms = items[3:] pAtms = ['' for i in Atms] for i,atm in enumerate(Atms): if '+' in atm: pAtms[i] = atm.strip('+') ids = [0,]*len(Atms) ops = ['1' for i in range(len(Atms))] chains = list(Chains.keys()) chains.sort() for chain in chains: residues = list(Chains[chain].keys()) residues.sort() for residue in residues: for ires in [0,1]: if residue == residues[-1] and Res == '*': continue if Res != '*': #works with disordered res for res,name,Id in Chains[chain][residue][ires]: if Res == res: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue else: try: for res,name,Id in Chains[chain][residue][ires]: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue for res,name,Id in Chains[chain][residue+1][ires]: try: ipos = pAtms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue except KeyError: continue if all(ids): plane = [list(ids),ops,0.0,Esd] if plane not in planeRestData['Planes']: planeRestData['Planes'].append(plane) ids = [0,]*len(Atms) macStr = macro.readline() macro.close() print(' Found %d plane restraints'%len(planeRestData['Planes'])) UpdatePlaneRestr(planeRestData) def AddAAChiralRestraint(chiralRestData): macro = getMacroFile('chiral') if not macro: return Chains = makeChains(Names,Ids) macStr = macro.readline() while macStr: items = macStr.split() if 'F' in items[0]: restrData['Chiral']['wtFactor'] = float(items[1]) elif 'S' in items[0]: Res = items[1] Value = float(items[2]) Esd = float(items[3]) Atms = items[4:8] ids = [0,0,0,0] chains = list(Chains.keys()) chains.sort() for chain in chains: residues = list(Chains[chain].keys()) residues.sort() for residue in residues: for ires in [0,1]: if residue == residues[-1] and Res == '*': continue if Res != '*': #works with disordered res for res,name,Id in Chains[chain][residue][ires]: if Res == res: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue else: try: for res,name,Id in Chains[chain][residue][ires]: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue except KeyError: continue if all(ids): chiral = [list(ids),['1','1','1','1'],Value,Esd] if chiral not in chiralRestData['Volumes']: chiralRestData['Volumes'].append(chiral) ids = [0,0,0,0] macStr = macro.readline() macro.close() print(' Found %d chiral volumes restraints'%len(chiralRestData['Volumes'])) UpdateChiralRestr(chiralRestData) def AddAATorsionRestraint(torsionRestData): macro = getMacroFile('torsion') if not macro: return Chains = makeChains(Names,Ids) macStr = macro.readline()[:-1] while macStr: items = macStr.split() if 'F' in items[0]: restrData['Torsion']['wtFactor'] = float(items[1]) elif 'A' in items[0]: name = items[10] coeff = np.zeros(9) for i,item in enumerate(items[1:10]): coeff[i] = float(item) torsionRestData['Coeff'][name] = coeff elif 'S' in items[0]: Name = items[1] Res = items[2] Esd = float(items[3]) Atms = items[4:8] pAtms = ['','','',''] for i,atm in enumerate(Atms): if '+' in atm: pAtms[i] = atm.strip('+') ids = [0,0,0,0] chains = list(Chains.keys()) chains.sort() for chain in chains: residues = list(Chains[chain].keys()) residues.sort() for residue in residues: for ires in [0,1]: if residue == residues[-1] and Res == '*': continue if Res != '*': #works with disordered res for res,name,Id in Chains[chain][residue][ires]: if Res == res: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue else: try: for res,name,Id in Chains[chain][residue][ires]: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue for res,name,Id in Chains[chain][residue+1][ires]: try: ipos = pAtms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue except KeyError: continue if all(ids): torsion = [list(ids),['1','1','1','1'],Name,Esd] if torsion not in torsionRestData['Torsions']: torsionRestData['Torsions'].append(torsion) ids = [0,0,0,0] macStr = macro.readline() macro.close() print(' Found %d torsion restraints'%len(torsionRestData['Torsions'])) UpdateTorsionRestr(torsionRestData) def AddAARamaRestraint(ramaRestData): macro = getMacroFile('Ramachandran') if not macro: return Chains = makeChains(Names,Ids) macStr = macro.readline() while macStr: items = macStr.split() if 'F' in items[0]: restrData['Rama']['wtFactor'] = float(items[1]) elif 'A' in items[0]: nTerms = int(items[1]) name = items[2] coeff = np.zeros((nTerms,6)) for i in range(nTerms): macStr = macro.readline() items = macStr.split() for j,val in enumerate(items): coeff[i][j] = float(val) ramaRestData['Coeff'][name] = coeff elif 'S' in items[0]: Name = items[1] Res = items[2] Esd = float(items[3]) Atms = items[4:9] mAtms = ['','','','',''] pAtms = ['','','','',''] for i,atm in enumerate(Atms): if '+' in atm: pAtms[i] = atm.strip('+') elif '-' in atm: mAtms[i] = atm.strip('-') ids = [0,0,0,0,0] chains = list(Chains.keys()) chains.sort() for chain in chains: residues = list(Chains[chain].keys()) residues.sort() if not (any(mAtms) or any(pAtms)): for residue in residues: for ires in [0,1]: for res,name,Id in Chains[chain][residue][ires]: if Res == res: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue if all(ids): rama = [list(ids),['1','1','1','1','1'],Name,Esd] if rama not in ramaRestData['Ramas']: ramaRestData['Ramas'].append(rama) ids = [0,0,0,0,0] else: for ires,residue in enumerate(residues[1:-1]): for jres in [0,1]: try: for res,name,Id in Chains[chain][residue-1][jres]: try: ipos = mAtms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue for res,name,Id in Chains[chain][residue+1][jres]: try: ipos = pAtms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue for res,name,Id in Chains[chain][residue][jres]: if Res == res: try: ipos = Atms.index(name[:3].strip()) ids[ipos] = Id except ValueError: continue if all(ids): rama = [list(ids),['1','1','1','1','1'],Name,Esd] if rama not in ramaRestData['Ramas']: ramaRestData['Ramas'].append(rama) ids = [0,0,0,0,0] except KeyError: continue macStr = macro.readline() macro.close() print(' Found %d Ramachandran restraints'%len(ramaRestData['Ramas'])) UpdateRamaRestr(ramaRestData) def AddChemCompRestraint(chemcompRestData): ids = [] factors = [] dlg = G2G.G2MultiChoiceDialog(G2frame,'Select atoms for chemical restraint in '+General['Name'], 'Select atoms',Names) if dlg.ShowModal() == wx.ID_OK: sel = dlg.GetSelections() for x in sel: if 'all' in Names[x]: allType = Types[x] for name,Type,Id in zip(Names,Types,Ids): if Type == allType and 'all' not in name: ids.append(Id) factors.append(1.0) else: ids.append(Ids[x]) factors.append(1.0) dlg.Destroy() if len(ids) > 0: value = 1.0 dlg = G2G.SingleFloatDialog(G2frame,'Cell sum','Enter unit cell sum ',value,[-1.e6,1.e6],'%.2f') if dlg.ShowModal() == wx.ID_OK: value = dlg.GetValue() comp = [ids,factors,value,0.01] if comp not in chemcompRestData['Sites']: chemcompRestData['Sites'].append(comp) UpdateChemcompRestr(chemcompRestData) else: print ('**** ERROR - not enough atoms for a composition restraint - try again ****') def AddMomentRestraint(momentRestData): ids = [] dlg = G2G.G2MultiChoiceDialog(G2frame,'Select 2 or more atoms for average moment restraint in '+General['Name'], 'Select 2+ atoms',Names[iBeg:]) if dlg.ShowModal() == wx.ID_OK: sel = dlg.GetSelections() if len(sel) > 1: for x in sel: ids.append(Ids[x+iBeg]) moment = [ids,0.0,0.01] if moment not in momentRestData['Moments']: momentRestData['Moments'].append(moment) else: print ('**** ERROR - not enough atoms for a average moment restraint - try again ****') UpdateMomentRestr(momentRestData) def AddSpinRBRestraint(spinRestData): SpinRB = RBModels.get('Spin',[]) indx = [item['Ids'][0] for item in SpinRB] Snames = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) dlg = G2G.G2MultiChoiceDialog(G2frame,'Select atoms for negative spin RB restraint in '+General['Name'], 'Select atoms',Snames) if dlg.ShowModal() == wx.ID_OK: sels = dlg.GetSelections() for sel in sels: minspin = [indx[sel],0.01,False,1.0] #spin atom id, esd, unit flag, unit esd if minspin not in spinRestData['SpinRBs']: spinRestData['SpinRBs'].append(minspin) UpdateSpinRBRestr(spinRestData) def AddTextureRestraint(textureRestData): dlg = wx.TextEntryDialog(G2frame,'Enter h k l for pole figure restraint','Enter HKL','') if dlg.ShowModal() == wx.ID_OK: text = dlg.GetValue() vals = text.split() try: hkl = [int(vals[i]) for i in range(3)] texture = [hkl,24,0.01,False,1.0] if texture not in textureRestData['HKLs']: textureRestData['HKLs'].append(texture) UpdateTextureRestr(textureRestData) except (ValueError,IndexError): print ('**** ERROR - bad input of h k l - try again ****') dlg.Destroy() def WtBox(wind,restData): def OnUseData(event): Obj = event.GetEventObject() restData['Use'] = Obj.GetValue() wtBox = wx.BoxSizer(wx.HORIZONTAL) wtBox.Add(wx.StaticText(wind,-1,'Phase '+phaseName+' Restraint weight factor: '),0,WACV) wtfactor = G2G.ValidatedTxtCtrl(wind,restData,'wtFactor',nDig=(10,2,'g'),typeHint=float) wtBox.Add(wtfactor,0,WACV) useData = wx.CheckBox(wind,-1,label=' Use?') useData.Bind(wx.EVT_CHECKBOX, OnUseData) useData.SetValue(restData['Use']) wtBox.Add(useData,0,WACV) if 'Bonds' in restData or 'Angles' in restData: restData['Range'] = restData.get('Range',1.1) wtBox.Add(wx.StaticText(wind,-1,' Search range: '),0,WACV) sRange = G2G.ValidatedTxtCtrl(wind,restData,'Range',nDig=(10,2),typeHint=float) wtBox.Add(sRange,0,WACV) if 'Bonds' in restData: wtBox.Add(wx.StaticText(wind,-1,' x target dist.'),0,WACV) if 'Angles' in restData: wtBox.Add(wx.StaticText(wind,-1,' x sum(atom radii)'),0,WACV) return wtBox def OnRowSelect(event): r,c = event.GetRow(),event.GetCol() Obj = event.GetEventObject() if r < 0 and c < 0: if Obj.IsSelection(): Obj.ClearSelection() else: for row in range(Obj.GetNumberRows()): Obj.SelectRow(row,True) elif c < 0: #only row clicks if event.ControlDown(): if r in Obj.GetSelectedRows(): Obj.DeselectRow(r) else: Obj.SelectRow(r,True) elif event.ShiftDown(): indxs = Obj.GetSelectedRows() Obj.ClearSelection() ibeg = 0 if indxs: ibeg = indxs[-1] for row in range(ibeg,r+1): Obj.SelectRow(row,True) else: Obj.ClearSelection() Obj.SelectRow(r,True) def UpdateBondRestr(bondRestData): def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: new = float(bondTable.GetValue(r,c)) if new <= 0.: raise ValueError bondRestData['Bonds'][r][c] = new except ValueError: pass wx.CallAfter(UpdateBondRestr,bondRestData) def OnChangeValue(event): rows = GetSelectedRows(Bonds) if not rows: return Bonds.ClearSelection() val = bondList[rows[0]][2] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new value for bond',val,[0.,5.],'%.4f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: bondRestData['Bonds'][r][2] = parm dlg.Destroy() UpdateBondRestr(bondRestData) def OnChangeEsd(event): rows = GetSelectedRows(Bonds) if not rows: return Bonds.ClearSelection() val = bondList[rows[0]][3] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for bond',val,[0.,1.],'%.4f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: bondRestData['Bonds'][r][3] = parm dlg.Destroy() UpdateBondRestr(bondRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(Bonds,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return Bonds.ClearSelection() rows.sort() rows.reverse() for row in rows: bondList.remove(bondList[row]) UpdateBondRestr(bondRestData) try: if BondRestr.GetSizer(): BondRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(BondRestr,bondRestData),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) bondList = bondRestData['Bonds'] if len(bondList) and len(bondList[0]) == 6: #patch bondList = bondRestData['Bonds'] = [] if len(bondList): table = [] rowLabels = [] bad = [] chisq = 0. Types = [wg.GRID_VALUE_STRING,]+4*[wg.GRID_VALUE_FLOAT+':10,3',] if 'macro' in General['Type']: colLabels = ['(res) A - (res) B','calc','target','esd','delt/sig'] for i,[indx,ops,obs,esd] in enumerate(bondList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '' for atom in atoms: name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - ' XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) calc = G2mth.getRestDist(XYZ,Amat) chisq += bondRestData['wtFactor']*((obs-calc)/esd)**2 table.append([name[:-3],calc,obs,esd,(obs-calc)/esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) else: colLabels = ['A+SymOp - B+SymOp','calc','target','esd','delt/sig'] for i,[indx,ops,obs,esd] in enumerate(bondList): try: names = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) XYZ = G2mth.getSyXYZ(XYZ,ops,SGData) calc = G2mth.getRestDist(XYZ,Amat) chisq += bondRestData['wtFactor']*((obs-calc)/esd)**2 table.append([names[0]+'+('+ops[0]+') - '+names[1]+'+('+ops[1]+')',calc,obs,esd,(obs-calc)/esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del bondList[ibad] if len(bondList): bondTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Bonds = G2G.GSGrid(BondRestr) Bonds.SetTable(bondTable, True) Bonds.AutoSizeColumns(False) for c in [0,1,4]: # format read-only rows attr = wx.grid.GridCellAttr() attr.IncRef() attr.SetBackgroundColour(VERY_LIGHT_GREY) attr.SetReadOnly(True) Bonds.SetColAttr(c, attr) Bonds.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) Bonds.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) G2frame.Bind(wx.EVT_MENU, OnChangeValue, id=G2G.wxID_RESRCHANGEVAL) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(BondRestr,wx.ID_ANY, f'Bond restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(bondList):.2f}' ),0) Bonds.SetScrollRate(10,10) Bonds.SetMinSize((-1,300)) mainSizer.Add(Bonds,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(BondRestr,-1,'No bond distance restraints for this phase'),0,) else: mainSizer.Add(wx.StaticText(BondRestr,-1,'No bond distance restraints for this phase'),0,) wx.CallAfter(G2phsGUI.SetPhaseWindow,BondRestr,mainSizer,Scroll=0) def UpdateAngleRestr(angleRestData): def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: new = float(angleTable.GetValue(r,c)) if new <= 0. or new > 180.: raise ValueError angleRestData['Angles'][r][c] = new except ValueError: pass wx.CallAfter(UpdateAngleRestr,angleRestData) def OnChangeValue(event): rows = GetSelectedRows(Angles) if not rows: return Angles.ClearSelection() val = angleList[rows[0]][2] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new value for angle',val,[0.,360.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: angleRestData['Angles'][r][2] = parm dlg.Destroy() UpdateAngleRestr(angleRestData) def OnChangeEsd(event): rows = GetSelectedRows(Angles) if not rows: return Angles.ClearSelection() val = angleList[rows[0]][3] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for angle',val,[0.,5.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: angleRestData['Angles'][r][3] = parm dlg.Destroy() UpdateAngleRestr(angleRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(Angles,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: angleList.remove(angleList[row]) UpdateAngleRestr(angleRestData) try: if AngleRestr.GetSizer(): AngleRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(AngleRestr,angleRestData),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) angleList = angleRestData['Angles'] if len(angleList): table = [] rowLabels = [] bad = [] chisq = 0. Types = [wg.GRID_VALUE_STRING,]+4*[wg.GRID_VALUE_FLOAT+':10,2',] if 'macro' in General['Type']: colLabels = ['(res) A - (res) B - (res) C','calc','target','esd','delt/sig'] for i,[indx,ops,obs,esd] in enumerate(angleList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '' for atom in atoms: name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - ' XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) calc = G2mth.getRestAngle(XYZ,Amat) chisq += angleRestData['wtFactor']*((obs-calc)/esd)**2 table.append([name[:-3],calc,obs,esd,(obs-calc)/esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) else: colLabels = ['A+SymOp - B+SymOp - C+SymOp','calc','target','esd','delt/sig'] for i,[indx,ops,obs,esd] in enumerate(angleList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) name = atoms[0]+'+('+ops[0]+') - '+atoms[1]+'+('+ops[1]+') - '+atoms[2]+ \ '+('+ops[2]+')' XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) XYZ = G2mth.getSyXYZ(XYZ,ops,SGData) calc = G2mth.getRestAngle(XYZ,Amat) chisq += angleRestData['wtFactor']*((obs-calc)/esd)**2 table.append([name,calc,obs,esd,(obs-calc)/esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del angleList[ibad] if len(angleList): angleTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Angles = G2G.GSGrid(AngleRestr) Angles.SetTable(angleTable, True) Angles.AutoSizeColumns(False) for c in [0,1,4]: # format readonly columns attr = wx.grid.GridCellAttr() attr.IncRef() attr.SetBackgroundColour(VERY_LIGHT_GREY) attr.SetReadOnly(True) Angles.SetColAttr(c, attr) Angles.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) Angles.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) G2frame.Bind(wx.EVT_MENU, OnChangeValue, id=G2G.wxID_RESRCHANGEVAL) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(AngleRestr,wx.ID_ANY, f'Angle restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(angleList):.2f}' ),0) Angles.SetScrollRate(10,10) Angles.SetMinSize((-1,300)) mainSizer.Add(Angles,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(AngleRestr,-1,'No bond angle restraints for this phase'),0,) else: mainSizer.Add(wx.StaticText(AngleRestr,-1,'No bond angle restraints for this phase'),0,) wx.CallAfter(G2phsGUI.SetPhaseWindow,AngleRestr,mainSizer,Scroll=0) def UpdatePlaneRestr(planeRestData): items = G2frame.dataWindow.RestraintEdit.GetMenuItems() for item in items: if item.GetItemLabelText() in ['Change value']: item.Enable(False) def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: new = float(planeTable.GetValue(r,c)) if new <= 0.: raise ValueError planeRestData['Planes'][r][c] = new except ValueError: pass wx.CallAfter(UpdatePlaneRestr,planeRestData) def OnChangeEsd(event): rows = GetSelectedRows(Planes) if not rows: return Planes.ClearSelection() val = planeList[rows[0]][3] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for plane',val,[0.,5.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: planeRestData['Planes'][r][3] = parm dlg.Destroy() UpdatePlaneRestr(planeRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(Planes,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: planeList.remove(planeList[row]) UpdatePlaneRestr(planeRestData) try: if PlaneRestr.GetSizer(): PlaneRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(PlaneRestr,planeRestData),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) planeList = planeRestData['Planes'] if len(planeList): table = [] rowLabels = [] bad = [] chisq = 0. Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',] if 'macro' in General['Type']: colLabels = ['(res) atom','calc','target','esd'] for i,[indx,ops,obs,esd] in enumerate(planeList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '' for a,atom in enumerate(atoms): name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - ' if (a+1)%3 == 0: name += '\n' XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) calc = G2mth.getRestPlane(XYZ,Amat) chisq += planeRestData['wtFactor']*((calc)/esd)**2 table.append([name[:-3],calc,obs,esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) else: colLabels = ['atom+SymOp','calc','target','esd'] for i,[indx,ops,obs,esd] in enumerate(planeList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) XYZ = G2mth.getSyXYZ(XYZ,ops,SGData) calc = G2mth.getRestPlane(XYZ,Amat) chisq += planeRestData['wtFactor']*((calc)/esd)**2 name = '' for a,atom in enumerate(atoms): name += atom+'+ ('+ops[a]+'),' if (a+1)%3 == 0: name += '\n' table.append([name[:-1],calc,obs,esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del planeList[ibad] if len(planeList): planeTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Planes = G2G.GSGrid(PlaneRestr) Planes.SetTable(planeTable, True) Planes.AutoSizeColumns(False) Planes.AutoSizeRows(False) for r in range(len(planeList)): for c in range(3): Planes.SetReadOnly(r,c,True) Planes.SetCellStyle(r,c,VERY_LIGHT_GREY,True) Planes.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) Planes.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(PlaneRestr,-1, f'Plane restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(planeList):.2f}' ),0) Planes.SetScrollRate(10,10) Planes.SetMinSize((-1,300)) mainSizer.Add(Planes,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(PlaneRestr,-1,'No plane restraints for this phase'),0,) else: mainSizer.Add(wx.StaticText(PlaneRestr,-1,'No plane restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(PlaneRestr,mainSizer,Scroll=0) def UpdateChiralRestr(chiralRestData): def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: new = float(volumeTable.GetValue(r,c)) if new <= 0.: raise ValueError chiralRestData['Volumes'][r][c] = new except ValueError: pass wx.CallAfter(UpdateChiralRestr,chiralRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(Volumes,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: volumeList.remove(volumeList[row]) UpdateChiralRestr(chiralRestData) def OnChangeValue(event): rows = GetSelectedRows(Volumes) if not rows: return Volumes.ClearSelection() val = volumeList[rows[0]][2] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new value for chiral volume',val,[0.,360.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: chiralRestData['Volumes'][r][2] = parm dlg.Destroy() UpdateChiralRestr(chiralRestData) def OnChangeEsd(event): rows = GetSelectedRows(Volumes) if not rows: return Volumes.ClearSelection() val = volumeList[rows[0]][3] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for chiral volume',val,[0.,5.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: chiralRestData['Volumes'][r][3] = parm dlg.Destroy() UpdateChiralRestr(chiralRestData) try: if ChiralRestr.GetSizer(): ChiralRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(ChiralRestr,chiralRestData),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) volumeList = chiralRestData['Volumes'] if len(volumeList): table = [] rowLabels = [] bad = [] chisq = 0. Types = [wg.GRID_VALUE_STRING,]+4*[wg.GRID_VALUE_FLOAT+':10,2',] if 'macro' in General['Type']: colLabels = ['(res) O (res) A (res) B (res) C','calc','target','esd','delt/sig'] for i,[indx,ops,obs,esd] in enumerate(volumeList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '' for atom in atoms: name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' ' XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) calc = G2mth.getRestChiral(XYZ,Amat) chisq += chiralRestData['wtFactor']*((obs-calc)/esd)**2 table.append([name,calc,obs,esd,(obs-calc)/esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) else: colLabels = ['O+SymOp A+SymOp B+SymOp C+SymOp)','calc','target','esd','delt/sig'] for i,[indx,ops,obs,esd] in enumerate(volumeList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) name = atoms[0]+'+('+ops[0]+') '+atoms[1]+'+('+ops[1]+') '+atoms[2]+ \ '+('+ops[2]+') '+atoms[3]+'+('+ops[3]+')' XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) XYZ = G2mth.getSyXYZ(XYZ,ops,SGData) calc = G2mth.getRestChiral(XYZ,Amat) chisq += chiralRestData['wtFactor']*((obs-calc)/esd)**2 table.append([name,calc,obs,esd,(obs-calc)/esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del volumeList[ibad] if len(volumeList): volumeTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Volumes = G2G.GSGrid(ChiralRestr) Volumes.SetTable(volumeTable, True) Volumes.AutoSizeColumns(False) for r in range(len(volumeList)): for c in [0,1,4]: Volumes.SetReadOnly(r,c,True) Volumes.SetCellStyle(r,c,VERY_LIGHT_GREY,True) Volumes.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) Volumes.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnChangeValue, id=G2G.wxID_RESRCHANGEVAL) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(ChiralRestr,-1, f'Chiral volume restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(volumeList):.2f}' ),0) Volumes.SetScrollRate(10,10) Volumes.SetMinSize((-1,300)) mainSizer.Add(Volumes,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(ChiralRestr,-1,'No chiral volume restraints for this phase'),0,) else: mainSizer.Add(wx.StaticText(ChiralRestr,-1,'No chiral volume restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(ChiralRestr,mainSizer,Scroll=0) def UpdateTorsionRestr(torsionRestData): def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: new = float(torsionTable.GetValue(r,c)) if new <= 0. or new > 5.: raise ValueError torsionRestData['Torsions'][r][3] = new #only esd is editable except ValueError: pass wx.CallAfter(UpdateTorsionRestr,torsionRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(TorsionRestr.Torsions,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: torsionList.remove(torsionList[row]) wx.CallAfter(UpdateTorsionRestr,torsionRestData) def OnChangeEsd(event): rows = GetSelectedRows(TorsionRestr.Torsions) if not rows: return TorsionRestr.Torsions.ClearSelection() val = torsionList[rows[0]][4] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for torsion restraints',val,[0.,5.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: torsionRestData['Torsions'][r][4] = parm dlg.Destroy() wx.CallAfter(UpdateTorsionRestr,torsionRestData) def coeffSizer(): table = [] rowLabels = [] Types = 9*[wg.GRID_VALUE_FLOAT+':10,4',] colLabels = ['Mag A','Pos A','Width A','Mag B','Pos B','Width B','Mag C','Pos C','Width C'] for item in coeffDict: rowLabels.append(item) table.append(coeffDict[item]) coeffTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Coeff = G2G.GSGrid(TorsionRestr) Coeff.SetScrollRate(0,10) Coeff.SetTable(coeffTable, True) Coeff.AutoSizeColumns(False) for r in range(len(coeffDict)): for c in range(9): Coeff.SetReadOnly(r,c,True) Coeff.SetCellStyle(r,c,VERY_LIGHT_GREY,True) Coeff.SetMaxSize((-1,200)) return Coeff try: if TorsionRestr.GetSizer(): TorsionRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(TorsionRestr,torsionRestData),0) coeffDict = torsionRestData['Coeff'] torsionList = torsionRestData['Torsions'] if len(coeffDict): mainSizer.Add((5,5)) mainSizer.Add(wx.StaticText(TorsionRestr,-1,'Torsion function coefficients:'),0) mainSizer.Add(coeffSizer(),1,wx.EXPAND,1) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) if len(torsionList): mainSizer.Add(wx.StaticText(TorsionRestr,-1,'Torsion restraints:'),0) table = [] rowLabels = [] bad = [] chisq = 0. Types = 2*[wg.GRID_VALUE_STRING,]+4*[wg.GRID_VALUE_FLOAT+':10,2',] if 'macro' in General['Type']: colLabels = ['(res) A B C D','coef name','torsion','obs E','restr','esd'] for i,[indx,ops,cofName,esd] in enumerate(torsionList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '('+atoms[2][1]+atoms[2][0].strip()+atoms[2][2]+')' for atom in atoms: name += ' '+atom[3] XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) tor = G2mth.getRestTorsion(XYZ,Amat) restr,calc = G2mth.calcTorsionEnergy(tor,coeffDict[cofName]) chisq += torsionRestData['wtFactor']*(restr/esd)**2 table.append([name,cofName,tor,calc,restr,esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del torsionList[ibad] torsionTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) TorsionRestr.Torsions = G2G.GSGrid(TorsionRestr) TorsionRestr.Torsions.SetTable(torsionTable, True) TorsionRestr.Torsions.AutoSizeColumns(False) for r in range(len(torsionList)): for c in range(5): TorsionRestr.Torsions.SetReadOnly(r,c,True) TorsionRestr.Torsions.SetCellStyle(r,c,VERY_LIGHT_GREY,True) TorsionRestr.Torsions.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) TorsionRestr.Torsions.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(TorsionRestr,-1, f'Torsion restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(torsionList):.2f}' ),0) TorsionRestr.Torsions.SetScrollRate(10,10) TorsionRestr.Torsions.SetMinSize((-1,300)) mainSizer.Add(TorsionRestr.Torsions,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(TorsionRestr,-1,'No torsion restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(TorsionRestr,mainSizer,Scroll=0) def UpdateRamaRestr(ramaRestData): def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: new = float(ramaTable.GetValue(r,c)) if new <= 0. or new > 5.: raise ValueError ramaRestData['Ramas'][r][4] = new #only esd is editable except ValueError: pass wx.CallAfter(UpdateRamaRestr,ramaRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(RamaRestr.Ramas,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: ramaList.remove(ramaList[row]) UpdateRamaRestr(ramaRestData) def OnChangeEsd(event): rows = GetSelectedRows(RamaRestr.Ramas) if not rows: return RamaRestr.Ramas.ClearSelection() val = ramaList[rows[0]][4] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for energy',val,[0.,5.],'%.2f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: ramaRestData['Ramas'][r][4] = parm dlg.Destroy() UpdateRamaRestr(ramaRestData) def coeffSizer(): table = [] rowLabels = [] Types = 6*[wg.GRID_VALUE_FLOAT+':10,4',] colLabels = ['Mag','Pos phi','Pos psi','sig(phi)','sig(psi)','sig(cov)'] for item in coeffDict: for i,term in enumerate(coeffDict[item]): rowLabels.append(item+' term:'+str(i)) table.append(term) coeffTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Coeff = G2G.GSGrid(RamaRestr) Coeff.SetScrollRate(0,10) Coeff.SetTable(coeffTable, True) Coeff.AutoSizeColumns(False) for r in range(Coeff.GetNumberRows()): for c in range(6): Coeff.SetReadOnly(r,c,True) Coeff.SetCellStyle(r,c,VERY_LIGHT_GREY,True) Coeff.SetMaxSize((-1,200)) return Coeff try: if RamaRestr.GetSizer(): RamaRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(RamaRestr,ramaRestData),0) ramaList = ramaRestData['Ramas'] coeffDict = ramaRestData['Coeff'] if len(coeffDict): mainSizer.Add(wx.StaticText(RamaRestr,-1,'Ramachandran function coefficients:'),0) mainSizer.Add(coeffSizer(),1,wx.EXPAND,1) if len(ramaList): mainSizer.Add(wx.StaticText(RamaRestr,-1,'Ramachandran restraints:'),0) table = [] rowLabels = [] bad = [] chisq = 0. Types = 2*[wg.GRID_VALUE_STRING,]+5*[wg.GRID_VALUE_FLOAT+':10,2',] if 'macro' in General['Type']: colLabels = ['(res) A B C D E','coef name','phi','psi','obs E','restr','esd'] for i,[indx,ops,cofName,esd] in enumerate(ramaList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4) name = '('+atoms[3][1]+atoms[3][0].strip()+atoms[3][2]+')' for atom in atoms: name += ' '+atom[3] XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3)) phi,psi = G2mth.getRestRama(XYZ,Amat) restr,calc = G2mth.calcRamaEnergy(phi,psi,coeffDict[cofName]) chisq += ramaRestData['wtFactor']*(restr/esd)**2 table.append([name,cofName,phi,psi,calc,restr,esd]) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del ramaList[ibad] for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) if len(ramaList): ramaTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) RamaRestr.Ramas = G2G.GSGrid(RamaRestr) RamaRestr.Ramas.SetTable(ramaTable, True) RamaRestr.Ramas.AutoSizeColumns(False) for r in range(len(ramaList)): for c in range(6): RamaRestr.Ramas.SetReadOnly(r,c,True) RamaRestr.Ramas.SetCellStyle(r,c,VERY_LIGHT_GREY,True) RamaRestr.Ramas.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) RamaRestr.Ramas.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(RamaRestr,-1, f'Ramachandran restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(ramaList):.2f}' ),0) RamaRestr.Ramas.SetScrollRate(10,10) RamaRestr.Ramas.SetMinSize((-1,300)) mainSizer.Add(RamaRestr.Ramas,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(RamaRestr,-1,'No Ramachandran restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(RamaRestr,mainSizer,Scroll=0) def UpdateChemcompRestr(chemcompRestData): def OnCellChange(event): r,c = event.GetRow(),event.GetCol() rowLabl = ChemComps.GetRowLabelValue(r) row = int(rowLabl.split(':')[1]) if 'Restr' in rowLabl: try: new = float(chemcompTable.GetValue(r,c)) chemcompRestData['Sites'][row][c-2] = new #obsd or esd except ValueError: pass else: try: new = float(chemcompTable.GetValue(r,c)) id = int(rowLabl.split(':')[2]) chemcompRestData['Sites'][row][1][id] = new #only factor except ValueError: pass wx.CallAfter(UpdateChemcompRestr,chemcompRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(ChemComps,'delete',G2frame) #rows = ChemComps.GetSelectedRows() G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return terms = [] restrs = [] for r in sorted(rows,reverse=True): rowLabl = ChemComps.GetRowLabelValue(r) if 'Restr' in rowLabl: restrs.append(int(rowLabl.split(':')[1])) else: terms.append([int(i) for i in rowLabl.split(':')[1:]]) # delete terms first in case someone deletes a term in a restraint to be deleted for row,term in terms: del chemcompList[row][0][term] del chemcompList[row][1][term] for row in restrs: del chemcompList[row] UpdateChemcompRestr(chemcompRestData) # def OnChangeValue(event): # rows = GetSelectedRows(ChemComps) # if not rows: # return # ChemComps.ClearSelection() # dlg = G2G.SingleFloatDialog(G2frame,'New value', # 'Enter new value for restraint multiplier',1.0,[-1.e6,1.e6],'%.2f') # if dlg.ShowModal() == wx.ID_OK: # parm = dlg.GetValue() # for r in rows: # rowLabl = ChemComps.GetRowLabelValue(r) # if 'term' in rowLabl: # items = rowLabl.split(':') # chemcompRestData['Sites'][int(items[1])][1][int(items[2])] = parm # dlg.Destroy() # UpdateChemcompRestr(chemcompRestData) try: if ChemCompRestr.GetSizer(): ChemCompRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(ChemCompRestr,chemcompRestData),0) mainSizer.Add(wx.StaticText(ChemCompRestr,-1, 'NB: The chemical restraint sum is over the unit cell contents'),0) mainSizer.Add((5,5),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) chemcompList = chemcompRestData['Sites'] if len(chemcompList): table = [] rowLabels = [] bad = [] chisq = 0. Types = [wg.GRID_VALUE_STRING,]+5*[wg.GRID_VALUE_FLOAT+':10,2',] colLabels = ['Atoms','mul*frac','factor','calc','target','esd'] for i,[indx,factors,obs,esd] in enumerate(chemcompList): try: atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) mul = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cs+1)) frac = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cs-1)) mulfrac = mul*frac calcs = mul*frac*factors chisq += chemcompRestData['wtFactor']*((obs-np.sum(calcs))/esd)**2 for iatm,[atom,mf,fr,clc] in enumerate(zip(atoms,mulfrac,factors,calcs)): table.append([atom,mf,fr,clc,'','']) rowLabels.append('term:'+str(i)+':'+str(iatm)) table.append(['(Sum)','','',np.sum(calcs),obs,esd]) rowLabels.append('Restr:'+str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) if len(bad): bad.reverse() for ibad in bad: del chemcompList[ibad] if len(chemcompList): chemcompTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) ChemComps = G2G.GSGrid(ChemCompRestr) ChemComps.SetTable(chemcompTable, True) ChemComps.AutoSizeColumns(False) for r in range(chemcompTable.GetNumberRows()): for c in range(2): ChemComps.SetReadOnly(r,c,True) ChemComps.SetCellStyle(r,c,VERY_LIGHT_GREY,True) if 'Restr' in ChemComps.GetRowLabelValue(r): for c in range(4): ChemComps.SetReadOnly(r,c,True) ChemComps.SetCellStyle(r,c,VERY_YELLOW,True) ChemComps.SetCellTextColour(r,1,VERY_YELLOW) # make spurious #'s disappear ChemComps.SetCellTextColour(r,2,VERY_YELLOW) else: for c in [3,4,5]: ChemComps.SetReadOnly(r,c,True) ChemComps.SetCellStyle(r,c,VERY_LIGHT_GREY,True) for c in [4,5]: ChemComps.SetCellTextColour(r,c,VERY_LIGHT_GREY) ChemComps.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) ChemComps.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) G2frame.dataWindow.RestraintEdit.Enable(id=G2G.wxID_RESTDELETE,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) #G2frame.Bind(wx.EVT_MENU, OnChangeValue, id=G2G.wxID_RESRCHANGEVAL) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(ChemCompRestr,-1, f'Chemical composition restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(chemcompList):.2f}' ),0) mainSizer.Add(ChemComps) else: mainSizer.Add(wx.StaticText(ChemCompRestr,-1,'No chemical composition restraints for this phase'),0,) else: mainSizer.Add(wx.StaticText(ChemCompRestr,-1,'No chemical composition restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(ChemCompRestr,mainSizer,Scroll=0) def UpdateMomentRestr(momentRestData): def OnChangeEsd(event): rows = GetSelectedRows(Moments) if not rows: return Moments.ClearSelection() val = momentList[rows[0]][-1] dlg = G2G.SingleFloatDialog(G2frame,'New value','Enter new esd for moments',val,[0.,5.],'%.3f') if dlg.ShowModal() == wx.ID_OK: parm = dlg.GetValue() for r in rows: momentRestData['Moments'][r][-1] = parm dlg.Destroy() UpdateMomentRestr(momentRestData) def OnDeleteRestraint(event): rows = GetSelectedRows(Moments,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: momentList.remove(momentList[row]) UpdateMomentRestr(momentRestData) try: if MomentRestr.GetSizer(): MomentRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(MomentRestr,momentRestData),0) mainSizer.Add((5,5),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) momentList = momentRestData['Moments'] if len(momentList): table = [] rowLabels = [] bad = [] chisq = 0. maxno = 0 for item in momentList: maxno = max(maxno,len(item[0])) colLabels = maxno*['atom','calc']+['target','esd'] Types = maxno*[wg.GRID_VALUE_STRING,wg.GRID_VALUE_FLOAT+':10,3']+2*[wg.GRID_VALUE_FLOAT+':10,3',] for i,[indx,obs,esd] in enumerate(momentList): try: sum = 0. atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1) Mom = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx+4,3)) line = [] for a,atom in enumerate(atoms): calc = G2mth.GetMag(Mom[a],Cell) sum += calc line += [atom,calc] line += (maxno-len(atoms))*['',''] obs = sum/len(atoms) line += [obs,esd] for a,atom in enumerate(atoms): chisq += momentRestData['wtFactor']*((obs-calc)/esd)**2 table.append(line) rowLabels.append(str(i)) except KeyError: print ('**** WARNING - missing atom - restraint deleted ****') bad.append(i) momentTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Moments = G2G.GSGrid(MomentRestr) Moments.SetTable(momentTable, True) Moments.AutoSizeColumns(False) Moments.AutoSizeRows(False) for r in range(len(momentList)): for c in range(maxno*2+1): Moments.SetReadOnly(r,c,True) Moments.SetCellStyle(r,c,VERY_LIGHT_GREY,True) if not c%2 and not Moments.GetCellValue(r,c): Moments.SetCellTextColour(r,c+1,VERY_LIGHT_GREY) Moments.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) G2frame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2G.wxID_RESTCHANGEESD) frac = '?' if 'chisq' in Rvals: frac = f"{100 * chisq / Rvals['chisq']:.1f}" mainSizer.Add(wx.StaticText(MomentRestr,-1, f'Moment restraints: sum(wt*(delt/sig)^2) = {chisq:.2f} ({frac}% of total \u03C7\u00b2), mean(wt*(delt/sig)^2) = {chisq/len(momentList):.2f}' ),0) Moments.SetScrollRate(10,10) Moments.SetMinSize((-1,300)) mainSizer.Add(Moments,1,wx.EXPAND,1) else: mainSizer.Add(wx.StaticText(MomentRestr,-1,'No magnetic moment restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(MomentRestr,mainSizer,Scroll=0) def UpdateTextureRestr(textureRestData): def OnDeleteRestraint(event): rows = GetSelectedRows(Textures,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: textureList.remove(textureList[row]) wx.CallAfter(UpdateTextureRestr,textureRestData) def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: if c == 1: #grid size new = int(textureTable.GetValue(r,c)) if new < 6 or new > 24: raise ValueError elif c in [2,4]: #esds new = float(textureTable.GetValue(r,c)) if new < -1. or new > 2.: raise ValueError else: new = textureTable.GetValue(r,c) textureRestData['HKLs'][r][c] = new except ValueError: pass wx.CallAfter(UpdateTextureRestr,textureRestData) try: if TextureRestr.GetSizer(): TextureRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(TextureRestr,textureRestData),0) mainSizer.Add(wx.StaticText(TextureRestr,-1, 'NB: The texture restraints suppress negative pole figure values for the selected HKLs\n' ' "unit esd" gives a bias toward a flatter polefigure'),0) mainSizer.Add((5,5),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) textureList = textureRestData['HKLs'] if len(textureList): table = [] rowLabels = [] Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_LONG,wg.GRID_VALUE_FLOAT+':10,2', wg.GRID_VALUE_BOOL,wg.GRID_VALUE_FLOAT+':10,2'] colLabels = ['HKL','grid','neg esd','use unit?','unit esd'] for i,[hkl,grid,esd1,ifesd2,esd2] in enumerate(textureList): table.append(['%d %d %d'%(hkl[0],hkl[1],hkl[2]),grid,esd1,ifesd2,esd2]) rowLabels.append(str(i)) textureTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) Textures = G2G.GSGrid(TextureRestr) Textures.SetTable(textureTable, True) Textures.AutoSizeColumns(False) for r in range(len(textureList)): Textures.SetReadOnly(r,0,True) Textures.SetCellStyle(r,0,VERY_LIGHT_GREY,True) if not textureTable.GetValue(r,3): Textures.SetReadOnly(r,4,True) Textures.SetCellStyle(r,4,VERY_LIGHT_GREY,True) Textures.SetCellTextColour(r,4,VERY_LIGHT_GREY) Textures.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) Textures.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) G2frame.dataWindow.RestraintEdit.Enable(id=G2G.wxID_RESTDELETE,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) mainSizer.Add(Textures,0,) else: mainSizer.Add(wx.StaticText(TextureRestr,-1,'No texture restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(TextureRestr,mainSizer,Scroll=0) def UpdateSpinRBRestr(spinRestData): def OnDeleteRestraint(event): rows = GetSelectedRows(SpinRBs,'delete',G2frame) G2frame.GetStatusBar().SetStatusText('',1) if not rows: G2frame.GetStatusBar().SetStatusText('First select restraints to be deleted',1) return rows.sort() rows.reverse() for row in rows: spinRestData['SpinRBs'].remove(spinRestData['SpinRBs'][row]) wx.CallAfter(UpdateSpinRBRestr,spinRestData) def OnCellChange(event): r,c = event.GetRow(),event.GetCol() try: if c in [1,3]: #esds new = float(spinRBTable.GetValue(r,c)) if new < -1. or new > 2.: raise ValueError else: new = spinRBTable.GetValue(r,c) spinRestData['SpinRBs'][r][c] = new except ValueError: pass wx.CallAfter(UpdateSpinRBRestr,spinRestData) try: if SpinRBRestr.GetSizer(): SpinRBRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) mainSizer.Add(WtBox(SpinRBRestr,spinRestData),0) mainSizer.Add(wx.StaticText(SpinRBRestr,-1, 'NB: The spin RB restraints suppress negative spin RB densities for the selected atoms'),0) # ' "unit esd" gives a bias toward a flatter spin RB density'),0) mainSizer.Add((5,5),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) if len(spinRestData['SpinRBs']): table = [] rowLabels = [] Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_FLOAT+':10,2'] colLabels = ['atom','neg esd'] for i,item in enumerate(spinRestData['SpinRBs']): if item[0] not in AtLookUp: del spinRestData['SpinRBs'][i] for i,[atomid,esd1,ifesd2,esd2] in enumerate(spinRestData['SpinRBs']): table.append(['%s'%G2mth.GetAtomItemsById(Atoms,AtLookUp,atomid,ct-1)[0],esd1]) rowLabels.append(str(i)) spinRBTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types) SpinRBs = G2G.GSGrid(SpinRBRestr) SpinRBs.SetTable(spinRBTable, True) SpinRBs.AutoSizeColumns(False) for r in range(len(spinRestData['SpinRBs'])): SpinRBs.SetReadOnly(r,0,True) SpinRBs.SetCellStyle(r,0,VERY_LIGHT_GREY,True) SpinRBs.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect) SpinRBs.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) G2frame.dataWindow.RestraintEdit.Enable(id=G2G.wxID_RESTDELETE,enable=True) G2frame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2G.wxID_RESTDELETE) mainSizer.Add(SpinRBs) else: mainSizer.Add(wx.StaticText(SpinRBRestr,-1,'No spin RB restraints for this phase'),0,) G2phsGUI.SetPhaseWindow(SpinRBRestr,mainSizer,Scroll=0) def UpdateGeneralRestr(generalRestData): '''Display any generalized restraint expressions''' def OnEditGenRestraint(event): '''Edit a restraint expression''' n = event.GetEventObject().index parmDict = SetupParmDict(G2frame) dlg = G2exG.ExpressionDialog(G2frame,parmDict, exprObj=generalRestData['General'][n][0], header="Edit a restraint expression", fit=False,wildCard=G2frame.testSeqRefineMode()) restobj = dlg.Show(True) if restobj: generalRestData['General'][n][0] = restobj wx.CallAfter(UpdateGeneralRestr,restrData['General']) def OnDelGenRestraint(event): #does this work?? '''Delete a restraint expression''' n = event.GetEventObject().index del restrData['General']['General'][n] wx.CallAfter(UpdateGeneralRestr,restrData['General']) try: if GeneralRestr.GetSizer(): GeneralRestr.GetSizer().Clear(True) except: pass mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add((5,5),0) hSizer = wx.BoxSizer(wx.HORIZONTAL) hSizer.Add(wx.StaticText(GeneralRestr,wx.ID_ANY,'Weight factor: ')) hSizer.Add(G2G.ValidatedTxtCtrl(GeneralRestr,generalRestData, 'wtFactor',nDig=(10,1),typeHint=float)) btn = G2G.G2CheckBox(GeneralRestr,'Use?',generalRestData,'Use') hSizer.Add(btn) hSizer.Add((5,5),0) btn = wx.Button(GeneralRestr, wx.ID_ANY,"Add restraint") btn.Bind(wx.EVT_BUTTON,OnAddRestraint) hSizer.Add(btn,0,wx.EXPAND|wx.ALL) mainSizer.Add(hSizer,0) mainSizer.Add((5,5),0) for i in (G2G.wxID_RESTDELETE,G2G.wxID_RESRCHANGEVAL,G2G.wxID_RESTCHANGEESD): G2frame.dataWindow.RestraintEdit.Enable(id=i,enable=False) if generalRestData['General']: parmDict = SetupParmDict(G2frame) GridSiz = wx.FlexGridSizer(0,9,10,2) GridSiz.Add((-1,-1)) GridSiz.Add( wx.StaticText(GeneralRestr,wx.ID_ANY,'Expression'), 0,wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL) GridSiz.Add((-1,-1)) # for lbl in ('expression',' ','target\nvalue','current\nvalue','esd'): for lbl in ('target\nvalue','current\nvalue','esd'): GridSiz.Add( wx.StaticText(GeneralRestr,wx.ID_ANY,lbl,style=wx.CENTER), 0,wx.ALIGN_CENTER) GridSiz.Add((-1,-1)) GridSiz.Add((-1,-1)) GridSiz.Add( wx.StaticText(GeneralRestr,wx.ID_ANY,'Variables',style=wx.CENTER), 0,wx.ALIGN_CENTER) for i,rest in enumerate(generalRestData['General']): eq = rest[0] txt = '{}: '.format(i+1) GridSiz.Add(wx.StaticText(GeneralRestr,wx.ID_ANY,txt)) txt = eq.expression if len(txt) > 50: txt = txt[:47]+'... ' txtC = wx.StaticText(GeneralRestr,wx.ID_ANY,txt) GridSiz.Add(txtC) GridSiz.Add(wx.StaticText(GeneralRestr,wx.ID_ANY,' = ')) GridSiz.Add( G2G.ValidatedTxtCtrl(GeneralRestr,rest,1,nDig=(10,3,'g'),typeHint=float) ) # evaluate the expression try: calcobj = G2obj.ExpressionCalcObj(rest[0]) calcobj.SetupCalc(parmDict) txt = ' {:f} '.format(calcobj.EvalExpression()) except: txt = ' (error) ' txtC.SetForegroundColour("red") GridSiz.Add(wx.StaticText(GeneralRestr,wx.ID_ANY,txt)) GridSiz.Add( G2G.ValidatedTxtCtrl(GeneralRestr,rest,2,nDig=(10,3,'g'),typeHint=float) ) btn = wx.Button(GeneralRestr, wx.ID_ANY,"Edit",size=(40,-1)) btn.index = i btn.Bind(wx.EVT_BUTTON,OnEditGenRestraint) GridSiz.Add(btn) btn = wx.Button(GeneralRestr, wx.ID_ANY,"Delete",size=(60,-1)) btn.index = i btn.Bind(wx.EVT_BUTTON,OnDelGenRestraint) GridSiz.Add(btn) txt = '' for i in eq.assgnVars: if txt: txt += '; ' txt += str(i) + '=' + str(eq.assgnVars[i]) if len(txt) > 50: txt = txt[:47]+'...' GridSiz.Add(wx.StaticText(GeneralRestr,wx.ID_ANY,txt)) mainSizer.Add(GridSiz) G2phsGUI.SetPhaseWindow(GeneralRestr,mainSizer,Scroll=0) def OnPageChanged(event): page = event.GetSelection() #G2frame.restrBook.SetSize(G2frame.dataWindow.GetClientSize()) #TODO -almost right text = G2frame.restrBook.GetPageText(page) G2frame.dataWindow.RestraintEdit.SetLabel(G2G.wxID_RESRCHANGEVAL,'Change target value') G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_USEMOGUL,False) if text == 'Bond': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_USEMOGUL,True) bondRestData = restrData['Bond'] UpdateBondRestr(bondRestData) elif text == 'Angle': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_USEMOGUL,True) angleRestData = restrData['Angle'] UpdateAngleRestr(angleRestData) elif text == 'Plane': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,False) planeRestData = restrData['Plane'] UpdatePlaneRestr(planeRestData) elif text == 'Chiral': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,False) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) chiralRestData = restrData['Chiral'] UpdateChiralRestr(chiralRestData) elif text == 'Torsion': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,False) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,False) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_AARESTRAINTPLOT,True) torsionRestData = restrData['Torsion'] UpdateTorsionRestr(torsionRestData) elif text == 'Ramachandran': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,False) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,False) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_AARESTRAINTPLOT,True) ramaRestData = restrData['Rama'] UpdateRamaRestr(ramaRestData) wx.CallAfter(G2plt.PlotRama,G2frame,phaseName,rama,ramaName) elif text == 'Chem. comp.': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.SetLabel(G2G.wxID_RESRCHANGEVAL,'Change factor') G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTCHANGEESD,False) chemcompRestData = restrData['ChemComp'] UpdateChemcompRestr(chemcompRestData) elif text == 'Texture': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) textureRestData = restrData['Texture'] UpdateTextureRestr(textureRestData) elif text == 'Spin RB': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) spinRBRestData = restrData['SpinRB'] UpdateSpinRBRestr(spinRBRestData) elif text == 'Moments': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,True) momentRestData = restrData['Moments'] UpdateMomentRestr(momentRestData) elif text == 'General': G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTRAINTADD,True) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESRCHANGEVAL,False) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_RESTCHANGEESD,False) UpdateGeneralRestr(restrData['General']) event.Skip() # def RaisePage(event): # 'Respond to a "select tab" menu button' # # class PseudoEvent(object): # # def __init__(self,page): self.page = page # # def Skip(self): pass # # def GetSelection(self): return self.page # try: # i = tabIndex.get(event.GetId()) # G2frame.restrBook.SetSelection(i) # #OnPageChanged(PseudoEvent(i)) # except ValueError: # print('Unexpected event in RaisePage') # def OnSelectPage(event): 'Called when an item is selected from the Select page menu' # lookup the menu item that called us and get its text tabname = TabSelectionIdDict.get(event.GetId()) if not tabname: print ('Warning: menu item not in dict! id= %d'%event.GetId()) return # find the matching tab for PageNum in range(G2frame.restrBook.GetPageCount()): if tabname == G2frame.restrBook.GetPageText(PageNum): G2frame.restrBook.SetSelection(PageNum) return else: print ("Warning: tab "+tabname+" was not found") #### UpdateRestraints execution starts here topSizer = G2frame.dataWindow.topBox topSizer.Clear(True) parent = G2frame.dataWindow.topPanel lbl= f"Create/edit restraints for {phaseName!r}"[:60] topSizer.Add(wx.StaticText(parent,label=lbl),0,WACV) topSizer.Add((-1,-1),1,wx.EXPAND) topSizer.Add(G2G.HelpButton(parent,helpIndex=G2frame.dataWindow.helpKey)) wx.CallAfter(G2frame.dataWindow.SetDataSize) G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) covdata = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Covariance')) Nvars = 0 Rvals = {} if 'Rvals' in covdata: Nvars = len(covdata['varyList']) Rvals = covdata['Rvals'] try: phasedata = G2frame.GetPhaseData()[phaseName] except KeyError: #delete unknown or previously deleted phases from Restraints # deleting phase without refresh can cause wx to crash #rId = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Restraints') #pId = G2gd.GetGPXtreeItemId(G2frame,rId,phaseName) #G2frame.GPXtree.Delete(pId) print('Unknown phase '+phaseName+' is deleted from Restraints') mainSizer = wx.BoxSizer(wx.VERTICAL) G2frame.dataWindow.SetSizer(mainSizer) mainSizer.Add( wx.StaticText(G2frame.dataWindow,-1,' Phase does not exist'),0) return restrData = data[phaseName] if 'Bond' not in restrData: restrData['Bond'] = {'wtFactor':1.0,'Range':1.1,'Bonds':[],'Use':True} if 'Angle' not in restrData: restrData['Angle'] = {'wtFactor':1.0,'Range':0.85,'Angles':[],'Use':True} if 'Plane' not in restrData: restrData['Plane'] = {'wtFactor':1.0,'Planes':[],'Use':True} if 'Chiral' not in restrData: restrData['Chiral'] = {'wtFactor':1.0,'Volumes':[],'Use':True} if 'Torsion' not in restrData: restrData['Torsion'] = {'wtFactor':1.0,'Coeff':{},'Torsions':[],'Use':True} if 'Rama' not in restrData: restrData['Rama'] = {'wtFactor':1.0,'Coeff':{},'Ramas':[],'Use':True} if 'Texture' not in restrData: restrData['Texture'] = {'wtFactor':1.0,'HKLs':[],'Use':True} if 'SpinRB' not in restrData: restrData['SpinRB'] = {'wtFactor':1.0,'SpinRBs':[],'Use':True} if 'ChemComp' not in restrData: restrData['ChemComp'] = {'wtFactor':1.0,'Sites':[],'Use':True} if 'General' not in restrData: restrData['General'] = {'wtFactor':1.0,'General':[], 'Use':True} General = phasedata['General'] RBModels = phasedata['RBModels'] if General['Type'] == 'magnetic' and 'Moments' not in restrData: restrData['Moments'] = {'wtFactor':1.0,'Moments':[],'Use':True} Cell = General['Cell'][1:7] #skip flag & volume Amat,Bmat = G2lat.cell2AB(Cell) SGData = General['SGData'] cx,ct,cs,cia = General['AtomPtrs'] Atoms = phasedata['Atoms'] AtLookUp = G2mth.FillAtomLookUp(Atoms,cia+8) if 'macro' in General['Type']: Names = [atom[0]+':'+atom[1]+atom[2]+' '+atom[3].ljust(4) for atom in Atoms] Ids = [] Coords = [] Types = [] iBeg = 0 else: Names = ['all '+ name for name in General['AtomTypes']] iBeg = len(Names) Types = [name for name in General['AtomTypes']] Coords = [ [] for type in Types] Ids = [ 0 for type in Types] Names += [atom[ct-1] for atom in Atoms] Types += [atom[ct] for atom in Atoms] Coords += [atom[cx:cx+3] for atom in Atoms] Ids += [atom[cia+8] for atom in Atoms] rama = G2data.ramachandranDist['All'] ramaName = 'All' G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RestraintMenu) G2frame.Bind(wx.EVT_MENU, OnAddRestraint, id=G2G.wxID_RESTRAINTADD) G2frame.Bind(wx.EVT_MENU, OnUseMogul, id=G2G.wxID_USEMOGUL) G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_USEMOGUL,True) if 'macro' in phasedata['General']['Type']: G2frame.dataWindow.RestraintEdit.Enable(G2G.wxID_AARESTRAINTADD,True) G2frame.Bind(wx.EVT_MENU, OnAddAARestraint, id=G2G.wxID_AARESTRAINTADD) G2frame.Bind(wx.EVT_MENU, OnPlotAARestraint, id=G2G.wxID_AARESTRAINTPLOT) # GUI defined here G2frame.restrBook = G2G.GSNoteBook(parent=G2frame.dataWindow) mainSizer = wx.BoxSizer(wx.VERTICAL) G2frame.dataWindow.SetSizer(mainSizer) mainSizer.Add(G2frame.restrBook,1,wx.ALL|wx.EXPAND,1) # clear menu and menu pointers Pages = [] txt = 'Bond' BondRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(BondRestr,txt) Pages.append(txt) txt = 'Angle' AngleRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(AngleRestr,txt) Pages.append(txt) txt = 'Plane' PlaneRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(PlaneRestr,txt) Pages.append(txt) txt = 'Chiral' ChiralRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(ChiralRestr,txt) Pages.append(txt) if 'macro' in General['Type']: txt = 'Torsion' TorsionRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(TorsionRestr,txt) Pages.append(txt) txt = 'Ramachandran' RamaRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(RamaRestr,txt) Pages.append(txt) txt = 'Chem. comp.' ChemCompRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(ChemCompRestr,txt) Pages.append(txt) if 'magnetic' in General['Type']: txt = 'Moments' MomentRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(MomentRestr,txt) Pages.append(txt) txt = 'General' GeneralRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(GeneralRestr,txt) Pages.append(txt) if General['SH Texture']['Order']: txt = 'Texture' TextureRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(TextureRestr,txt) Pages.append(txt) UpdateBondRestr(restrData['Bond']) if 'Spin' in phasedata['RBModels'] and len(phasedata['RBModels']['Spin']): txt = 'Spin RB' SpinRBRestr = wx.ScrolledWindow(G2frame.restrBook) G2frame.restrBook.AddPage(SpinRBRestr,txt) Pages.append(txt) G2frame.restrBook.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged) # fill page selection menu menu = G2frame.dataWindow.RestraintTab for page in Pages: if menu.FindItem(page) >= 0: continue # is tab already in menu? Id = wx.NewId() TabSelectionIdDict[Id] = page menu.Append(Id,page,'') G2frame.Bind(wx.EVT_MENU, OnSelectPage, id=Id)