- Timestamp:
- May 24, 2020 5:19:15 PM (3 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/GSASIIconstrGUI.py
r4421 r4431 16 16 ''' 17 17 from __future__ import division, print_function 18 import platform 18 19 import sys 19 20 import copy … … 46 47 WACV = wx.ALIGN_CENTER_VERTICAL 47 48 49 class G2BoolEditor(wg.GridCellBoolEditor): 50 '''Substitute for wx.grid.GridCellBoolEditor except toggles 51 grid items immediately when opened, updates grid & table contents after every 52 item change 53 ''' 54 def __init__(self): 55 self.saveVals = None 56 wx.grid.GridCellBoolEditor.__init__(self) 57 58 59 def Create(self, parent, id, evtHandler): 60 '''Create the editing control (wx.CheckBox) when cell is opened 61 for edit 62 ''' 63 self._tc = wx.CheckBox(parent, -1, "") 64 self._tc.Bind(wx.EVT_CHECKBOX, self.onCheckSet) 65 self.SetControl(self._tc) 66 if evtHandler: 67 self._tc.PushEventHandler(evtHandler) 68 69 def onCheckSet(self, event): 70 '''Callback used when checkbox is toggled. 71 Makes change to table immediately (creating event) 72 ''' 73 if self.saveVals: 74 self.ApplyEdit(*self.saveVals) 75 76 77 def SetSize(self, rect): 78 '''Set position/size the edit control within the cell's rectangle. 79 ''' 80 # self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2, # older 81 self._tc.SetSize(rect.x, rect.y, rect.width+2, rect.height+2, 82 wx.SIZE_ALLOW_MINUS_ONE) 83 84 def BeginEdit(self, row, col, grid): 85 '''Prepares the edit control by loading the initial 86 value from the table (toggles it since you would not 87 click on it if you were not planning to change it), 88 buts saves the original, pre-change value. 89 Makes change to table immediately. 90 Saves the info needed to make updates in self.saveVals. 91 Sets the focus. 92 ''' 93 self.startValue = int(grid.GetTable().GetValue(row, col)) 94 self.saveVals = row, col, grid 95 # invert state and set in editor 96 if self.startValue: 97 grid.GetTable().SetValue(row, col, 0) 98 self._tc.SetValue(0) 99 else: 100 grid.GetTable().SetValue(row, col, 1) 101 self._tc.SetValue(1) 102 self._tc.SetFocus() 103 self.ApplyEdit(*self.saveVals) 104 105 def EndEdit(self, row, col, grid, oldVal=None): 106 '''End editing the cell. This is supposed to 107 return None if the value has not changed, but I am not 108 sure that actually works. 109 ''' 110 val = int(self._tc.GetValue()) 111 if val != oldVal: #self.startValue:? 112 return val 113 else: 114 return None 115 116 def ApplyEdit(self, row, col, grid): 117 '''Save the value into the table, and create event. 118 Called after EndEdit(), BeginEdit and onCheckSet. 119 ''' 120 val = int(self._tc.GetValue()) 121 grid.GetTable().SetValue(row, col, val) # update the table 122 123 def Reset(self): 124 '''Reset the value in the control back to its starting value. 125 ''' 126 self._tc.SetValue(self.startValue) 127 128 def StartingClick(self): 129 '''This seems to be needed for BeginEdit to work properly''' 130 pass 131 132 def Destroy(self): 133 "final cleanup" 134 super(G2BoolEditor, self).Destroy() 135 136 def Clone(self): 137 'required' 138 return G2BoolEditor() 139 48 140 class DragableRBGrid(wg.Grid): 49 141 '''Simple grid implentation for display of rigid body positions. … … 62 154 self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self) 63 155 self.SetColSize(0, 60) 64 self.SetColSize(1, 35)65 self.SetColSize( 5, 40)156 self.SetColSize(1, 40) 157 self.SetColSize(2, 35) 66 158 for r in range(len(rb['RBlbls'])): 67 159 self.SetReadOnly(r,0,isReadOnly=True) 68 self.SetCellEditor(r,2, wg.GridCellFloatEditor()) 160 self.SetCellEditor(r, 1, G2BoolEditor()) 161 self.SetCellRenderer(r, 1, wg.GridCellBoolRenderer()) 162 self.SetReadOnly(r,2,isReadOnly=True) 69 163 self.SetCellEditor(r,3, wg.GridCellFloatEditor()) 70 164 self.SetCellEditor(r,4, wg.GridCellFloatEditor()) 165 self.SetCellEditor(r,6, wg.GridCellFloatEditor()) 71 166 72 167 def OnRowMove(self,evt): … … 89 184 def __init__(self,rb,onChange): 90 185 wg.GridTableBase.__init__(self) 91 self.colLabels = ['Label',' Type','x','y','z','Select']186 self.colLabels = ['Label','Select','Type','x','y','z'] 92 187 self.coords = rb['RBcoords'] 93 188 self.labels = rb['RBlbls'] … … 109 204 return self.labels[row] 110 205 elif col == 1: 206 return int(self.select[row]) 207 elif col == 2: 111 208 return self.types[row] 112 elif col < 5: 113 return '{:.5f}'.format(self.coords[row][col-2]) 114 elif col == 5: 115 return self.select[row] 209 else: 210 return '{:.5f}'.format(self.coords[row][col-3]) 116 211 def SetValue(self, row, col, value): 117 212 row = self.index[row] 118 if col == 0: 119 self.labels[row] = value 120 elif col == 1: 121 self.types[row] = value 122 elif col < 5: 123 self.coords[row][col-2] = float(value) 124 elif col == 5: 125 self.select[row] = value 213 try: 214 if col == 0: 215 self.labels[row] = value 216 elif col == 1: 217 self.select[row] = int(value) 218 elif col == 2: 219 self.types[row] = value 220 else: 221 self.coords[row][col-3] = float(value) 222 except: 223 pass 126 224 if self.onChange: 127 225 self.onChange() 128 # implement boolean for selection129 def GetTypeName(self, row, col):130 if col==5:131 return wg.GRID_VALUE_BOOL132 else:133 return wg.GRID_VALUE_STRING134 def CanGetValueAs(self, row, col, typeName):135 if col==5 and typeName != wg.GRID_VALUE_BOOL:136 return False137 return True138 139 226 # Display column & row labels 140 227 def GetColLabelValue(self, col): … … 2027 2114 def onSetAll(event): 2028 2115 'Set all atoms as selected' 2116 grid.completeEdits() 2029 2117 for i in range(len(rd.Phase['RBselection'])): 2030 rd.Phase['RBselection'][i] = True2118 rd.Phase['RBselection'][i] = 1 # table needs 0/1 for T/F 2031 2119 grid.ForceRefresh() 2032 2120 UpdateDraw() … … 2036 2124 grid.completeEdits() 2037 2125 for i in range(len(rd.Phase['RBselection'])): 2038 rd.Phase['RBselection'][i] = not rd.Phase['RBselection'][i]2126 rd.Phase['RBselection'][i] = int(not rd.Phase['RBselection'][i]) 2039 2127 grid.ForceRefresh() 2040 2128 UpdateDraw() … … 2063 2151 center += rd.Phase['RBcoords'][i] 2064 2152 if not count: 2153 G2G.G2MessageBox(G2frame,'No atoms selected', 2154 'Selection required') 2065 2155 return 2066 X P = center/count2067 if np.sqrt(sum(X P**2)) < 0.1:2156 XYZP = center/count 2157 if np.sqrt(sum(XYZP**2)) < 0.1: 2068 2158 G2G.G2MessageBox(G2frame, 2069 2159 'The selected atom(s) are too close to the origin', 2070 2160 'near origin') 2071 2161 return 2072 XP /= np.sqrt(np.sum(XP**2)) 2073 Z = np.array((0,0,1.)) 2074 YP = np.cross(Z,XP) 2075 ZP = np.cross(XP,YP) 2162 if bntOpts['direction'] == 'y': 2163 YP = XYZP / np.sqrt(np.sum(XYZP**2)) 2164 ZP = np.cross((1,0,0),YP) 2165 if sum(ZP*ZP) < .1: # pathological condition: Y' along X 2166 ZP = np.cross((0,0,1),YP) 2167 XP = np.cross(YP,ZP) 2168 elif bntOpts['direction'] == 'z': 2169 ZP = XYZP / np.sqrt(np.sum(XYZP**2)) 2170 XP = np.cross((0,1,0),ZP) 2171 if sum(XP*XP) < .1: # pathological condition: X' along Y 2172 XP = np.cross((0,0,1),ZP) 2173 YP = np.cross(ZP,XP) 2174 else: 2175 XP = XYZP / np.sqrt(np.sum(XYZP**2)) 2176 YP = np.cross((0,0,1),XP) 2177 if sum(YP*YP) < .1: # pathological condition: X' along Z 2178 YP = np.cross((0,1,0),XP) 2179 ZP = np.cross(XP,YP) 2076 2180 trans = np.array((XP,YP,ZP)) 2077 2181 # update atoms in place … … 2080 2184 UpdateDraw() 2081 2185 2082 def onSetPlane(event): 2186 def onSetPlane(event): 2083 2187 '''Compute least-squares plane for selected atoms; 2084 2188 move atoms so that LS plane aligned with x-y plane, … … 2086 2190 ''' 2087 2191 grid.completeEdits() 2088 #X,Y,Z = rd.Phase['RBcoords'][rd.Phase['RBselection']].T 2089 XYZ = rd.Phase['RBcoords'][rd.Phase['RBselection']] 2090 Z = copy.copy(XYZ[:,2]) 2091 if len(Z) < 3: 2192 selList = [i==1 for i in rd.Phase['RBselection']] 2193 XYZ = rd.Phase['RBcoords'][selList] 2194 if len(XYZ) < 3: 2092 2195 G2G.G2MessageBox(G2frame,'A plane requires three or more atoms', 2093 2196 'Need more atoms') 2094 2197 return 2095 XY0 = copy.copy(XYZ) 2096 XY0[:,2] = 1 2198 # fit 3 ways (in case of singularity) and take result with lowest residual 2199 X,Y,Z = [XYZ[:,i] for i in (0,1,2)] 2200 XZ = copy.copy(XYZ) 2201 XZ[:,1] = 1 2202 (a,d,b), resd, rank, sing = nl.lstsq(XZ, -Y) 2203 resid_min = resd 2204 normal = a,1,b 2205 YZ = copy.copy(XYZ) 2206 YZ[:,0] = 1 2207 (d,a,b), resd, rank, sing = nl.lstsq(YZ, -X) 2208 if resid_min > resd: 2209 resid_min = resd 2210 normal = 1,a,b 2211 XY = copy.copy(XYZ) 2212 XY[:,2] = 1 2213 (a,b,d), resd, rank, sing = nl.lstsq(XY, -Z) 2214 if resid_min > resd: 2215 resid_min = resd 2216 normal = a,b,1 2097 2217 # solve for ax + bx + z + c = 0 or equivalently ax + bx + c = -z 2098 try: 2099 (a,b,c), resd, rank, sing = nl.lstsq(XY0, -Z) 2100 except: 2101 G2G.G2MessageBox(G2frame, 2102 'Error computing plane; are atoms in a line?', 2103 'Computation error') 2218 # try: 2219 # except: 2220 # G2G.G2MessageBox(G2frame, 2221 # 'Error computing plane; are atoms in a line?', 2222 # 'Computation error') 2223 # return 2224 if bntOpts['plane'] == 'xy': 2225 # new coordinate system is 2226 # ZP, z' normal to plane 2227 # YP, y' = z' cross x (= [0,1,-b]) 2228 # XP, x' = (z' cross x) cross z' 2229 # this puts XP as close as possible to X with XP & YP in plane 2230 ZP = np.array(normal) 2231 ZP /= np.sqrt(np.sum(ZP**2)) 2232 YP = np.cross(ZP,[1,0,0]) 2233 if sum(YP*YP) < .1: # pathological condition: z' along x 2234 YP = np.cross(ZP,[0,1,0]) 2235 YP /= np.sqrt(np.sum(YP**2)) 2236 XP = np.cross(YP,ZP) 2237 elif bntOpts['plane'] == 'yz': 2238 # new coordinate system is 2239 # XP, x' normal to plane 2240 # ZP, z' = x' cross y 2241 # YP, y' = (x' cross y) cross x' 2242 # this puts y' as close as possible to y with z' & y' in plane 2243 XP = np.array(normal) 2244 XP /= np.sqrt(np.sum(XP**2)) 2245 ZP = np.cross(XP,[0,1,0]) 2246 if sum(ZP*ZP) < .1: # pathological condition: x' along y 2247 ZP = np.cross(XP,(0,0,1)) 2248 ZP /= np.sqrt(np.sum(ZP**2)) 2249 YP = np.cross(ZP,XP) 2250 elif bntOpts['plane'] == 'xz': 2251 # new coordinate system is 2252 # YP, y' normal to plane 2253 # ZP, z' = x cross y' 2254 # XP, y' = (x cross y') cross z' 2255 # this puts XP as close as possible to X with XP & YP in plane 2256 YP = np.array(normal) 2257 YP /= np.sqrt(np.sum(YP**2)) 2258 ZP = np.cross([1,0,0],YP) 2259 if sum(ZP*ZP) < .1: # pathological condition: y' along x 2260 ZP = np.cross([0,1,0],YP) 2261 ZP /= np.sqrt(np.sum(ZP**2)) 2262 XP = np.cross(YP,ZP) 2263 else: 2264 print('unexpected plane',bntOpts['plane']) 2104 2265 return 2105 # new coordinate system is z' (zp, normal to plane = [a,b,1]),2106 # y' = z' cross x (YP, = [0,1,-b])2107 # x' = (z' cross x) cross z'2108 # this puts XP as close as possible to X with XP & YP in plane2109 ZP = np.array([a,b,1])2110 ZP /= np.sqrt(np.sum(ZP**2))2111 YP = np.array([0,1,-b])2112 YP /= np.sqrt(np.sum(YP**2))2113 XP = np.cross(YP,ZP)2114 2266 trans = np.array((XP,YP,ZP)) 2115 2267 # update atoms in place … … 2184 2336 2185 2337 rd.Phase['RBindex'] = list(range(len(rd.Phase['RBtypes']))) 2186 rd.Phase['RBselection'] = len(rd.Phase['RBtypes']) * [ True]2338 rd.Phase['RBselection'] = len(rd.Phase['RBtypes']) * [1] 2187 2339 rbData = MakeVectorBody() 2188 2340 DrawCallback = G2plt.PlotRigidBody(G2frame,'Vector', … … 2190 2342 2191 2343 mainSizer = wx.BoxSizer(wx.HORIZONTAL) 2192 gridSizer = wx.BoxSizer(wx.VERTICAL) 2193 grid = DragableRBGrid(RBImpPnl,rd.Phase,UpdateDraw) 2194 gridSizer.Add(grid) 2195 gridSizer.Add( 2344 btnSizer = wx.BoxSizer(wx.VERTICAL) 2345 btnSizer.Add( 2196 2346 wx.StaticText(RBImpPnl,wx.ID_ANY,'Reorder atoms by dragging'), 2197 2347 0,wx.ALL) 2198 mainSizer.Add(gridSizer) 2199 mainSizer.Add((5,5)) 2200 btnSizer = wx.BoxSizer(wx.VERTICAL) 2201 btn = wx.Button(RBImpPnl, wx.ID_OK, 'Set All') 2348 btnSizer.Add((-1,15)) 2349 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Set All') 2202 2350 btn.Bind(wx.EVT_BUTTON,onSetAll) 2203 2351 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 2204 btn = wx.Button(RBImpPnl, wx.ID_ OK, 'Toggle')2352 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Toggle') 2205 2353 btn.Bind(wx.EVT_BUTTON,onToggle) 2206 2354 btnSizer.Add(btn,0,wx.ALIGN_CENTER) … … 2210 2358 0,wx.ALL) 2211 2359 btnSizer.Add((-1,5)) 2212 btn = wx.Button(RBImpPnl, wx.ID_ OK, 'Set origin')2360 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Set origin') 2213 2361 btn.Bind(wx.EVT_BUTTON,onSetOrigin) 2214 2362 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 2215 btn = wx.Button(RBImpPnl, wx.ID_OK, 'Place in xy plane') 2363 2364 bntOpts = {'plane':'xy','direction':'x'} 2365 inSizer = wx.BoxSizer(wx.HORIZONTAL) 2366 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Place in plane') 2216 2367 btn.Bind(wx.EVT_BUTTON,onSetPlane) 2217 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 2218 btn = wx.Button(RBImpPnl, wx.ID_OK, 'Define selection as X') 2368 inSizer.Add(btn) 2369 inSizer.Add(G2G.G2ChoiceButton(RBImpPnl,('xy','yz','xz'), 2370 None,None,bntOpts,'plane')) 2371 btnSizer.Add(inSizer,0,wx.ALIGN_CENTER) 2372 2373 inSizer = wx.BoxSizer(wx.HORIZONTAL) 2374 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Define as') 2219 2375 btn.Bind(wx.EVT_BUTTON,onSetX) 2220 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 2376 inSizer.Add(btn) 2377 inSizer.Add(G2G.G2ChoiceButton(RBImpPnl,('x','y','z'), 2378 None,None,bntOpts,'direction')) 2379 btnSizer.Add(inSizer,0,wx.ALIGN_CENTER) 2380 2221 2381 btnSizer.Add((-1,15)) 2222 2382 btnSizer.Add( … … 2224 2384 0,wx.ALL) 2225 2385 btnSizer.Add((-1,5)) 2226 btn = wx.Button(RBImpPnl, wx.ID_ OK, 'a Vector Body')2386 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'a Vector Body') 2227 2387 btn.Bind(wx.EVT_BUTTON,onAddVector) 2228 2388 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 2229 btn = wx.Button(RBImpPnl, wx.ID_ OK, 'a Residue Body')2389 btn = wx.Button(RBImpPnl, wx.ID_ANY, 'a Residue Body') 2230 2390 btn.Bind(wx.EVT_BUTTON,onAddResidue) 2231 2391 btnSizer.Add(btn,0,wx.ALIGN_CENTER) … … 2236 2396 2237 2397 mainSizer.Add(btnSizer) 2398 mainSizer.Add((5,5)) 2399 grid = DragableRBGrid(RBImpPnl,rd.Phase,UpdateDraw) 2400 mainSizer.Add(grid) 2238 2401 RBImpPnl.SetSizer(mainSizer,True) 2239 2402 mainSizer.Layout() … … 2299 2462 return rb 2300 2463 2464 # too lazy to figure out why wx crashes 2465 if wx.__version__.split('.')[0] != '4': 2466 wx.MessageBox('Sorry, wxPython 4.x is required to run this command', 2467 caption='Update Python', 2468 style=wx.ICON_EXCLAMATION) 2469 return 2470 if platform.python_version()[:1] == '2': 2471 wx.MessageBox('Sorry, Python >=3.x is required to run this command', 2472 caption='Update Python', 2473 style=wx.ICON_EXCLAMATION) 2474 return 2475 2301 2476 # get importer type and a phase file of that type 2302 2477 G2sc.LoadG2fil() … … 2304 2479 dlg = G2G.G2SingleChoiceDialog(G2frame,'Select the format of the file', 2305 2480 'select format',choices) 2481 dlg.CenterOnParent() 2306 2482 try: 2307 2483 if dlg.ShowModal() == wx.ID_OK: -
trunk/GSASIIctrlGUI.py
r4421 r4431 1875 1875 if self.OnChange: 1876 1876 self.OnChange(self.GetSelections(),*self.OnChangeArgs) 1877 self.SelectList.clear() 1877 try: 1878 self.SelectList.clear() 1879 except: # patch: clear not in EPD 1880 for i in reversed((range(len(self.SelectList)))): 1881 del self.SelectList[i] 1878 1882 for i,val in enumerate(self.Selections): 1879 1883 if val: self.SelectList.append(i) … … 3396 3400 dlg = wx.FileDialog(parent, message, defaultDir, defaultFile, *args, 3397 3401 style=style, **kwargs) 3402 dlg.CenterOnParent() 3398 3403 pth = GetImportPath(G2frame) 3399 3404 if not defaultDir and pth: dlg.SetDirectory(pth) … … 4115 4120 if colLblCallback: wx.EVT_MOTION(self.GetGridColLabelWindow(), OnMouseMotion) 4116 4121 if rowLblCallback: wx.EVT_MOTION(self.GetGridRowLabelWindow(), OnMouseMotion) 4117 4122 4123 def completeEdits(self): 4124 'complete any outstanding edits' 4125 if self.IsCellEditControlEnabled(): # complete any grid edits in progress 4126 self.SaveEditControlValue() 4127 #self.HideCellEditControl() 4128 #self.DisableCellEditControl() 4129 4118 4130 ################################################################################ 4119 4131 class Table(wg.PyGridTableBase): #TODO: this works in python 3/phoenix but pygridtablebase doesn't exist -
trunk/GSASIIdataGUI.py
r4429 r4431 6088 6088 self.DrawAtomEdit.Append(G2G.wxID_DRAWATOMCOLOR,'Atom color','Select atoms first') 6089 6089 self.DrawAtomEdit.Append(G2G.wxID_DRAWATOMRESETCOLOR,'Reset atom colors','Resets all atom colors to defaults') 6090 self.DrawAtomEdit.Append(G2G.wxID_DRWAEDITRADII,'Edit atom radii','Edit drawing atom radii') # TODO: removed until it can be made to do something6090 # self.DrawAtomEdit.Append(G2G.wxID_DRWAEDITRADII,'Edit atom radii','Edit drawing atom radii') # TODO: removed until it can be made to do something 6091 6091 self.DrawAtomEdit.Append(G2G.wxID_DRAWVIEWPOINT,'View point','View point is 1st atom selected') 6092 6092 self.DrawAtomEdit.Append(G2G.wxID_DRAWADDEQUIV,'Add atoms','Add symmetry & cell equivalents to drawing set from selected atoms') … … 6181 6181 self.RigidBodiesEdit = wx.Menu(title='') 6182 6182 self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit Body') 6183 self.RigidBodiesEdit.Append(G2G.wxID_ASSIGNATMS2RB,' Assign atoms to rigid body',6184 ' Select & position rigid body in structure ofexisting atoms')6183 self.RigidBodiesEdit.Append(G2G.wxID_ASSIGNATMS2RB,'Locate && Insert Rigid Body', 6184 'Locate rigid body in structure mapping to existing atoms') 6185 6185 self.RigidBodiesEdit.Append(G2G.wxID_AUTOFINDRESRB,'Auto find residues', 6186 6186 'Auto find of residue RBs in macromolecule') -
trunk/GSASIImath.py
r4425 r4431 984 984 985 985 def UpdateRBXYZ(Bmat,RBObj,RBData,RBType): 986 '''default doc string 987 988 :param type name: description 989 990 :returns: type name: description 991 992 ''' 993 ''' returns crystal coordinates for atoms described by RBObj 986 '''returns crystal coordinates for atoms described by RBObj 987 988 :param np.array Bmat: see :func:`GSASIIlattice.cell2AB` 989 :param dict rbObj: rigid body selection/orientation information 990 :param dict RBData: rigid body tree data structure 991 :param str RBType: rigid body type, 'Vector' or 'Residue' 992 993 :returns: coordinates for rigid body as XYZ,Cart where XYZ is 994 the location in crystal coordinates and Cart is in cartesian 994 995 ''' 995 996 RBRes = RBData[RBType][RBObj['RBId']] -
trunk/GSASIIphsGUI.py
r4430 r4431 44 44 import subprocess as subp 45 45 import distutils.file_util as disfile 46 import scipy.optimize as so 46 47 import GSASIIpath 47 48 GSASIIpath.SetVersionNumber("$Revision$") … … 4589 4590 fileSizer.Add((5,5),0) 4590 4591 return fileSizer 4591 4592 4592 4593 G2frame.GetStatusBar().SetStatusText('',1) 4593 4594 if G2frame.RMCchoice == 'RMCProfile': … … 6988 6989 Waves.Add((5,5),0) 6989 6990 else: 6990 waveDel = wx. CheckBox(waveData,label='Delete?')6991 waveDel = wx.Button(waveData,wx.ID_ANY,'Delete',style=wx.BU_EXACTFIT) 6991 6992 Indx[waveDel.GetId()] = [Stype,iwave] 6992 waveDel.Bind(wx.EVT_ CHECKBOX,OnDelWave)6993 waveDel.Bind(wx.EVT_BUTTON,OnDelWave) 6993 6994 Waves.Add(waveDel,0,WACV) 6994 6995 waveSizer.Add(Waves) … … 9257 9258 9258 9259 topSizer = wx.FlexGridSizer(0,6,5,5) 9259 Orig = RBObj['Orig'][0] 9260 if type(RBObj['Orig'][0]) is tuple: # patch because somehow adding RB origin is becoming a tuple 9261 if GSASIIpath.GetConfigValue('debug'): print('patching origin!') 9262 RBObj['Orig'][0] = list(RBObj['Orig'][0]) 9260 9263 Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0]) 9261 9264 Orien = [Orien,] 9262 9265 Orien.extend(OrienV/nl.norm(OrienV)) 9263 9266 topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,WACV) 9264 for ix,x in enumerate(Orig): 9265 origX = G2G.ValidatedTxtCtrl(RigidBodies,Orig,ix,nDig=(8,5),OnLeave=OnOrigX) 9267 for ix in range(3): 9268 origX = G2G.ValidatedTxtCtrl(RigidBodies,RBObj['Orig'][0],ix,nDig=(8,5), 9269 typeHint=float,OnLeave=OnOrigX) 9266 9270 topSizer.Add(origX,0,WACV) 9267 9271 topSizer.Add((5,0),) … … 9318 9322 'Name: '+RBObj['RBname']+RBObj['numChain']+' '),0,WACV) 9319 9323 rbId = RBObj['RBId'] 9320 delRB = wx. CheckBox(RigidBodies,-1,'Delete?')9321 delRB.Bind(wx.EVT_ CHECKBOX,OnDelResRB)9324 delRB = wx.Button(RigidBodies,wx.ID_ANY,'Delete',style=wx.BU_EXACTFIT) 9325 delRB.Bind(wx.EVT_BUTTON,OnDelResRB) 9322 9326 Indx[delRB.GetId()] = rbId 9323 9327 topLine.Add(delRB,0,WACV) … … 9370 9374 'Name: '+RBObj['RBname']+' '),0,WACV) 9371 9375 rbId = RBObj['RBId'] 9372 delRB = wx. CheckBox(RigidBodies,-1,'Delete?')9373 delRB.Bind(wx.EVT_ CHECKBOX,OnDelVecRB)9376 delRB = wx.Button(RigidBodies,wx.ID_ANY,'Delete',style=wx.BU_EXACTFIT) 9377 delRB.Bind(wx.EVT_BUTTON,OnDelVecRB) 9374 9378 Indx[delRB.GetId()] = rbId 9375 9379 topLine.Add(delRB,0,WACV) … … 9424 9428 Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Rigid bodies') 9425 9429 if not Id: 9430 G2frame.CheckNotebook() 9431 Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Rigid bodies') 9432 if not Id: 9433 print('Strange! Why no Rigid Bodies tree entry?') 9426 9434 return 9427 9435 RBData = G2frame.GPXtree.GetItemPyData(Id) … … 9497 9505 9498 9506 def OnRBAssign(event): 9499 9507 '''Assign RB to atoms in a phase with tools to locate the RB in the structure 9508 ''' 9509 9510 def assignAtoms(selDict={}): 9511 '''Find the closest RB atoms to atoms in the structure 9512 If selDict is specified, it overrides the assignments to specify 9513 atoms that should be matched. 9514 ''' 9515 rbType = data['testRBObj']['rbType'] 9516 rbObj = data['testRBObj']['rbObj'] 9517 rbId = rbObj['RBId'] 9518 rbAtmTypes = RBData[rbType][rbId]['rbTypes'] 9519 if 'atNames' in RBData[rbType][rbId]: 9520 rbAtmLbs = RBData[rbType][rbId]['atNames'] 9521 else: 9522 rbAtmLbs = None 9523 9524 newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0] 9525 atmTypes = [atomData[i][ct] for i in range(len(atomData))] 9526 # remove assigned atoms from search groups 9527 for i in selDict: 9528 atmTypes[selDict[i]] = None 9529 atmXYZ = G2mth.getAtomXYZ(atomData,cx) 9530 # separate structure's atoms by type (w/o assigned atoms) 9531 oXYZbyT = {} 9532 atmNumByT = {} 9533 for t in set(atmTypes): 9534 if t is None: continue 9535 oXYZbyT[t] = np.array([atmXYZ[i] for i in range(len(atmXYZ)) if atmTypes[i] == t]) 9536 atmNumByT[t] = [i for i in range(len(atmXYZ)) if atmTypes[i] == t] 9537 Ids = [] 9538 # create table of fixed and found assignments 9539 matchTable = [] 9540 for i,xyz in enumerate(newXYZ): 9541 t = rbAtmTypes[i] 9542 if rbAtmLbs: 9543 lbl = rbAtmLbs[i] 9544 else: 9545 lbl = '' 9546 if i in selDict: 9547 searchXYZ = [atmXYZ[selDict[i]]] #assigned 9548 numLookup = [selDict[i]] 9549 else: 9550 searchXYZ = oXYZbyT[t] 9551 numLookup = atmNumByT[t] 9552 dist = G2mth.GetXYZDist(xyz,searchXYZ,Amat) 9553 repeat = True 9554 while repeat: 9555 repeat = False 9556 pidIndx = np.argmin(dist) 9557 d = dist[pidIndx] 9558 pid = numLookup[pidIndx] 9559 if atomData[pid][-1] in Ids: #duplicate - 2 atoms on same site; invalidate & look again 9560 repeat = True 9561 dist[pidIndx] = 100. 9562 if min(dist) == 100: 9563 print('no atom matches, how could this happen?') 9564 GSASIIpath.IPyBreak() 9565 return 9566 Ids.append(atomData[pid][-1]) 9567 matchTable.append([t , lbl] + list(xyz) + [pid, atomData[pid][0]] 9568 + atomData[pid][cx:cx+3] + [d, Ids[-1]]) 9569 return matchTable 9570 9571 def Draw(): 9572 '''Create the window for assigning RB to atoms''' 9573 def OnOk(event): 9574 'respond to OK button, set info into phase' 9575 matchTable = UpdateTable() 9576 dmax = 0. 9577 Ids = [] 9578 for line in matchTable: 9579 xyz = line[2:5] 9580 pid = line[5] 9581 dmax = max(dmax,line[10]) 9582 atomData[pid][cx:cx+3] = xyz 9583 Ids.append(line[11]) 9584 if dmax > 1.0: 9585 msg = "Atoms may not be properly located. Are you sure you want to do this?" 9586 dlg = wx.MessageDialog(G2frame,msg,caption='Continue?',style=wx.YES_NO|wx.ICON_EXCLAMATION) 9587 if dlg.ShowModal() != wx.ID_YES: 9588 #OkBtn.SetLabel('Not Ready') 9589 #OkBtn.Enable(False) 9590 return 9591 9592 rbType = data['testRBObj']['rbType'] 9593 rbObj['Ids'] = Ids 9594 rbId = rbObj['RBId'] 9595 rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags 9596 rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount']) 9597 if type(rbObj['Orig'][0]) is tuple: # patch because somehow adding RB origin is becoming a tuple 9598 if GSASIIpath.GetConfigValue('debug'): print('patching origin!') 9599 rbObj['Orig'][0] = list(rbObj['Orig'][0]) # patch: somehow this was getting set as a tuple 9600 if not rbType in data['RBModels']: 9601 data['RBModels'][rbType] = [] 9602 data['RBModels'][rbType].append(rbObj) 9603 RBData[rbType][rbId]['useCount'] += 1 9604 del data['testRBObj'] 9605 G2plt.PlotStructure(G2frame,data,False) 9606 FillRigidBodyGrid(True) 9607 9608 def OnCancel(event): 9609 del data['testRBObj'] 9610 FillRigidBodyGrid(True) 9611 9612 def OnTorAngle(invalid,value,tc): 9613 #OkBtn.SetLabel('OK') 9614 #OkBtn.Enable(True) 9615 Obj = tc.event.GetEventObject() 9616 [tor,torSlide] = Indx[Obj.GetId()] 9617 torSlide.SetValue(int(value*10)) 9618 UpdateTablePlot() 9619 9620 def OnTorSlide(event): 9621 #OkBtn.SetLabel('OK') 9622 #OkBtn.Enable(True) 9623 Obj = event.GetEventObject() 9624 tor,ang = Indx[Obj.GetId()] 9625 Tors = data['testRBObj']['rbObj']['Torsions'][tor] 9626 val = float(Obj.GetValue())/10. 9627 Tors[0] = val 9628 ang.SetValue(val) 9629 UpdateTablePlot() 9630 9631 def UpdateTable(event=None): 9632 '''get fixed atom assignments, find closest mappings & 9633 update displayed table 9634 ''' 9635 selDict = getSelectedAtoms() 9636 matchTable = assignAtoms(selDict) 9637 for i,l in enumerate(matchTable): 9638 RigidBodies.atomsTable.data[i][1:4] = l[5],l[6],l[10] 9639 RigidBodies.atomsGrid.ForceRefresh() 9640 return matchTable 9641 9642 def UpdateTablePlot(*args,**kwargs): 9643 '''update displayed table and plot 9644 ''' 9645 G2plt.PlotStructure(G2frame,data,False,UpdateTable) 9646 UpdateTable() 9647 9648 def getSelectedAtoms(): 9649 'Find the FB atoms that have been assigned to specific atoms in structure' 9650 RigidBodies.atomsGrid.completeEdits() 9651 tbl = RigidBodies.atomsGrid.GetTable() 9652 selDict = {} 9653 dups = [] 9654 assigned = [] 9655 for r in range(tbl.GetRowsCount()): 9656 sel = tbl.GetValue(r,4).strip() 9657 if sel not in labelsChoices: continue 9658 atmNum = labelsChoices.index(sel)-1 9659 if atmNum < 0: continue 9660 if atmNum in assigned: 9661 if sel not in dups: 9662 dups.append(sel) 9663 else: 9664 assigned.append(atmNum) 9665 selDict[r] = atmNum 9666 if dups: 9667 msg = 'Error: The following atom(s) are assigned multiple times: ' 9668 for i in dups: 9669 msg += i 9670 msg += ', ' 9671 wx.MessageBox(msg[:-2],caption='Duplicated Fixed Atoms', 9672 style=wx.ICON_EXCLAMATION) 9673 return 9674 return selDict 9675 9676 def getDeltaXYZ(selDict,data,rbObj): 9677 '''Evaluate the RB position & return the difference between the coordinates 9678 and RB coordinates with origin and orientation from data['testRBObj'] 9679 ''' 9680 Amat,Bmat = G2lat.cell2AB(data['General']['Cell'][1:7]) 9681 rbXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,data['testRBObj']['rbData'],data['testRBObj']['rbType'])[0] 9682 phaseXYZ = G2mth.getAtomXYZ(atomData,cx) 9683 deltaList = [] 9684 for i in selDict: 9685 deltaList.append(phaseXYZ[selDict[i]]-rbXYZ[i]) 9686 return np.array(deltaList) 9687 9688 def objectiveDeltaPos(vals,selDict,data,rbObj_in): 9689 '''Returns a list of distances between atom positions and 9690 located rigid body positions 9691 9692 :param list vals: a 4 or 7 element array with 4 quaterian values 9693 or 4 quaterian values followed by 3 origin (x,y,z) values 9694 9695 :returns: the 3*n distances between the n selected atoms 9696 ''' 9697 rbObj = copy.deepcopy(rbObj_in) 9698 rbObj['Orient'][0][:] = G2mth.normQ(vals[:4]) 9699 if len(vals) == 7: 9700 rbObj['Orig'][0][:] = vals[4:] 9701 #print(np.sqrt(sum(getDeltaXYZ(selDict,data,rbObj).flatten()**2))) 9702 return getDeltaXYZ(selDict,data,rbObj).flatten() 9703 9704 def onSetOrigin(event): 9705 'Set Origin to best fit selected atoms' 9706 if rbObj['fixOrig']: 9707 wx.MessageBox('Not possible with origin locked',caption='Îrigin Locked', 9708 style=wx.ICON_EXCLAMATION) 9709 return 9710 selDict = getSelectedAtoms() 9711 if len(selDict) < 1: 9712 wx.MessageBox('No atoms were selected',caption='Select Atom(s)', 9713 style=wx.ICON_EXCLAMATION) 9714 return 9715 deltaList = getDeltaXYZ(selDict,data,rbObj) 9716 data['testRBObj']['rbObj']['Orig'][0][:] = deltaList.sum(axis=0)/len(deltaList) 9717 for i,item in enumerate(Xsizers): 9718 item.SetValue(data['testRBObj']['rbObj']['Orig'][0][i]) 9719 UpdateTablePlot() 9720 9721 def onFitOrientation(event): 9722 'Set Orientation to best fit selected atoms' 9723 selDict = getSelectedAtoms() 9724 if len(selDict) < 2: 9725 wx.MessageBox('At least two atoms must be selected',caption='Select Atoms', 9726 style=wx.ICON_EXCLAMATION) 9727 return 9728 vals = rbObj['Orient'][0][:] #+ rbObj['Orig'][0][:] 9729 out = so.leastsq(objectiveDeltaPos,vals,(selDict,data,rbObj)) 9730 data['testRBObj']['rbObj']['Orient'][0][:] = G2mth.normQ(out[0]) 9731 for i,item in enumerate(Osizers): 9732 item.SetLabel('%10.4f'%(data['testRBObj']['rbObj']['Orient'][0][i])) 9733 UpdateTablePlot() 9734 # debug code 9735 #selDict = getSelectedAtoms() 9736 #for line in assignAtoms(selDict): print(line) 9737 9738 def onFitBoth(event): 9739 'Set Orientation and origin to best fit selected atoms' 9740 if rbObj['fixOrig']: 9741 wx.MessageBox('Not possible with origin locked',caption='Îrigin Locked', 9742 style=wx.ICON_EXCLAMATION) 9743 return 9744 selDict = getSelectedAtoms() 9745 if len(selDict) < 3: 9746 wx.MessageBox('At least three atoms must be selected',caption='Select Atoms', 9747 style=wx.ICON_EXCLAMATION) 9748 return 9749 vals = rbObj['Orient'][0][:] + rbObj['Orig'][0][:] 9750 out = so.leastsq(objectiveDeltaPos,vals,(selDict,data,rbObj)) 9751 data['testRBObj']['rbObj']['Orig'][0][:] = out[0][4:] 9752 data['testRBObj']['rbObj']['Orient'][0][:] = G2mth.normQ(out[0][:4]) 9753 for i,item in enumerate(Xsizers): 9754 item.SetValue(data['testRBObj']['rbObj']['Orig'][0][i]) 9755 for i,item in enumerate(Osizers): 9756 item.SetLabel('%10.4f'%(data['testRBObj']['rbObj']['Orient'][0][i])) 9757 UpdateTablePlot() 9758 9759 if not data['testRBObj']: return 9760 # if len(data['testRBObj']): 9761 # G2plt.PlotStructure(G2frame,data,True,UpdateTable) 9762 if RigidBodies.GetSizer(): RigidBodies.GetSizer().Clear(True) 9763 mainSizer = wx.BoxSizer(wx.VERTICAL) 9764 mainSizer.Add((5,5),0) 9765 Osizers = [] 9766 rbObj = data['testRBObj']['rbObj'] 9767 rbName = rbObj['RBname'] 9768 rbId = rbObj['RBId'] 9769 Orien = rbObj['Orient'][0] 9770 rbRef = data['testRBObj']['rbRef'] 9771 Torsions = rbObj['Torsions'] 9772 refName = [] 9773 for ref in rbRef: 9774 refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref)) 9775 atNames = data['testRBObj']['atNames'] 9776 mainSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Locate rigid body : '+rbName), 9777 0,WACV) 9778 mainSizer.Add((5,5),0) 9779 OriSizer = wx.BoxSizer(wx.HORIZONTAL) 9780 OriSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Origin: '),0,WACV) 9781 Xsizers = [] 9782 lbl = 'xyz' 9783 for ix in range(3): 9784 OriSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,lbl[ix]),0,WACV,4) 9785 origX = G2G.ValidatedTxtCtrl(RigidBodies,rbObj['Orig'][0],ix,nDig=(10,5), 9786 min=-1.5,max=1.5,typeHint=float, 9787 OnLeave=UpdateTablePlot) 9788 OriSizer.Add(origX,0,WACV) 9789 Xsizers.append(origX) 9790 try: 9791 rbObj['fixOrig'] 9792 except: 9793 rbObj['fixOrig'] = False 9794 fixOrig = G2G.G2CheckBox(RigidBodies,'Lock',rbObj,'fixOrig') 9795 OriSizer.Add(fixOrig,0,WACV,10) 9796 9797 mainSizer.Add(OriSizer) 9798 OriSizer.Add((5,0),) 9799 OriSizer = wx.FlexGridSizer(0,5,5,5) 9800 if len(atomData): 9801 choice = list(atNames[0].keys()) 9802 choice.sort() 9803 G2frame.testRBObjSizers.update({'Xsizers':Xsizers}) 9804 OriSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Orientation quaternion: '),0,WACV) 9805 for ix,x in enumerate(Orien): 9806 orien = wx.StaticText(RigidBodies,wx.ID_ANY,'%10.4f'%(x)) 9807 OriSizer.Add(orien,0,WACV) 9808 Osizers.append(orien) 9809 G2frame.testRBObjSizers.update({'Osizers':Osizers}) 9810 mainSizer.Add(OriSizer) 9811 mainSizer.Add((5,5),0) 9812 RefSizer = wx.FlexGridSizer(0,7,5,5) 9813 mainSizer.Add(RefSizer) 9814 mainSizer.Add((5,5),0) 9815 if Torsions: 9816 rbSeq = RBData['Residue'][rbId]['rbSeq'] 9817 TorSizer = wx.FlexGridSizer(0,4,5,5) 9818 TorSizer.AddGrowableCol(1,1) 9819 for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)): 9820 torName = '' 9821 for item in [seq[0],seq[1],seq[3][0]]: 9822 torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' ' 9823 TorSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Side chain torsion for rb seq: '+torName),0,WACV) 9824 torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL) 9825 torSlide.SetRange(0,3600) 9826 torSlide.SetValue(int(torsion[0]*10.)) 9827 torSlide.Bind(wx.EVT_SLIDER, OnTorSlide) 9828 TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT) 9829 TorSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,' Angle: '),0,WACV) 9830 ang = G2G.ValidatedTxtCtrl(RigidBodies,torsion,0,nDig=(8,3),typeHint=float,OnLeave=OnTorAngle) 9831 Indx[torSlide.GetId()] = [t,ang] 9832 Indx[ang.GetId()] = [t,torSlide] 9833 TorSizer.Add(ang,0,WACV) 9834 mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT) 9835 else: 9836 mainSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'No side chain torsions'),0,WACV) 9837 matchTable = assignAtoms() 9838 OkBtn = wx.Button(RigidBodies,wx.ID_ANY,"Add") 9839 OkBtn.Bind(wx.EVT_BUTTON, OnOk) 9840 CancelBtn = wx.Button(RigidBodies,wx.ID_ANY,'Cancel') 9841 CancelBtn.Bind(wx.EVT_BUTTON, OnCancel) 9842 btnSizer = wx.BoxSizer(wx.HORIZONTAL) 9843 btnSizer.Add((20,20),1) 9844 btnSizer.Add(OkBtn) 9845 btnSizer.Add(CancelBtn) 9846 btnSizer.Add((20,20),1) 9847 mainSizer.Add(btnSizer,0,wx.BOTTOM|wx.TOP, 20) 9848 9849 SetPhaseWindow(RigidBodies,mainSizer) 9850 9851 G2plt.PlotStructure(G2frame,data,True,UpdateTable) 9852 colLabels = ['RB\ntype','phase\n#','phase\nlabel','delta, A','Assign as atom'] 9853 rowLabels = [l[1] for l in matchTable] 9854 displayTable = [[l[0],l[5],l[6],l[10],''] for l in matchTable] 9855 Types = [wg.GRID_VALUE_STRING, wg.GRID_VALUE_NUMBER, 9856 wg.GRID_VALUE_STRING, wg.GRID_VALUE_FLOAT+':8,3', wg.GRID_VALUE_STRING] 9857 RigidBodies.atomsTable = G2G.Table(displayTable,rowLabels=rowLabels,colLabels=colLabels,types=Types) 9858 RigidBodies.atomsGrid = G2G.GSGrid(RigidBodies) 9859 9860 labelsChoices = [' '] + [a[0] for a in data['Atoms']] 9861 choiceeditor = wg.GridCellChoiceEditor(labelsChoices, False) 9862 RigidBodies.atomsGrid.SetTable(RigidBodies.atomsTable,True) 9863 # make all grid entries read only 9864 attr = wg.GridCellAttr() 9865 attr.SetReadOnly(True) 9866 for i in range(len(colLabels)-1): 9867 attr.IncRef() 9868 RigidBodies.atomsGrid.SetColAttr(i, attr) 9869 attr = wg.GridCellAttr() 9870 attr.SetAlignment(wx.ALIGN_RIGHT,wx.ALIGN_CENTRE) 9871 RigidBodies.atomsGrid.SetColAttr(1, attr) 9872 attr = wg.GridCellAttr() 9873 attr.SetEditor(choiceeditor) 9874 RigidBodies.atomsGrid.SetColAttr(4, attr) 9875 9876 RigidBodies.atomsGrid.AutoSizeColumns(True) 9877 RigidBodies.atomsGrid.SetMargins(0,0) 9878 9879 gridSizer = wx.BoxSizer(wx.HORIZONTAL) 9880 gridSizer.Add(RigidBodies.atomsGrid)#,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10) 9881 gridSizer.Add((5,5)) 9882 9883 btnSizer = wx.BoxSizer(wx.VERTICAL) 9884 btnSizer.Add((-1,20)) 9885 btnSizer.Add( 9886 wx.StaticText(RigidBodies,wx.ID_ANY,'Actions with fixed\natom(s)...'), 9887 0,wx.ALL) 9888 btnSizer.Add((-1,10)) 9889 btn = wx.Button(RigidBodies, wx.ID_ANY, 'Process Assignments') 9890 btn.Bind(wx.EVT_BUTTON,UpdateTable) 9891 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 9892 btnSizer.Add((-1,10)) 9893 9894 btn = wx.Button(RigidBodies, wx.ID_ANY, 'Set Origin') 9895 9896 btn.Bind(wx.EVT_BUTTON,onSetOrigin) 9897 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 9898 btnSizer.Add((-1,5)) 9899 btn = wx.Button(RigidBodies, wx.ID_ANY, 'Set Orientation') 9900 9901 btn.Bind(wx.EVT_BUTTON,onFitOrientation) 9902 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 9903 btnSizer.Add((-1,5)) 9904 btn = wx.Button(RigidBodies, wx.ID_ANY, 'Set both') 9905 btn.Bind(wx.EVT_BUTTON,onFitBoth) 9906 btnSizer.Add(btn,0,wx.ALIGN_CENTER) 9907 gridSizer.Add(btnSizer) 9908 mainSizer.Add(gridSizer) 9909 mainSizer.Layout() 9910 RigidBodies.SetScrollRate(10,10) 9911 RigidBodies.SendSizeEvent() 9912 RigidBodies.Scroll(0,0) 9913 9500 9914 G2frame.GetStatusBar().SetStatusText('',1) 9501 9915 RBData = G2frame.GPXtree.GetItemPyData( … … 9510 9924 if not rbNames: 9511 9925 print ('**** ERROR - no rigid bodies defined ****') 9926 G2G.G2MessageBox(G2frame, 9927 'You must define bodies in Rigid Bodies tree item before trying to add them to a phase', 9928 'No Rigid Bodies') 9512 9929 return 9513 9930 general = data['General'] … … 9518 9935 atInd = [-1,-1,-1] 9519 9936 data['testRBObj'] = {} 9520 9521 def Draw(): 9522 9523 def OnOk(event): 9524 rbType = data['testRBObj']['rbType'] 9525 RBObjs = data['RBModels'].get(rbType,[]) 9526 rbObj = data['testRBObj']['rbObj'] 9527 rbId = rbObj['RBId'] 9528 newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0] 9529 Ids = [] 9530 dmax = 0.0 9531 oldXYZ = G2mth.getAtomXYZ(atomData,cx) 9532 for xyz in newXYZ: 9533 dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat) 9534 dmax = max(dmax,np.min(dist)) 9535 pid = np.argmin(dist) 9536 Id = atomData[pid][-1] 9537 if Id in Ids: #duplicate - 2 atoms on same site; invalidate & look again 9538 dist[pid] = 100. 9539 Id = atomData[pid][-1] 9540 Ids.append(Id) 9541 atomData[pid][cx:cx+3] = xyz 9542 if dmax > 1.0: 9543 print ('**** WARNING - some atoms not found or misidentified ****') 9544 print ('**** check torsion angles & try again ****') 9545 OkBtn.SetLabel('Not Ready') 9546 OkBtn.Enable(False) 9937 if len(rbNames) == 1: 9938 selection = list(rbNames.keys())[0] 9939 else: 9940 choices = sorted(list(rbNames.keys())) 9941 dlg = G2G.G2SingleChoiceDialog( 9942 G2frame,'Select rigid body to add to structure', 9943 'Select rigid body',choices) 9944 dlg.CenterOnParent() 9945 try: 9946 if dlg.ShowModal() == wx.ID_OK: 9947 selection = choices[dlg.GetSelection()] 9948 else: 9547 9949 return 9548 rbObj['Ids'] = Ids 9549 rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags 9550 rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount']) 9551 RBObjs.append(rbObj) 9552 data['RBModels'][rbType] = RBObjs 9553 RBData[rbType][rbId]['useCount'] += 1 9554 del data['testRBObj'] 9555 G2plt.PlotStructure(G2frame,data) 9556 FillRigidBodyGrid(True) 9557 9558 def OnCancel(event): 9559 del data['testRBObj'] 9560 FillRigidBodyGrid(True) 9561 9562 def OnRBSel(event): 9563 selection = rbSel.GetValue() 9564 if selection not in rbNames: 9565 return 9566 rbType,rbId = rbNames[selection] 9567 data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes'] 9568 data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo'] 9569 data['testRBObj']['rbType'] = rbType 9570 data['testRBObj']['rbData'] = RBData 9571 data['testRBObj']['Sizers'] = {} 9572 rbRef = RBData[rbType][rbId]['rbRef'] 9573 data['testRBObj']['rbRef'] = rbRef 9574 refType = [] 9575 refName = [] 9576 for ref in rbRef[:3]: 9577 reftype = data['testRBObj']['rbAtTypes'][ref] 9578 refType.append(reftype) 9579 refName.append(reftype+' '+str(rbRef[0])) 9580 atNames,AtNames = fillAtNames(refType,atomData,ct) 9581 data['testRBObj']['atNames'] = atNames 9582 data['testRBObj']['AtNames'] = AtNames 9583 data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False], 9584 'Orient':[[0.,0.,0.,0.],' '],'Ids':[],'RBId':rbId,'Torsions':[], 9950 finally: 9951 dlg.Destroy() 9952 if selection not in rbNames: 9953 print('Invalid RB selection',selection,'How did this happen?') 9954 return 9955 rbType,rbId = rbNames[selection] 9956 data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes'] 9957 data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo'] 9958 data['testRBObj']['rbType'] = rbType 9959 data['testRBObj']['rbData'] = RBData 9960 data['testRBObj']['Sizers'] = {} 9961 rbRef = RBData[rbType][rbId]['rbRef'] 9962 data['testRBObj']['rbRef'] = rbRef 9963 refType = [] 9964 refName = [] 9965 for ref in rbRef[:3]: 9966 reftype = data['testRBObj']['rbAtTypes'][ref] 9967 refType.append(reftype) 9968 refName.append(reftype+' '+str(rbRef[0])) 9969 atNames = [{},{},{}] 9970 AtNames = {} 9971 for iatm,atom in enumerate(atomData): 9972 AtNames[atom[ct-1]] = iatm 9973 for i,reftype in enumerate(refType): 9974 if atom[ct] == reftype: 9975 atNames[i][atom[ct-1]] = iatm 9976 data['testRBObj']['atNames'] = atNames 9977 data['testRBObj']['AtNames'] = AtNames 9978 data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False], 9979 'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[], 9585 9980 'numChain':'','RBname':RBData[rbType][rbId]['RBname']} 9586 data['testRBObj']['torAtms'] = [] 9587 for item in RBData[rbType][rbId].get('rbSeq',[]): 9588 data['testRBObj']['rbObj']['Torsions'].append([item[2],False]) 9589 data['testRBObj']['torAtms'].append([-1,-1,-1]) 9590 wx.CallAfter(Draw) 9591 9592 def fillAtNames(refType,atomData,ct): 9593 atNames = [{},{},{}] 9594 AtNames = {} 9595 for iatm,atom in enumerate(atomData): 9596 AtNames[atom[ct-1]] = iatm 9597 for i,reftype in enumerate(refType): 9598 if atom[ct] == reftype: 9599 atNames[i][atom[ct-1]] = iatm 9600 return atNames,AtNames 9601 9602 def OnAtOrigPick(event): 9603 Obj = event.GetEventObject() 9604 item = Indx[Obj.GetId()] 9605 atName = Obj.GetValue() 9606 rbType = data['testRBObj']['rbType'] 9607 atInd[0] = atNames[item][atName] 9608 if 'Vector' in rbType: 9609 rbObj = data['testRBObj']['rbObj'] 9610 rbId = rbObj['RBId'] 9611 rbRef = data['testRBObj']['rbRef'] 9612 rbXYZ = -RBData[rbType][rbId]['rbXYZ'] 9613 nref = atNames[item][atName] 9614 Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]])) 9615 Nxyz = np.array(atomData[nref][cx:cx+3]) 9616 Orig = Nxyz-Oxyz 9617 data['testRBObj']['rbObj']['Orig'][0] = Orig 9618 else: 9619 Orig = atomData[atNames[item][atName]][cx:cx+3] 9620 data['testRBObj']['rbObj']['Orig'][0] = Orig 9621 for x,item in zip(Orig,Xsizers): 9622 item.SetLabel('%10.5f'%(x)) 9623 G2plt.PlotStructure(G2frame,data) 9624 9625 def OnAtQPick(event): 9626 Obj = event.GetEventObject() 9627 item = Indx[Obj.GetId()] 9628 atName = Obj.GetValue() 9629 atInd[item] = atNames[item][atName] 9630 if any([x<0 for x in atInd]): 9631 return 9632 OkBtn.SetLabel('OK') 9633 OkBtn.Enable(True) 9634 rbType = data['testRBObj']['rbType'] 9635 rbObj = data['testRBObj']['rbObj'] 9636 rbId = rbObj['RBId'] 9637 rbRef = data['testRBObj']['rbRef'] 9638 rbXYZ = RBData[rbType][rbId]['rbXYZ'] 9639 rbOrig = rbXYZ[rbRef[0]] 9640 VAR = rbXYZ[rbRef[1]]-rbOrig 9641 VBR = rbXYZ[rbRef[2]]-rbOrig 9642 if rbType == 'Vector': 9643 Orig = np.array(atomData[atInd[0]][cx:cx+3]) 9644 else: 9645 Orig = np.array(data['testRBObj']['rbObj']['Orig'][0]) 9646 VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3]-Orig)) 9647 VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3]-Orig)) 9648 VCC = np.cross(VAR,VAC) 9649 if nl.norm(VCC) > 1e-7: 9650 QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0] 9651 VAR = G2mth.prodQVQ(QuatA,VAR) 9652 VBR = G2mth.prodQVQ(QuatA,VBR) 9653 QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0] 9654 QuatC = G2mth.prodQQ(QuatB,QuatA) 9655 else: #parallel/antiparallel 9656 if np.dot(VAR,VAC)/(nl.norm(VAR)*nl.norm(VAC)) > 1e-7: #no rotation 9657 QuatC = G2mth.AVdeg2Q(0.,[0.,0.,1.]) 9658 else: 9659 QuatC = G2mth.AVdeg2Q(180.,VBR+VBC) 9660 data['testRBObj']['rbObj']['Orient'] = [QuatC,' '] 9661 for x,item in zip(QuatC,Osizers): 9662 item.SetLabel('%10.4f'%(x)) 9663 if rbType == 'Vector': 9664 Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig)) 9665 Nxyz = np.array(atomData[atInd[0]][cx:cx+3]) 9666 Orig = Nxyz-Oxyz 9667 data['testRBObj']['rbObj']['Orig'][0] = Orig 9668 for x,item in zip(Orig,Xsizers): 9669 item.SetLabel('%10.5f'%(x)) 9670 G2plt.PlotStructure(G2frame,data) 9671 9672 def OnTorAngle(invalid,value,tc): 9673 OkBtn.SetLabel('OK') 9674 OkBtn.Enable(True) 9675 Obj = tc.event.GetEventObject() 9676 [tor,torSlide] = Indx[Obj.GetId()] 9677 torSlide.SetValue(int(value*10)) 9678 G2plt.PlotStructure(G2frame,data) 9679 9680 def OnTorSlide(event): 9681 OkBtn.SetLabel('OK') 9682 OkBtn.Enable(True) 9683 Obj = event.GetEventObject() 9684 tor,ang = Indx[Obj.GetId()] 9685 Tors = data['testRBObj']['rbObj']['Torsions'][tor] 9686 val = float(Obj.GetValue())/10. 9687 Tors[0] = val 9688 ang.SetValue(val) 9689 G2plt.PlotStructure(G2frame,data) 9690 9691 if len(data['testRBObj']): 9692 G2plt.PlotStructure(G2frame,data) 9693 9694 if RigidBodies.GetSizer(): RigidBodies.GetSizer().Clear(True) 9695 mainSizer = wx.BoxSizer(wx.VERTICAL) 9696 mainSizer.Add((5,5),0) 9697 if data['testRBObj']: 9698 Xsizers = [] 9699 Osizers = [] 9700 rbObj = data['testRBObj']['rbObj'] 9701 rbName = rbObj['RBname'] 9702 rbId = rbObj['RBId'] 9703 Orig = rbObj['Orig'][0] 9704 Orien = rbObj['Orient'][0] 9705 rbRef = data['testRBObj']['rbRef'] 9706 Torsions = rbObj['Torsions'] 9707 refName = [] 9708 for ref in rbRef: 9709 refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref)) 9710 atNames = data['testRBObj']['atNames'] 9711 mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName), 9712 0,WACV) 9713 mainSizer.Add((5,5),0) 9714 OriSizer = wx.FlexGridSizer(0,5,5,5) 9715 OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,WACV) 9716 for ix,x in enumerate(Orig): 9717 origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x)) 9718 OriSizer.Add(origX,0,WACV) 9719 Xsizers.append(origX) 9720 OriSizer.Add((5,0),) 9721 if len(atomData): 9722 choice = list(atNames[0].keys()) 9723 choice.sort() 9724 G2frame.testRBObjSizers.update({'Xsizers':Xsizers}) 9725 OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,WACV) 9726 for ix,x in enumerate(Orien): 9727 orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x)) 9728 OriSizer.Add(orien,0,WACV) 9729 Osizers.append(orien) 9730 G2frame.testRBObjSizers.update({'Osizers':Osizers}) 9731 mainSizer.Add(OriSizer) 9732 mainSizer.Add((5,5),0) 9733 RefSizer = wx.FlexGridSizer(0,7,5,5) 9734 if len(atomData): 9735 RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,WACV) 9736 for i in [0,1,2]: 9737 choice = ['',]+list(atNames[i].keys()) 9738 choice.sort() 9739 RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,WACV) 9740 atPick = wx.ComboBox(RigidBodies,-1,value='', 9741 choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN) 9742 if i: 9743 atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick) 9744 else: 9745 atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick) 9746 Indx[atPick.GetId()] = i 9747 RefSizer.Add(atPick,0,WACV) 9748 mainSizer.Add(RefSizer) 9749 mainSizer.Add((5,5),0) 9750 if Torsions: 9751 rbSeq = RBData['Residue'][rbId]['rbSeq'] 9752 TorSizer = wx.FlexGridSizer(0,4,5,5) 9753 TorSizer.AddGrowableCol(1,1) 9754 for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)): 9755 torName = '' 9756 for item in [seq[0],seq[1],seq[3][0]]: 9757 torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' ' 9758 TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,WACV) 9759 torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL) 9760 torSlide.SetRange(0,3600) 9761 torSlide.SetValue(int(torsion[0]*10.)) 9762 torSlide.Bind(wx.EVT_SLIDER, OnTorSlide) 9763 TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT) 9764 TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,WACV) 9765 ang = G2G.ValidatedTxtCtrl(RigidBodies,torsion,0,nDig=(8,3),typeHint=float,OnLeave=OnTorAngle) 9766 Indx[torSlide.GetId()] = [t,ang] 9767 Indx[ang.GetId()] = [t,torSlide] 9768 TorSizer.Add(ang,0,WACV) 9769 mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT) 9770 else: 9771 mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,WACV) 9772 else: 9773 mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,WACV) 9774 mainSizer.Add((5,5),0) 9775 topSizer = wx.BoxSizer(wx.HORIZONTAL) 9776 topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,WACV) 9777 rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=['']+list(rbNames.keys()), 9778 style=wx.CB_READONLY|wx.CB_DROPDOWN) 9779 rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel) 9780 topSizer.Add((5,5),0) 9781 topSizer.Add(rbSel,0,WACV) 9782 mainSizer.Add(topSizer) 9783 9784 OkBtn = wx.Button(RigidBodies,-1,"Not ready") 9785 OkBtn.Bind(wx.EVT_BUTTON, OnOk) 9786 OkBtn.Enable(False) 9787 CancelBtn = wx.Button(RigidBodies,-1,'Cancel') 9788 CancelBtn.Bind(wx.EVT_BUTTON, OnCancel) 9789 btnSizer = wx.BoxSizer(wx.HORIZONTAL) 9790 btnSizer.Add((20,20),1) 9791 btnSizer.Add(OkBtn) 9792 btnSizer.Add(CancelBtn) 9793 btnSizer.Add((20,20),1) 9794 mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10) 9795 SetPhaseWindow(RigidBodies,mainSizer) 9981 data['testRBObj']['torAtms'] = [] 9982 for item in RBData[rbType][rbId].get('rbSeq',[]): 9983 data['testRBObj']['rbObj']['Torsions'].append([item[2],False]) 9984 data['testRBObj']['torAtms'].append([-1,-1,-1]) 9796 9985 wx.CallAfter(Draw) 9797 9986 … … 11486 11675 G2frame.Bind(wx.EVT_MENU, DrawAtomColor, id=G2G.wxID_DRAWATOMCOLOR) 11487 11676 G2frame.Bind(wx.EVT_MENU, ResetAtomColors, id=G2G.wxID_DRAWATOMRESETCOLOR) 11488 G2frame.Bind(wx.EVT_MENU, OnEditAtomRadii, id=G2G.wxID_DRWAEDITRADII)11677 #G2frame.Bind(wx.EVT_MENU, OnEditAtomRadii, id=G2G.wxID_DRWAEDITRADII) # TODO: removed until fixed 11489 11678 G2frame.Bind(wx.EVT_MENU, SetViewPoint, id=G2G.wxID_DRAWVIEWPOINT) 11490 11679 G2frame.Bind(wx.EVT_MENU, AddSymEquiv, id=G2G.wxID_DRAWADDEQUIV) -
trunk/GSASIIplot.py
r4428 r4431 7920 7920 ################################################################################ 7921 7921 7922 def PlotStructure(G2frame,data,firstCall=False ):7922 def PlotStructure(G2frame,data,firstCall=False,pageCallback=None): 7923 7923 '''Crystal structure plotting package. Can show structures as balls, sticks, lines, 7924 7924 thermal motion ellipsoids and polyhedra. Magnetic moments shown as black/red 7925 7925 arrows according to spin state 7926 7927 :param wx.Frame G2frame: main GSAS-II window 7928 :param dict data: dict with plotting information 7929 (see :ref:`Phase Tree object<Phase_table>`) 7930 :param bool firstCall: If True, this is the initial call and causes 7931 the plot to be shown twice (needed for Mac and possibly linux) 7932 :param function pageCallback: a callback function to 7933 update items on the parent page. Currently implemented for 7934 RB Models tab only 7926 7935 ''' 7927 7936 … … 8304 8313 if G2frame.phaseDisplay.GetPageText(page) == 'RB Models': 8305 8314 for i,sizer in enumerate(G2frame.testRBObjSizers['Xsizers']): 8306 sizer.SetValue('%8.5f'%(testRBObj['rbObj']['Orig'][0][i])) 8307 8315 sizer.SetValue(testRBObj['rbObj']['Orig'][0][i]) 8316 if pageCallback: 8317 try: 8318 pageCallback() 8319 except: 8320 pass 8321 8308 8322 def SetRBOrienText(): 8309 8323 page = getSelection() … … 8312 8326 for i,sizer in enumerate(G2frame.testRBObjSizers['Osizers']): 8313 8327 sizer.SetLabel('%8.5f'%(testRBObj['rbObj']['Orient'][0][i])) 8328 if pageCallback: 8329 try: 8330 pageCallback() 8331 except: 8332 pass 8314 8333 8315 8334 def SetViewDirText(VD): … … 8449 8468 8450 8469 def SetRBTranslation(newxy): 8451 #first get translation vector in screen coords. 8470 #first get translation vector in screen coords. 8471 if 'fixOrig' in rbObj: 8472 if rbObj['fixOrig']: return 8452 8473 oldxy = drawingData['oldxy'] 8453 8474 if not len(oldxy): oldxy = list(newxy) … … 8462 8483 Ty -= V[1]*0.01 8463 8484 Tz -= V[2]*0.01 8464 rbObj['Orig'][0] = Tx,Ty,Tz8485 rbObj['Orig'][0][:] = Tx,Ty,Tz 8465 8486 SetRBOrigText() 8466 8487
Note: See TracChangeset
for help on using the changeset viewer.