source: trunk/GSASIIphsGUI.py @ 936

Last change on this file since 936 was 936, checked in by vondreele, 10 years ago

more MC/SA stuff
further drawing optimization

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 235.9 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - phase data display routines
3########### SVN repository information ###################
4# $Date: 2013-05-30 14:05:36 +0000 (Thu, 30 May 2013) $
5# $Author: vondreele $
6# $Revision: 936 $
7# $URL: trunk/GSASIIphsGUI.py $
8# $Id: GSASIIphsGUI.py 936 2013-05-30 14:05:36Z vondreele $
9########### SVN repository information ###################
10'''
11*GSASIIphsGUI: Phase GUI*
12-------------------------
13
14Module to create the GUI for display of phase information
15in the data display window when a phase is selected.
16(pages displayed in response to some phase tabs are done in other modules,
17such as GSASIIddata.)
18
19'''
20import wx
21import wx.grid as wg
22import wx.lib.gridmovers as wgmove
23import wx.wizard as wz
24import matplotlib as mpl
25import math
26import copy
27import time
28import sys
29import random as ran
30import cPickle
31import GSASIIpath
32GSASIIpath.SetVersionNumber("$Revision: 936 $")
33import GSASIIlattice as G2lat
34import GSASIIspc as G2spc
35import GSASIIElem as G2elem
36import GSASIIElemGUI as G2elemGUI
37import GSASIIddataGUI as G2ddG
38import GSASIIplot as G2plt
39import GSASIIgrid as G2gd
40import GSASIIIO as G2IO
41import GSASIIstrMain as G2stMn
42import GSASIImath as G2mth
43import GSASIIpwd as G2pwd
44import numpy as np
45import numpy.linalg as nl
46import numpy.ma as ma
47
48VERY_LIGHT_GREY = wx.Colour(235,235,235)
49WHITE = wx.Colour(255,255,255)
50BLACK = wx.Colour(0,0,0)
51mapDefault = {'MapType':'','RefList':'','Resolution':0.5,'Show bonds':True,
52                'rho':[],'rhoMax':0.,'mapSize':10.0,'cutOff':50.,'Flip':False}
53# trig functions in degrees
54sind = lambda x: np.sin(x*np.pi/180.)
55tand = lambda x: np.tan(x*np.pi/180.)
56cosd = lambda x: np.cos(x*np.pi/180.)
57asind = lambda x: 180.*np.arcsin(x)/np.pi
58acosd = lambda x: 180.*np.arccos(x)/np.pi
59
60
61def UpdatePhaseData(G2frame,Item,data,oldPage):
62    '''Create the data display window contents when a phase is clicked on
63    in the man (data tree) window.
64    Called only from :mod:`GSASIIgrid.MovePatternTreeToGrid`,
65    which in turn is called from :mod:`GSASII.GSASII.OnPatternTreeSelChanged`
66    when a tree item is selected.
67
68    :param wx.frame G2frame: the main GSAS-II frame object
69
70    :param wx.TreeItemId Item: the tree item that was selected
71
72    :param dict data: all the information on the phase in a dictionary
73
74    :param int oldPage: This sets a tab to select when moving
75      from one phase to another, in which case the same tab is selected
76      to display first. This is set only when the previous data tree
77      selection is a phase, if not the value is None. The default action
78      is to bring up the General tab.
79
80    '''
81       
82#patch
83    if 'RBModels' not in data:
84        data['RBModels'] = {}
85    if 'MCSA' not in data:
86        data['MCSA'] = {'Models':[{'Type':'MD','Coef':[1.0,False,[0.,3.],],'axis':[0,0,1]}],'Results':[],'AtInfo':{}}
87#end patch   
88
89    global rbAtmDict   
90    rbAtmDict = {}
91    if G2frame.dataDisplay:
92        G2frame.dataDisplay.Destroy()
93    PhaseName = G2frame.PatternTree.GetItemText(Item)
94    G2gd.SetDataMenuBar(G2frame)
95    G2frame.dataFrame.SetLabel('Phase Data for '+PhaseName)
96    G2frame.dataFrame.CreateStatusBar()
97    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
98
99    def SetupGeneral():
100        generalData = data['General']
101        atomData = data['Atoms']
102        generalData['AtomTypes'] = []
103        generalData['Isotopes'] = {}
104# various patches
105        if 'Isotope' not in generalData:
106            generalData['Isotope'] = {}
107        if 'Data plot type' not in generalData:
108            generalData['Data plot type'] = 'Mustrain'
109        if 'POhkl' not in generalData:
110            generalData['POhkl'] = [0,0,1]
111        if 'Map' not in generalData:
112            generalData['Map'] = mapDefault
113        if 'Flip' not in generalData:
114            generalData['Flip'] = {'RefList':'','Resolution':0.5,'Norm element':'None',
115                'k-factor':0.1,'k-Max':20.}
116        if 'doPawley' not in generalData:
117            generalData['doPawley'] = False
118        if 'Pawley dmin' not in generalData:
119            generalData['Pawley dmin'] = 1.0
120        if 'Pawley neg wt' not in generalData:
121            generalData['Pawley neg wt'] = 0.0
122        if 'MCSA controls' not in generalData:
123            generalData['MCSA controls'] = {'Data source':'','Annealing':[50.0,0.001,0.90,1000],
124            'dmin':2.0,'Algolrithm':'Random jump','Jump coeff':[0.95,0.5],'nRuns':1} #'Random jump','Tremayne jump'
125# end of patches
126        generalData['NoAtoms'] = {}
127        generalData['BondRadii'] = []
128        generalData['AngleRadii'] = []
129        generalData['vdWRadii'] = []
130        generalData['AtomMass'] = []
131        generalData['Color'] = []
132        generalData['Mydir'] = G2frame.dirname
133        cx,ct,cs,cia = [3,1,7,9]
134        if generalData['Type'] =='macromolecular':
135            cx,ct,cs,cia = [6,4,10,12]
136        generalData['AtomPtrs'] = [cx,ct,cs,cia]
137        for atom in atomData:
138            atom[ct] = atom[ct].lower().capitalize()              #force to standard form
139            if generalData['AtomTypes'].count(atom[ct]):
140                generalData['NoAtoms'][atom[ct]] += atom[cs-1]*float(atom[cs+1])
141            elif atom[ct] != 'UNK':
142                Info = G2elem.GetAtomInfo(atom[ct])
143                generalData['AtomTypes'].append(atom[ct])
144                generalData['Z'] = Info['Z']
145                generalData['Isotopes'][atom[ct]] = Info['Isotopes']
146                generalData['BondRadii'].append(Info['Drad'])
147                generalData['AngleRadii'].append(Info['Arad'])
148                generalData['vdWRadii'].append(Info['Vdrad'])
149                if atom[ct] in generalData['Isotope']:
150                    generalData['AtomMass'].append(Info['Isotopes'][generalData['Isotope'][atom[ct]]][0])
151                else:
152                    generalData['Isotope'][atom[ct]] = 'Nat. Abund.'
153                    generalData['AtomMass'].append(Info['Mass'])
154                generalData['NoAtoms'][atom[ct]] = atom[cs-1]*float(atom[cs+1])
155                generalData['Color'].append(Info['Color'])
156        F000X = 0.
157        F000N = 0.
158        for i,elem in enumerate(generalData['AtomTypes']):
159            F000X += generalData['NoAtoms'][elem]*generalData['Z']
160            isotope = generalData['Isotope'][elem]
161            F000N += generalData['NoAtoms'][elem]*generalData['Isotopes'][elem][isotope][1]
162        generalData['F000X'] = F000X
163        generalData['F000N'] = F000N
164       
165
166################################################################################
167##### General phase routines
168################################################################################
169
170    def UpdateGeneral():
171        '''Draw the controls for the General phase data subpage
172        '''
173       
174        """ This is the default dictionary structure for phase data
175        (taken from GSASII.py)
176        'General':{
177            'Name':PhaseName
178            'Type':'nuclear'
179            'SGData':SGData
180            'Cell':[False,10.,10.,10.,90.,90.,90,1000.]
181            'AtomPtrs':[]
182            'Histogram list':['',]
183            'Pawley dmin':1.0,
184            'Pawley neg wt':0.0}
185        'Atoms':[]
186        'Drawing':{}
187        """       
188        # UpdateGeneral execution starts here
189        phaseTypes = ['nuclear','modulated','magnetic','macromolecular']
190        SetupGeneral()
191        generalData = data['General']
192        Map = generalData['Map']
193        Flip = generalData['Flip']
194        MCSA = generalData['MCSA controls'] 
195        PWDR = any(['PWDR' in item for item in data['Histograms'].keys()])
196        # UpdateGeneral execution continues below
197       
198        def NameSizer():                   
199            def OnPhaseName(event):
200                oldName = generalData['Name']
201                generalData['Name'] = NameTxt.GetValue()
202                G2frame.G2plotNB.Rename(oldName,generalData['Name'])
203                G2frame.dataFrame.SetLabel('Phase Data for '+generalData['Name'])
204                G2frame.PatternTree.SetItemText(Item,generalData['Name'])
205                #Hmm, need to change phase name key in Reflection Lists for each histogram
206                           
207            def OnPhaseType(event):
208                if not generalData['AtomTypes']:             #can change only if no atoms!
209                    generalData['Type'] = TypeTxt.GetValue()
210                    wx.CallAfter(UpdateGeneral)
211                else:
212                    TypeTxt.SetValue(generalData['Type'])               
213               
214            def OnSpaceGroup(event):
215                SpcGp = SGTxt.GetValue()
216                SGErr,SGData = G2spc.SpcGroup(SpcGp)
217                # try a lookup on the user-supplied name
218                if SGErr:
219                    SpGrpNorm = G2spc.StandardizeSpcName(SpcGp)
220                    if SpGrpNorm:
221                        E,SGData = G2spc.SpcGroup(SpGrpNorm)
222                        if not E: SGErr = False
223                if SGErr:
224                    text = [G2spc.SGErrors(SGErr)+'\nSpace Group set to previous']
225                    SGTxt.SetValue(generalData['SGData']['SpGrp'])
226                    msg = 'Space Group Error'
227                    Style = wx.ICON_EXCLAMATION
228                else:
229                    text = G2spc.SGPrint(SGData)
230                    generalData['SGData'] = SGData
231                    msg = 'Space Group Information'
232                    Style = wx.ICON_INFORMATION
233                Text = ''
234                for line in text:
235                    Text += line+'\n'
236                wx.MessageBox(Text,caption=msg,style=Style)
237#                General.DestroyChildren()           #needed to clear away bad cellSizer, etc.
238                wx.CallAfter(UpdateGeneral)
239               
240            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
241            nameSizer.Add(wx.StaticText(General,-1,' Phase name: '),0,wx.ALIGN_CENTER_VERTICAL)
242            NameTxt = wx.TextCtrl(General,-1,value=generalData['Name'],style=wx.TE_PROCESS_ENTER)
243            NameTxt.Bind(wx.EVT_TEXT_ENTER,OnPhaseName)
244            NameTxt.Bind(wx.EVT_KILL_FOCUS,OnPhaseName)
245            nameSizer.Add(NameTxt,0,wx.ALIGN_CENTER_VERTICAL)
246            nameSizer.Add(wx.StaticText(General,-1,'  Phase type: '),0,wx.ALIGN_CENTER_VERTICAL)
247            TypeTxt = wx.ComboBox(General,-1,value=generalData['Type'],choices=phaseTypes,
248                style=wx.CB_READONLY|wx.CB_DROPDOWN)
249            TypeTxt.Bind(wx.EVT_COMBOBOX, OnPhaseType)
250            nameSizer.Add(TypeTxt,0,wx.ALIGN_CENTER_VERTICAL)
251            nameSizer.Add(wx.StaticText(General,-1,'  Space group: '),0,wx.ALIGN_CENTER_VERTICAL)
252            SGTxt = wx.TextCtrl(General,-1,value=generalData['SGData']['SpGrp'],style=wx.TE_PROCESS_ENTER)
253            SGTxt.Bind(wx.EVT_TEXT_ENTER,OnSpaceGroup)
254            nameSizer.Add(SGTxt,0,wx.ALIGN_CENTER_VERTICAL)
255            return nameSizer
256           
257        def CellSizer():
258           
259            cellGUIlist = [[['m3','m3m'],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
260            [['3R','3mR'],6,zip([" a = "," alpha = "," Vol = "],["%.5f","%.3f","%.3f"],[True,True,False],[0,2,0])],
261            [['3','3m1','31m','6/m','6/mmm','4/m','4/mmm'],6,zip([" a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
262            [['mmm'],8,zip([" a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
263                [True,True,True,False],[0,1,2,0])],
264            [['2/m'+'a'],10,zip([" a = "," b = "," c = "," alpha = "," Vol = "],
265                ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
266            [['2/m'+'b'],10,zip([" a = "," b = "," c = "," beta = "," Vol = "],
267                ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
268            [['2/m'+'c'],10,zip([" a = "," b = "," c = "," gamma = "," Vol = "],
269                ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
270            [['-1'],8,zip([" a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
271                ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
272                [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
273               
274            def OnCellRef(event):
275                generalData['Cell'][0] = cellRef.GetValue()
276               
277            def OnCellChange(event):
278                SGData = generalData['SGData']
279                laue = SGData['SGLaue']
280                if laue == '2/m':
281                    laue += SGData['SGUniq']
282                cell = generalData['Cell']
283                Obj = event.GetEventObject()
284                ObjId = cellList.index(Obj.GetId())
285                try:
286                    value = max(1.0,float(Obj.GetValue()))
287                except ValueError:
288                    if ObjId < 3:               #bad cell edge - reset
289                        value = controls[6+ObjId]
290                    else:                       #bad angle
291                        value = 90.
292                if laue in ['m3','m3m']:
293                    cell[1] = cell[2] = cell[3] = value
294                    cell[4] = cell[5] = cell[6] = 90.0
295                    Obj.SetValue("%.5f"%(cell[1]))
296                elif laue in ['3R','3mR']:
297                    if ObjId == 0:
298                        cell[1] = cell[2] = cell[3] = value
299                        Obj.SetValue("%.5f"%(cell[1]))
300                    else:
301                        cell[4] = cell[5] = cell[6] = value
302                        Obj.SetValue("%.5f"%(cell[4]))
303                elif laue in ['3','3m1','31m','6/m','6/mmm','4/m','4/mmm']:                   
304                    cell[4] = cell[5] = 90.
305                    cell[6] = 120.
306                    if laue in ['4/m','4/mmm']:
307                        cell[6] = 90.
308                    if ObjId == 0:
309                        cell[1] = cell[2] = value
310                        Obj.SetValue("%.5f"%(cell[1]))
311                    else:
312                        cell[3] = value
313                        Obj.SetValue("%.5f"%(cell[3]))
314                elif laue in ['mmm']:
315                    cell[ObjId+1] = value
316                    cell[4] = cell[5] = cell[6] = 90.
317                    Obj.SetValue("%.5f"%(cell[ObjId+1]))
318                elif laue in ['2/m'+'a']:
319                    cell[5] = cell[6] = 90.
320                    if ObjId != 3:
321                        cell[ObjId+1] = value
322                        Obj.SetValue("%.5f"%(cell[ObjId+1]))
323                    else:
324                        cell[4] = value
325                        Obj.SetValue("%.3f"%(cell[4]))
326                elif laue in ['2/m'+'b']:
327                    cell[4] = cell[6] = 90.
328                    if ObjId != 3:
329                        cell[ObjId+1] = value
330                        Obj.SetValue("%.5f"%(cell[ObjId+1]))
331                    else:
332                        cell[5] = value
333                        Obj.SetValue("%.3f"%(cell[5]))
334                elif laue in ['2/m'+'c']:
335                    cell[5] = cell[6] = 90.
336                    if ObjId != 3:
337                        cell[ObjId+1] = value
338                        Obj.SetValue("%.5f"%(cell[ObjId+1]))
339                    else:
340                        cell[6] = value
341                        Obj.SetValue("%.3f"%(cell[6]))
342                else:
343                    cell[ObjId+1] = value
344                    if ObjId < 3:
345                        Obj.SetValue("%.5f"%(cell[1+ObjId]))
346                    else:
347                        Obj.SetValue("%.3f"%(cell[1+ObjId]))                       
348                cell[7] = G2lat.calc_V(G2lat.cell2A(cell[1:7]))
349                volVal.SetValue("%.3f"%(cell[7]))
350                density,mattCoeff = G2mth.getDensity(generalData)
351                if denSizer:
352                    denSizer[1].SetValue('%.3f'%(density))
353                    if denSizer[2]:
354                        denSizer[2].SetValue('%.3f'%(mattCoeff))
355                generalData['Cell'] = cell
356           
357            cell = generalData['Cell']
358            laue = generalData['SGData']['SGLaue']
359            if laue == '2/m':
360                laue += generalData['SGData']['SGUniq']
361            for cellGUI in cellGUIlist:
362                if laue in cellGUI[0]:
363                    useGUI = cellGUI
364            cellSizer = wx.FlexGridSizer(2,useGUI[1]+1,5,5)
365            if PWDR:
366                cellRef = wx.CheckBox(General,-1,label='Refine unit cell:')
367                cellSizer.Add(cellRef,0,wx.ALIGN_CENTER_VERTICAL)
368                cellRef.Bind(wx.EVT_CHECKBOX, OnCellRef)
369                cellRef.SetValue(cell[0])
370            cellList = []
371            for txt,fmt,ifEdit,Id in useGUI[2]:
372                cellSizer.Add(wx.StaticText(General,label=txt),0,wx.ALIGN_CENTER_VERTICAL)
373                if ifEdit:          #a,b,c,etc.
374                    cellVal = wx.TextCtrl(General,value=(fmt%(cell[Id+1])),
375                        style=wx.TE_PROCESS_ENTER)
376                    cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
377                    cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
378                    cellSizer.Add(cellVal,0,wx.ALIGN_CENTER_VERTICAL)
379                    cellList.append(cellVal.GetId())
380                else:               #volume
381                    volVal = wx.TextCtrl(General,value=(fmt%(cell[7])),style=wx.TE_READONLY)
382                    volVal.SetBackgroundColour(VERY_LIGHT_GREY)
383                    cellSizer.Add(volVal,0,wx.ALIGN_CENTER_VERTICAL)
384            return cellSizer
385           
386        def ElemSizer():
387           
388            def OnIsotope(event):
389                Obj = event.GetEventObject()
390                item = Indx[Obj.GetId()]
391                isotope = Obj.GetValue()
392                generalData['Isotope'][item] = isotope
393                indx = generalData['AtomTypes'].index(item)
394                data['General']['AtomMass'][indx] = generalData['Isotopes'][item][isotope][0]
395                density,mattCoeff = G2mth.getDensity(generalData)
396                denSizer[1].SetValue('%.3f'%(density))
397                if denSizer[2]:
398                    denSizer[2].SetValue('%.3f'%(mattCoeff))
399               
400            elemSizer = wx.FlexGridSizer(8,len(generalData['AtomTypes'])+1,1,1)
401            elemSizer.Add(wx.StaticText(General,label=' Elements'),0,wx.ALIGN_CENTER_VERTICAL)
402            for elem in generalData['AtomTypes']:
403                typTxt = wx.TextCtrl(General,value=elem,style=wx.TE_READONLY)
404                typTxt.SetBackgroundColour(VERY_LIGHT_GREY)
405                elemSizer.Add(typTxt,0,wx.ALIGN_CENTER_VERTICAL)
406            elemSizer.Add(wx.StaticText(General,label=' Isotope'),0,wx.ALIGN_CENTER_VERTICAL)
407            for elem in generalData['AtomTypes']:
408                choices = generalData['Isotopes'][elem].keys()
409                isoSel = wx.ComboBox(General,-1,value=generalData['Isotope'][elem],choices=choices,
410                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
411                isoSel.Bind(wx.EVT_COMBOBOX,OnIsotope)
412                Indx[isoSel.GetId()] = elem
413                elemSizer.Add(isoSel,1,wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
414            elemSizer.Add(wx.StaticText(General,label=' No. per cell'),0,wx.ALIGN_CENTER_VERTICAL)
415            for elem in generalData['AtomTypes']:
416                numbTxt = wx.TextCtrl(General,value='%.1f'%(generalData['NoAtoms'][elem]),
417                    style=wx.TE_READONLY)
418                numbTxt.SetBackgroundColour(VERY_LIGHT_GREY)
419                elemSizer.Add(numbTxt,0,wx.ALIGN_CENTER_VERTICAL)
420            elemSizer.Add(wx.StaticText(General,label=' Atom weight'),0,wx.ALIGN_CENTER_VERTICAL)
421            for wt in generalData['AtomMass']:
422                wtTxt = wx.TextCtrl(General,value='%.3f'%(wt),style=wx.TE_READONLY)
423                wtTxt.SetBackgroundColour(VERY_LIGHT_GREY)
424                elemSizer.Add(wtTxt,0,wx.ALIGN_CENTER_VERTICAL)
425            elemSizer.Add(wx.StaticText(General,label=' Bond radii'),0,wx.ALIGN_CENTER_VERTICAL)
426            for rad in generalData['BondRadii']:
427                bondRadii = wx.TextCtrl(General,value='%.2f'%(rad),style=wx.TE_READONLY)
428                bondRadii.SetBackgroundColour(VERY_LIGHT_GREY)
429                elemSizer.Add(bondRadii,0,wx.ALIGN_CENTER_VERTICAL)
430            elemSizer.Add(wx.StaticText(General,label=' Angle radii'),0,wx.ALIGN_CENTER_VERTICAL)
431            for rad in generalData['AngleRadii']:
432                elemTxt = wx.TextCtrl(General,value='%.2f'%(rad),style=wx.TE_READONLY)
433                elemTxt.SetBackgroundColour(VERY_LIGHT_GREY)
434                elemSizer.Add(elemTxt,0,wx.ALIGN_CENTER_VERTICAL)
435            elemSizer.Add(wx.StaticText(General,label=' van der Waals radii'),0,wx.ALIGN_CENTER_VERTICAL)
436            for rad in generalData['vdWRadii']:
437                elemTxt = wx.TextCtrl(General,value='%.2f'%(rad),style=wx.TE_READONLY)
438                elemTxt.SetBackgroundColour(VERY_LIGHT_GREY)
439                elemSizer.Add(elemTxt,0,wx.ALIGN_CENTER_VERTICAL)
440            elemSizer.Add(wx.StaticText(General,label=' Default color'),0,wx.ALIGN_CENTER_VERTICAL)
441            for R,G,B in generalData['Color']:
442                colorTxt = wx.TextCtrl(General,value='',style=wx.TE_READONLY)
443                colorTxt.SetBackgroundColour(wx.Colour(R,G,B))
444                elemSizer.Add(colorTxt,0,wx.ALIGN_CENTER_VERTICAL)
445            return elemSizer
446       
447        def DenSizer():
448           
449            mass = G2mth.getMass(generalData)
450            density,mattCoeff = G2mth.getDensity(generalData)
451            denSizer = wx.BoxSizer(wx.HORIZONTAL)
452            denSizer.Add(wx.StaticText(General,-1,' Density: '),0,wx.ALIGN_CENTER_VERTICAL)
453            denTxt = wx.TextCtrl(General,-1,'%.3f'%(density),style=wx.TE_READONLY)
454            denTxt.SetBackgroundColour(VERY_LIGHT_GREY)
455            denSizer.Add(denTxt,0,wx.ALIGN_CENTER_VERTICAL)
456            mattTxt = None       
457            if generalData['Type'] == 'macromolecular' and mass > 0.0:
458                denSizer.Add(wx.StaticText(General,-1,' Matthews coeff.: '),
459                    0,wx.ALIGN_CENTER_VERTICAL)
460                mattTxt = wx.TextCtrl(General,-1,'%.3f'%(mattCoeff),style=wx.TE_READONLY)
461                mattTxt.SetBackgroundColour(VERY_LIGHT_GREY)
462                denSizer.Add(mattTxt,0,wx.ALIGN_CENTER_VERTICAL)
463            return denSizer,denTxt,mattTxt
464           
465        def PawleySizer():
466           
467            def OnPawleyRef(event):
468                generalData['doPawley'] = pawlRef.GetValue()
469           
470            def OnPawleyVal(event):
471                try:
472                    dmin = float(pawlVal.GetValue())
473                    if 0.25 <= dmin <= 20.:
474                        generalData['Pawley dmin'] = dmin
475                except ValueError:
476                    pass
477                pawlVal.SetValue("%.3f"%(generalData['Pawley dmin']))          #reset in case of error               
478           
479            def OnPawleyNegWt(event):
480                try:
481                    wt = float(pawlNegWt.GetValue())
482                    if 0. <= wt <= 1.:
483                        generalData['Pawley neg wt'] = wt
484                except ValueError:
485                    pass
486                pawlNegWt.SetValue("%.2f"%(generalData['Pawley neg wt']))          #reset in case of error               
487
488            pawleySizer = wx.BoxSizer(wx.HORIZONTAL)
489            pawleySizer.Add(wx.StaticText(General,label=' Pawley controls: '),0,wx.ALIGN_CENTER_VERTICAL)
490            pawlRef = wx.CheckBox(General,-1,label=' Do Pawley refinement?')
491            pawlRef.SetValue(generalData['doPawley'])
492            pawlRef.Bind(wx.EVT_CHECKBOX,OnPawleyRef)
493            pawleySizer.Add(pawlRef,0,wx.ALIGN_CENTER_VERTICAL)
494            pawleySizer.Add(wx.StaticText(General,label=' Pawley dmin: '),0,wx.ALIGN_CENTER_VERTICAL)
495            pawlVal = wx.TextCtrl(General,value='%.3f'%(generalData['Pawley dmin']),style=wx.TE_PROCESS_ENTER)
496            pawlVal.Bind(wx.EVT_TEXT_ENTER,OnPawleyVal)       
497            pawlVal.Bind(wx.EVT_KILL_FOCUS,OnPawleyVal)
498            pawleySizer.Add(pawlVal,0,wx.ALIGN_CENTER_VERTICAL)
499            pawleySizer.Add(wx.StaticText(General,label=' Pawley neg. wt.: '),0,wx.ALIGN_CENTER_VERTICAL)
500            pawlNegWt = wx.TextCtrl(General,value='%.2f'%(generalData['Pawley neg wt']),style=wx.TE_PROCESS_ENTER)
501            pawlNegWt.Bind(wx.EVT_TEXT_ENTER,OnPawleyNegWt)       
502            pawlNegWt.Bind(wx.EVT_KILL_FOCUS,OnPawleyNegWt)
503            pawleySizer.Add(pawlNegWt,0,wx.ALIGN_CENTER_VERTICAL)
504            return pawleySizer
505           
506        def MapSizer():
507           
508            def OnMapType(event):
509                Map['MapType'] = mapType.GetValue()
510               
511            def OnRefList(event):
512                Map['RefList'] = refList.GetValue()
513               
514            def OnResVal(event):
515                try:
516                    res = float(mapRes.GetValue())
517                    if 0.25 <= res <= 20.:
518                        Map['Resolution'] = res
519                except ValueError:
520                    pass
521                mapRes.SetValue("%.2f"%(Map['Resolution']))          #reset in case of error
522           
523            def OnCutOff(event):
524                try:
525                    res = float(cutOff.GetValue())
526                    if 10.0 <= res <= 100.:
527                        Map['cutOff'] = res
528                except ValueError:
529                    pass
530                cutOff.SetValue("%.1f"%(Map['cutOff']))          #reset in case of error
531           
532            #patch
533            if 'cutOff' not in Map:
534                Map['cutOff'] = 100.0
535            mapTypes = ['Fobs','Fcalc','delt-F','2*Fo-Fc','Omit','Patterson']
536            refList = data['Histograms'].keys()
537            if not generalData['AtomTypes']:
538                 mapTypes = ['Patterson',]
539                 Map['MapType'] = 'Patterson'
540            mapSizer = wx.BoxSizer(wx.VERTICAL)
541            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
542            lineSizer.Add(wx.StaticText(General,label=' Fourier map controls: Map type: '),0,wx.ALIGN_CENTER_VERTICAL)
543            mapType = wx.ComboBox(General,-1,value=Map['MapType'],choices=mapTypes,
544                style=wx.CB_READONLY|wx.CB_DROPDOWN)
545            mapType.Bind(wx.EVT_COMBOBOX,OnMapType)
546            lineSizer.Add(mapType,0,wx.ALIGN_CENTER_VERTICAL)
547            lineSizer.Add(wx.StaticText(General,label=' Reflection set from: '),0,wx.ALIGN_CENTER_VERTICAL)
548            refList = wx.ComboBox(General,-1,value=Map['RefList'],choices=refList,
549                style=wx.CB_READONLY|wx.CB_DROPDOWN)
550            refList.Bind(wx.EVT_COMBOBOX,OnRefList)
551            lineSizer.Add(refList,0,wx.ALIGN_CENTER_VERTICAL)
552            mapSizer.Add(lineSizer,0,wx.ALIGN_CENTER_VERTICAL)
553            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
554            line2Sizer.Add(wx.StaticText(General,label=' Resolution: '),0,wx.ALIGN_CENTER_VERTICAL)
555            mapRes =  wx.TextCtrl(General,value='%.2f'%(Map['Resolution']),style=wx.TE_PROCESS_ENTER)
556            mapRes.Bind(wx.EVT_TEXT_ENTER,OnResVal)       
557            mapRes.Bind(wx.EVT_KILL_FOCUS,OnResVal)
558            line2Sizer.Add(mapRes,0,wx.ALIGN_CENTER_VERTICAL)
559            line2Sizer.Add(wx.StaticText(General,label=' Peak cutoff %: '),0,wx.ALIGN_CENTER_VERTICAL)
560            cutOff =  wx.TextCtrl(General,value='%.1f'%(Map['cutOff']),style=wx.TE_PROCESS_ENTER)
561            cutOff.Bind(wx.EVT_TEXT_ENTER,OnCutOff)       
562            cutOff.Bind(wx.EVT_KILL_FOCUS,OnCutOff)
563            line2Sizer.Add(cutOff,0,wx.ALIGN_CENTER_VERTICAL)
564            mapSizer.Add(line2Sizer,0,wx.ALIGN_CENTER_VERTICAL)
565            return mapSizer
566               
567        def FlipSizer():
568            if 'k-Max' not in Flip: Flip['k-Max'] = 20.
569           
570            def OnRefList(event):
571                Flip['RefList'] = refList.GetValue()
572               
573            def OnNormElem(event):
574                PE = G2elemGUI.PickElement(G2frame,ifNone=True)
575                if PE.ShowModal() == wx.ID_OK:
576                    Flip['Norm element'] = PE.Elem.strip()
577                    normElem.SetLabel(Flip['Norm element'])
578                PE.Destroy()               
579               
580            def OnResVal(event):
581                try:
582                    res = float(flipRes.GetValue())
583                    if 0.25 <= res <= 20.:
584                        Flip['Resolution'] = res
585                except ValueError:
586                    pass
587                flipRes.SetValue("%.2f"%(Flip['Resolution']))          #reset in case of error
588           
589            def OnkFactor(event):
590                try:
591                    res = float(kFactor.GetValue())
592                    if 0.1 <= res <= 1.2:
593                        Flip['k-factor'] = res
594                except ValueError:
595                    pass
596                kFactor.SetValue("%.3f"%(Flip['k-factor']))          #reset in case of error
597           
598            def OnkMax(event):
599                try:
600                    res = float(kMax.GetValue())
601                    if res >= 10.:
602                        Flip['k-Max'] = res
603                except ValueError:
604                    pass
605                kMax.SetValue("%.1f"%(Flip['k-Max']))          #reset in case of error
606
607            refList = data['Histograms'].keys()
608            flipSizer = wx.BoxSizer(wx.VERTICAL)
609            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
610            lineSizer.Add(wx.StaticText(General,label=' Charge flip controls: Reflection set from: '),0,wx.ALIGN_CENTER_VERTICAL)
611            refList = wx.ComboBox(General,-1,value=Flip['RefList'],choices=refList,
612                style=wx.CB_READONLY|wx.CB_DROPDOWN)
613            refList.Bind(wx.EVT_COMBOBOX,OnRefList)
614            lineSizer.Add(refList,0,wx.ALIGN_CENTER_VERTICAL)
615            lineSizer.Add(wx.StaticText(General,label=' Normalizing element: '),0,wx.ALIGN_CENTER_VERTICAL)
616            normElem = wx.Button(General,label=Flip['Norm element'],style=wx.TE_READONLY)
617            normElem.Bind(wx.EVT_BUTTON,OnNormElem)
618            lineSizer.Add(normElem,0,wx.ALIGN_CENTER_VERTICAL)
619            flipSizer.Add(lineSizer,0,wx.ALIGN_CENTER_VERTICAL)
620            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
621            line2Sizer.Add(wx.StaticText(General,label=' Resolution: '),0,wx.ALIGN_CENTER_VERTICAL)
622            flipRes =  wx.TextCtrl(General,value='%.2f'%(Flip['Resolution']),style=wx.TE_PROCESS_ENTER)
623            flipRes.Bind(wx.EVT_TEXT_ENTER,OnResVal)       
624            flipRes.Bind(wx.EVT_KILL_FOCUS,OnResVal)
625            line2Sizer.Add(flipRes,0,wx.ALIGN_CENTER_VERTICAL)
626            line2Sizer.Add(wx.StaticText(General,label=' k-Factor (0.1-1.2): '),0,wx.ALIGN_CENTER_VERTICAL)
627            kFactor =  wx.TextCtrl(General,value='%.3f'%(Flip['k-factor']),style=wx.TE_PROCESS_ENTER)
628            kFactor.Bind(wx.EVT_TEXT_ENTER,OnkFactor)       
629            kFactor.Bind(wx.EVT_KILL_FOCUS,OnkFactor)
630            line2Sizer.Add(kFactor,0,wx.ALIGN_CENTER_VERTICAL)
631            line2Sizer.Add(wx.StaticText(General,label=' k-Max (>=10.0): '),0,wx.ALIGN_CENTER_VERTICAL)
632            kMax = wx.TextCtrl(General,value='%.1f'%(Flip['k-Max']),style=wx.TE_PROCESS_ENTER)
633            kMax.Bind(wx.EVT_TEXT_ENTER,OnkMax)       
634            kMax.Bind(wx.EVT_KILL_FOCUS,OnkMax)
635            line2Sizer.Add(kMax,0,wx.ALIGN_CENTER_VERTICAL)
636            flipSizer.Add(line2Sizer,0,wx.ALIGN_CENTER_VERTICAL)
637            return flipSizer
638           
639        def MCSASizer():
640            Ind = {}
641           
642            def OnRefList(event):
643                MCSA['Data source'] = refList.GetValue()
644           
645            def OnDmin(event):
646                try:
647                    val = float(dmin.GetValue())
648                    if 1.0 <= val < 5.0:
649                        MCSA['dmin'] = val
650                except ValueError:
651                    pass
652                dmin.SetValue("%.3f"%(MCSA['dmin']))          #reset in case of error
653               
654            def OnNoRuns(event):
655                MCSA['nRuns'] = int(noRuns.GetValue())
656           
657            def OnAlist(event):
658                MCSA['Algolrithm'] = Alist.GetValue()
659                if 'Tremayne' in MCSA['Algolrithm']:
660                    wx.CallAfter(UpdateGeneral)
661           
662            def OnAjump(event):
663                Obj = event.GetEventObject()
664                ind = Indx[Obj.GetId()]
665                try:
666                    val = float(Obj.GetValue())
667                    if .0 <= val <= 1.0:
668                        MCSA['Jump coeff'][ind] = val
669                except ValueError:
670                    pass
671                Obj.SetValue("%.3f"%(MCSA['Jump coeff'][ind]))          #reset in case of error
672           
673            def OnAnneal(event):
674                Obj = event.GetEventObject()
675                ind,fmt = Indx[Obj.GetId()]
676                if ind < 3:
677                    try:
678                        val = float(Obj.GetValue())
679                        if .0 <= val:
680                            MCSA['Annealing'][ind] = val
681                    except ValueError:
682                        pass
683                else:
684                    try:
685                        val = int(Obj.GetValue())
686                        if 1 <= val:
687                            MCSA['Annealing'][3] = val
688                    except ValueError:
689                        pass
690                   
691                Obj.SetValue(fmt%(MCSA['Annealing'][ind]))          #reset in case of error
692                       
693            refList = []
694            if len(data['Pawley ref']):
695                refList = ['Pawley reflections']
696            for item in data['Histograms'].keys():
697                if 'HKLF' in item or 'PWDR' in item:
698                    refList.append(item)
699            mcsaSizer = wx.BoxSizer(wx.VERTICAL)
700            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
701            lineSizer.Add(wx.StaticText(General,label=' Monte Carlo/Simulated Annealing controls: Reflection set from: '),0,wx.ALIGN_CENTER_VERTICAL)
702            refList = wx.ComboBox(General,-1,value=MCSA['Data source'],choices=refList,
703                style=wx.CB_READONLY|wx.CB_DROPDOWN)
704            refList.Bind(wx.EVT_COMBOBOX,OnRefList)
705            lineSizer.Add(refList,0,wx.ALIGN_CENTER_VERTICAL)
706            lineSizer.Add(wx.StaticText(General,label=' d-min: '),0,wx.ALIGN_CENTER_VERTICAL)
707            dmin = wx.TextCtrl(General,-1,value='%.3f'%(MCSA['dmin']),style=wx.TE_PROCESS_ENTER)
708            dmin.Bind(wx.EVT_TEXT_ENTER,OnDmin)       
709            dmin.Bind(wx.EVT_KILL_FOCUS,OnDmin)
710            lineSizer.Add(dmin,0,wx.ALIGN_CENTER_VERTICAL)
711            mcsaSizer.Add(lineSizer)
712            mcsaSizer.Add((5,5),)
713            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
714            Rchoice = ['1','2','3','5','10','15','20']
715            line2Sizer.Add(wx.StaticText(General,label=' No. MC/SA runs: '),0,wx.ALIGN_CENTER_VERTICAL)
716            noRuns = wx.ComboBox(General,-1,value=str(MCSA.get('nRuns',1)),choices=Rchoice,
717                style=wx.CB_READONLY|wx.CB_DROPDOWN)
718            noRuns.Bind(wx.EVT_COMBOBOX,OnNoRuns)
719            line2Sizer.Add(noRuns,0,wx.ALIGN_CENTER_VERTICAL)
720            Achoice = ['Random jump','Tremayne jump']
721            line2Sizer.Add(wx.StaticText(General,label=' MC/SA algorithm: '),0,wx.ALIGN_CENTER_VERTICAL)
722            Alist = wx.ComboBox(General,-1,value=MCSA['Algolrithm'],choices=Achoice,
723                style=wx.CB_READONLY|wx.CB_DROPDOWN)
724            Alist.Bind(wx.EVT_COMBOBOX,OnAlist)
725            line2Sizer.Add(Alist,0,wx.ALIGN_CENTER_VERTICAL)
726            if 'Tremayne' in MCSA['Algolrithm']:
727                for i,name in enumerate([' A-jump: ',' B-jump: ']):
728                    line2Sizer.Add(wx.StaticText(General,label=name),0,wx.ALIGN_CENTER_VERTICAL)
729                    Ajump =  wx.TextCtrl(General,-1,value='%.3f'%(MCSA['Jump coeff'][i]),style=wx.TE_PROCESS_ENTER)
730                    Ajump.Bind(wx.EVT_TEXT_ENTER,OnAjump)       
731                    Ajump.Bind(wx.EVT_KILL_FOCUS,OnAjump)
732                    Indx[Ajump.GetId()] = i
733                    line2Sizer.Add(Ajump,0,wx.ALIGN_CENTER_VERTICAL)
734            mcsaSizer.Add(line2Sizer)
735            mcsaSizer.Add((5,5),)
736            line3Sizer = wx.BoxSizer(wx.HORIZONTAL)
737            line3Sizer.Add(wx.StaticText(General,label=' Annealing schedule: '),0,wx.ALIGN_CENTER_VERTICAL)
738            names = [' Start temp: ',' Final temp: ',' Slope: ',' No. trials: ']
739            fmts = ['%.1f','%.5f','%.2f','%d']
740            for i,[name,fmt] in enumerate(zip(names,fmts)):
741                line3Sizer.Add(wx.StaticText(General,label=name),0,wx.ALIGN_CENTER_VERTICAL)
742                anneal =  wx.TextCtrl(General,-1,value=fmt%(MCSA['Annealing'][i]),style=wx.TE_PROCESS_ENTER)
743                anneal.Bind(wx.EVT_TEXT_ENTER,OnAnneal)       
744                anneal.Bind(wx.EVT_KILL_FOCUS,OnAnneal)
745                Indx[anneal.GetId()] = [i,fmt]
746                line3Sizer.Add(anneal,0,wx.ALIGN_CENTER_VERTICAL)
747            mcsaSizer.Add(line3Sizer)           
748            return mcsaSizer
749
750        # UpdateGeneral execution continues here
751        if General.GetSizer():
752            General.GetSizer().Clear(True)
753        mainSizer = wx.BoxSizer(wx.VERTICAL)
754        mainSizer.Add((5,5),0)
755        mainSizer.Add(NameSizer(),0)
756        mainSizer.Add((5,5),0)       
757        mainSizer.Add(CellSizer(),0)
758        mainSizer.Add((5,5),0)
759       
760        Indx = {}
761        denSizer = None
762        if len(generalData['AtomTypes']):
763            denSizer = DenSizer()
764            mainSizer.Add(denSizer[0])
765            mainSizer.Add((5,5),0)           
766            mainSizer.Add(ElemSizer())
767        G2gd.HorizontalLine(mainSizer,General)
768
769        mainSizer.Add(PawleySizer())
770        G2gd.HorizontalLine(mainSizer,General)
771       
772        mainSizer.Add(MapSizer())
773        G2gd.HorizontalLine(mainSizer,General)
774
775        mainSizer.Add(FlipSizer())
776        G2gd.HorizontalLine(mainSizer,General)
777
778        mainSizer.Add(MCSASizer())
779
780        General.SetSizer(mainSizer)
781        General.SetScrollbars(1,1,1,1)
782
783        if G2frame.dataFrame.PhaseUserSize is None:
784            Size = mainSizer.GetMinSize()
785            Size[0] += 40
786            Size[1] = max(Size[1],290) + 35
787            General.SetSize(Size)
788            General.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
789            Size[1] = min(Size[1],500) # don't let initial size get larger than 500 points
790            G2frame.dataFrame.setSizePosLeft(Size)
791        else:
792            Size = G2frame.dataFrame.PhaseUserSize
793            General.SetSize(G2frame.dataFrame.GetClientSize())
794            Size = mainSizer.ComputeFittingWindowSize(G2frame.dataFrame)
795            General.SetVirtualSize(Size)
796            General.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
797            G2frame.dataFrame.Update()
798        G2frame.dataFrame.SetStatusText('')
799
800################################################################################
801#####  Atom routines
802################################################################################
803
804    def FillAtomsGrid(Atoms):
805        '''Display the contents of the Atoms tab
806        '''
807        def RefreshAtomGrid(event):
808
809            r,c =  event.GetRow(),event.GetCol()
810            if r < 0 and c < 0:
811                for row in range(Atoms.GetNumberRows()):
812                    Atoms.SelectRow(row,True)                   
813            if r < 0:                          #double click on col label! Change all atoms!
814                sel = -1
815                noSkip = True
816                if Atoms.GetColLabelValue(c) == 'refine':
817                    Type = generalData['Type']
818                    if Type in ['nuclear','macromolecular']:
819                        choice = ['F - site fraction','X - coordinates','U - thermal parameters']
820                    elif Type in ['magnetic',]:
821                        choice = ['F - site fraction','X - coordinates','U - thermal parameters','M - magnetic moment']
822                    dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',choice)
823                    if dlg.ShowModal() == wx.ID_OK:
824                        sel = dlg.GetSelections()
825                        parms = ''
826                        for x in sel:
827                            parms += choice[x][0]
828                    dlg.Destroy()
829                elif Atoms.GetColLabelValue(c) == 'I/A':
830                    choice = ['Isotropic','Anisotropic']
831                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Thermal Motion',choice)
832                    if dlg.ShowModal() == wx.ID_OK:
833                        sel = dlg.GetSelection()
834                        parms = choice[sel][0]
835                    dlg.Destroy()
836                elif Atoms.GetColLabelValue(c) == 'Type':
837                    choice = generalData['AtomTypes']
838                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom types',choice)
839                    if dlg.ShowModal() == wx.ID_OK:
840                        sel = dlg.GetSelection()
841                        parms = choice[sel]
842                        noSkip = False
843                        Atoms.ClearSelection()
844                        for row in range(Atoms.GetNumberRows()):
845                            if parms == atomData[row][c]:
846                                Atoms.SelectRow(row,True)
847                    dlg.Destroy()
848                    SetupGeneral()
849                elif Atoms.GetColLabelValue(c) == 'residue':
850                    choice = []
851                    for r in range(Atoms.GetNumberRows()):
852                        if str(atomData[r][c]) not in choice:
853                            choice.append(str(atomData[r][c]))
854                    choice.sort()
855                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Residue',choice)
856                    if dlg.ShowModal() == wx.ID_OK:
857                        sel = dlg.GetSelection()
858                        parms = choice[sel]
859                        noSkip = False
860                        Atoms.ClearSelection()
861                        for row in range(Atoms.GetNumberRows()):
862                            if parms == atomData[row][c]:
863                                Atoms.SelectRow(row,True)
864                    dlg.Destroy()
865                elif Atoms.GetColLabelValue(c) == 'res no':
866                    choice = []
867                    for r in range(Atoms.GetNumberRows()):
868                        if str(atomData[r][c]) not in choice:
869                            choice.append(str(atomData[r][c]))
870                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Residue no.',choice)
871                    if dlg.ShowModal() == wx.ID_OK:
872                        sel = dlg.GetSelection()
873                        parms = choice[sel]
874                        noSkip = False
875                        Atoms.ClearSelection()
876                        for row in range(Atoms.GetNumberRows()):
877                            if int(parms) == atomData[row][c]:
878                                Atoms.SelectRow(row,True)
879                    dlg.Destroy()
880                elif Atoms.GetColLabelValue(c) == 'chain':
881                    choice = []
882                    for r in range(Atoms.GetNumberRows()):
883                        if atomData[r][c] not in choice:
884                            choice.append(atomData[r][c])
885                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Chain',choice)
886                    if dlg.ShowModal() == wx.ID_OK:
887                        sel = dlg.GetSelection()
888                        parms = choice[sel]
889                        noSkip = False
890                        Atoms.ClearSelection()
891                        for row in range(Atoms.GetNumberRows()):
892                            if parms == atomData[row][c]:
893                                Atoms.SelectRow(row,True)
894                    dlg.Destroy()
895                elif Atoms.GetColLabelValue(c) == 'Uiso':       #this needs to ask for value
896                    pass                                        #& then change all 'I' atoms
897                if sel >= 0 and noSkip:
898                    ui = colLabels.index('U11')
899                    us = colLabels.index('Uiso')
900                    ss = colLabels.index('site sym')
901                    for r in range(Atoms.GetNumberRows()):
902                        ID = atomData[r][-1]
903                        if parms != atomData[r][c] and Atoms.GetColLabelValue(c) == 'I/A':
904                            if parms == 'A':                #'I' --> 'A'
905                                Uiso = float(Atoms.GetCellValue(r,us))
906                                sytsym = atomData[r][ss]
907                                CSI = G2spc.GetCSuinel(sytsym)
908                                atomData[r][ui:ui+6] = Uiso*np.array(CSI[3])
909                                atomData[r][us] = 0.0
910                                Atoms.SetCellStyle(r,us,VERY_LIGHT_GREY,True)
911                                for i in range(6):
912                                    ci = ui+i
913                                    Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
914                                    if CSI[2][i]:
915                                        Atoms.SetCellStyle(r,ci,WHITE,False)
916                            else:                           #'A' --> 'I'
917                                Uij = atomData[r][ui:ui+6]
918                                Uiso = (Uij[0]+Uij[1]+Uij[2])/3.0
919                                atomData[r][us] = Uiso
920                                Atoms.SetCellStyle(r,us,WHITE,False)
921                                for i in range(6):
922                                    ci = ui+i
923                                    atomData[r][ci] = 0.0
924                                    Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
925                        if not Atoms.IsReadOnly(r,c):
926                            if Atoms.GetColLabelValue(c) == 'refine':
927                                rbExcl = rbAtmDict.get(atomData[r][-1],'')
928                                if rbExcl:
929                                    for excl in rbExcl:
930                                        atomData[r][c] = parms.replace(excl,'')
931                                else:
932                                    atomData[r][c] = parms
933                            else: 
934                                atomData[r][c] = parms
935                        if 'Atoms' in data['Drawing']:
936                            DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
937                    wx.CallAfter(Paint)
938                   
939        def ChangeAtomCell(event):
940           
941            def chkUij(Uij,CSI): #needs to do something!!!
942                return Uij
943
944            r,c =  event.GetRow(),event.GetCol()
945            if r >= 0 and c >= 0:
946                ID = atomData[r][-1]
947                if Atoms.GetColLabelValue(c) in ['x','y','z']:
948                    ci = colLabels.index('x')
949                    XYZ = atomData[r][ci:ci+3]
950                    if None in XYZ:
951                        XYZ = [0,0,0]
952                    SScol = colLabels.index('site sym')
953                    Mulcol = colLabels.index('mult')
954                    E,SGData = G2spc.SpcGroup(generalData['SGData']['SpGrp'])
955                    Sytsym,Mult = G2spc.SytSym(XYZ,SGData)
956                    atomData[r][SScol] = Sytsym
957                    atomData[r][Mulcol] = Mult
958                    if atomData[r][colLabels.index('I/A')] == 'A':
959                        ui = colLabels.index('U11')
960                        CSI = G2spc.GetCSuinel(Sytsym)
961                        atomData[r][ui:ui+6] = chkUij(atomData[r][ui:ui+6],Sytsym)
962                        for i in range(6):
963                            ci = i+ui
964                            Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
965                            if CSI[2][i]:
966                                Atoms.SetCellStyle(r,ci,WHITE,False)
967                    SetupGeneral()
968                elif Atoms.GetColLabelValue(c) == 'I/A':            #note use of text color to make it vanish!
969                    if atomData[r][c] == 'I':
970                        Uij = atomData[r][c+2:c+8]
971                        atomData[r][c+1] = (Uij[0]+Uij[1]+Uij[2])/3.0
972                        Atoms.SetCellStyle(r,c+1,WHITE,False)
973                        Atoms.SetCellTextColour(r,c+1,BLACK)
974                        for i in range(6):
975                            ci = i+colLabels.index('U11')
976                            Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
977                            Atoms.SetCellTextColour(r,ci,VERY_LIGHT_GREY)
978                            atomData[r][ci] = 0.0
979                    else:
980                        value = atomData[r][c+1]
981                        CSI = G2spc.GetCSuinel(atomData[r][colLabels.index('site sym')])
982                        atomData[r][c+1] =  0.0
983                        Atoms.SetCellStyle(r,c+1,VERY_LIGHT_GREY,True)
984                        Atoms.SetCellTextColour(r,c+1,VERY_LIGHT_GREY)
985                        for i in range(6):
986                            ci = i+colLabels.index('U11')
987                            atomData[r][ci] = value*CSI[3][i]
988                            Atoms.SetCellStyle(r,ci,VERY_LIGHT_GREY,True)
989                            Atoms.SetCellTextColour(r,ci,BLACK)
990                            if CSI[2][i]:
991                                Atoms.SetCellStyle(r,ci,WHITE,False)
992                elif Atoms.GetColLabelValue(c) in ['U11','U22','U33','U12','U13','U23']:
993                    value = atomData[r][c]
994                    CSI = G2spc.GetCSuinel(atomData[r][colLabels.index('site sym')])
995                    iUij = CSI[0][c-colLabels.index('U11')]
996                    for i in range(6):
997                        if iUij == CSI[0][i]:
998                            atomData[r][i+colLabels.index('U11')] = value*CSI[1][i]
999                elif Atoms.GetColLabelValue(c) == 'refine':
1000                    atomData[r][c] = atomData[r][c].replace(rbAtmDict.get(atomData[r][-1],''),'')
1001                if 'Atoms' in data['Drawing']:
1002                    DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1003                wx.CallAfter(Paint)
1004
1005        def AtomTypeSelect(event):
1006            r,c =  event.GetRow(),event.GetCol()
1007            if Atoms.GetColLabelValue(c) == 'Type':
1008                PE = G2elemGUI.PickElement(G2frame)
1009                if PE.ShowModal() == wx.ID_OK:
1010                    if PE.Elem != 'None':                       
1011                        atomData[r][c] = PE.Elem.strip()
1012                        name = atomData[r][c]
1013                        if len(name) in [2,4]:
1014                            atomData[r][c-1] = name[:2]+'(%d)'%(r+1)
1015                        else:
1016                            atomData[r][c-1] = name[:1]+'(%d)'%(r+1)
1017                PE.Destroy()
1018                SetupGeneral()
1019                wx.CallAfter(Paint)
1020                value = Atoms.GetCellValue(r,c)
1021                atomData[r][c] = value
1022                ID = atomData[r][-1]
1023                if 'Atoms' in data['Drawing']:
1024                    DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1025                SetupGeneral()
1026            else:
1027                event.Skip()
1028
1029        def RowSelect(event):
1030            r,c =  event.GetRow(),event.GetCol()
1031            if not event.AltDown():
1032                Atoms.frm = -1
1033                G2frame.dataFrame.SetStatusText('')                   
1034            if r < 0 and c < 0:
1035                if Atoms.IsSelection():
1036                    Atoms.ClearSelection()
1037            elif c < 0:                   #only row clicks
1038                if event.ControlDown():                   
1039                    if r in Atoms.GetSelectedRows():
1040                        Atoms.DeselectRow(r)
1041                    else:
1042                        Atoms.SelectRow(r,True)
1043                elif event.ShiftDown():
1044                    indxs = Atoms.GetSelectedRows()
1045                    Atoms.ClearSelection()
1046                    ibeg = 0
1047                    if indxs:
1048                        ibeg = indxs[-1]
1049                    for row in range(ibeg,r+1):
1050                        Atoms.SelectRow(row,True)
1051                elif event.AltDown():
1052                    if atomData[r][-1] in rbAtmDict:
1053                        G2frame.dataFrame.SetStatusText('**** ERROR - atom is in a rigid body and can not be moved ****')
1054                        Atoms.frm = -1
1055                        Atoms.ClearSelection()
1056                    else:   
1057                        if Atoms.frm < 0:           #pick atom to be moved
1058                            Atoms.frm = r
1059                            Atoms.SelectRow(r,True)
1060                            n = colLabels.index('Name')
1061                            G2frame.dataFrame.SetStatusText('Atom '+atomData[r][n]+' is to be moved')
1062                        else:                       #move it
1063                            item = atomData.pop(Atoms.frm)
1064                            atomData.insert(r,item)
1065                            Atoms.frm = -1
1066                            G2frame.dataFrame.SetStatusText('')
1067                            wx.CallAfter(Paint)
1068                else:
1069                    Atoms.ClearSelection()
1070                    Atoms.SelectRow(r,True)
1071               
1072        def ChangeSelection(event):
1073            r,c =  event.GetRow(),event.GetCol()
1074            if r < 0 and c < 0:
1075                Atoms.ClearSelection()
1076            if c < 0:
1077                if r in Atoms.GetSelectedRows():
1078                    Atoms.DeselectRow(r)
1079                else:
1080                    Atoms.SelectRow(r,True)
1081            if r < 0:
1082                if c in Atoms.GetSelectedCols():
1083                    Atoms.DeselectCol(c)
1084                else:
1085                    Atoms.SelectCol(c,True)
1086                   
1087        def Paint():
1088       
1089            table = []
1090            rowLabels = []
1091            for i,atom in enumerate(atomData):
1092                table.append(atom)
1093                rowLabels.append(str(i))
1094            atomTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1095            Atoms.SetTable(atomTable, True)
1096            Atoms.frm = -1           
1097            colType = colLabels.index('Type')
1098            colR = colLabels.index('refine')
1099            colSS = colLabels.index('site sym')
1100            colX = colLabels.index('x')
1101            colIA = colLabels.index('I/A')
1102            colU11 = colLabels.index('U11')
1103            colUiso = colLabels.index('Uiso')
1104            attr = wx.grid.GridCellAttr()
1105            attr.IncRef()               #fix from Jim Hester
1106            attr.SetEditor(G2gd.GridFractionEditor(Atoms))
1107            for c in range(colX,colX+3):
1108                Atoms.SetColAttr(c, attr)
1109            for i in range(colU11-1,colU11+6):
1110                Atoms.SetColSize(i,50)           
1111            for row in range(Atoms.GetNumberRows()):
1112                atId = atomData[row][-1]
1113                rbExcl = rbAtmDict.get(atId,'')
1114                Atoms.SetReadOnly(row,colSS,True)                         #site sym
1115                Atoms.SetReadOnly(row,colSS+1,True)                       #Mult
1116                if Atoms.GetCellValue(row,colIA) == 'A':
1117                    CSI = G2spc.GetCSuinel(atomData[row][colLabels.index('site sym')])
1118                    Atoms.SetCellStyle(row,colUiso,VERY_LIGHT_GREY,True)
1119                    Atoms.SetCellTextColour(row,colUiso,VERY_LIGHT_GREY)
1120                    for i in range(6):
1121                        ci = colU11+i
1122                        Atoms.SetCellTextColour(row,ci,BLACK)
1123                        Atoms.SetCellStyle(row,ci,VERY_LIGHT_GREY,True)
1124                        if CSI[2][i] and 'U' not in rbExcl:
1125                            Atoms.SetCellStyle(row,ci,WHITE,False)
1126                else:
1127                    Atoms.SetCellStyle(row,colUiso,WHITE,False)
1128                    Atoms.SetCellTextColour(row,colUiso,BLACK)
1129                    if 'U' in rbExcl:
1130                        Atoms.SetCellStyle(row,colUiso,VERY_LIGHT_GREY,True)
1131                    for i in range(6):
1132                        ci = colU11+i
1133                        Atoms.SetCellStyle(row,ci,VERY_LIGHT_GREY,True)
1134                        Atoms.SetCellTextColour(row,ci,VERY_LIGHT_GREY)
1135                if 'X' in rbExcl:
1136                    for c in range(0,colX+3):
1137                        if c != colR:
1138                            Atoms.SetCellStyle(row,c,VERY_LIGHT_GREY,True)
1139            Atoms.AutoSizeColumns(False)
1140
1141        # FillAtomsGrid executable code starts here
1142        generalData = data['General']
1143        atomData = data['Atoms']
1144        DData = data['Drawing']
1145        resRBData = data['RBModels'].get('Residue',[])
1146        vecRBData = data['RBModels'].get('Vector',[])
1147        rbAtmDict = {}
1148        for rbObj in resRBData+vecRBData:
1149            exclList = ['X' for i in range(len(rbObj['Ids']))]
1150            rbAtmDict.update(dict(zip(rbObj['Ids'],exclList)))
1151            if rbObj['ThermalMotion'][0] != 'None':
1152                for id in rbObj['Ids']:
1153                    rbAtmDict[id] += 'U'           
1154        # exclList will be 'x' or 'xu' if TLS used in RB
1155        Items = [G2gd.wxID_ATOMSEDITINSERT,G2gd.wxID_ATOMSEDITDELETE,G2gd.wxID_ATOMSREFINE, 
1156            G2gd.wxID_ATOMSMODIFY,G2gd.wxID_ATOMSTRANSFORM,G2gd.wxID_ATOMVIEWINSERT,G2gd.wxID_ATOMMOVE]
1157        if atomData:
1158            for item in Items:   
1159                G2frame.dataFrame.AtomsMenu.Enable(item,True)
1160        else:
1161            for item in Items:
1162                G2frame.dataFrame.AtomsMenu.Enable(item,False)
1163        Items = [G2gd.wxID_ATOMVIEWINSERT, G2gd.wxID_ATOMSVIEWADD,G2gd.wxID_ATOMMOVE]
1164        if 'showABC' in data['Drawing']:
1165            for item in Items:
1166                G2frame.dataFrame.AtomsMenu.Enable(item,True)
1167        else:
1168            for item in Items:
1169                G2frame.dataFrame.AtomsMenu.Enable(item,False)
1170
1171        AAchoice = ": ,ALA,ARG,ASN,ASP,CYS,GLN,GLU,GLY,HIS,ILE,LEU,LYS,MET,PHE,PRO,SER,THR,TRP,TYR,VAL,MSE,HOH,UNK"
1172        Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+": ,X,XU,U,F,FX,FXU,FU",]+ \
1173            3*[wg.GRID_VALUE_FLOAT+':10,5',]+[wg.GRID_VALUE_FLOAT+':10,4', #x,y,z,frac
1174            wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+":I,A",]
1175        Types += 7*[wg.GRID_VALUE_FLOAT+':10,5',]
1176        colLabels = ['Name','Type','refine','x','y','z','frac','site sym','mult','I/A','Uiso','U11','U22','U33','U12','U13','U23']
1177        if generalData['Type'] == 'magnetic':
1178            colLabels += ['Mx','My','Mz']
1179            Types[2] = wg.GRID_VALUE_CHOICE+": ,X,XU,U,M,MX,MXU,MU,F,FX,FXU,FU,FM,FMX,FMU,"
1180            Types += 3*[wg.GRID_VALUE_FLOAT+':10,4',]
1181        elif generalData['Type'] == 'macromolecular':
1182            colLabels = ['res no','residue','chain'] + colLabels
1183            Types = [wg.GRID_VALUE_STRING,
1184                wg.GRID_VALUE_CHOICE+AAchoice,
1185                wg.GRID_VALUE_STRING] + Types
1186        elif generalData['Type'] == 'modulated':
1187            Types += []
1188            colLabels += []
1189        SGData = data['General']['SGData']
1190        G2frame.dataFrame.SetStatusText('')
1191        if SGData['SGPolax']:
1192            G2frame.dataFrame.SetStatusText('Warning: The location of the origin is arbitrary in '+SGData['SGPolax'])
1193        Atoms.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeAtomCell)
1194        Atoms.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, AtomTypeSelect)
1195        Atoms.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, RefreshAtomGrid)
1196        Atoms.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1197        Atoms.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, ChangeSelection)
1198        Atoms.SetMargins(0,0)
1199        if G2frame.dataFrame.PhaseUserSize is None:
1200            G2frame.dataFrame.setSizePosLeft([700,300])
1201        else:
1202            G2frame.dataFrame.Update()
1203        Paint()
1204
1205    def OnAtomAdd(event):
1206        AtomAdd(0,0,0)
1207        FillAtomsGrid(Atoms)
1208        event.StopPropagation()
1209        G2plt.PlotStructure(G2frame,data)
1210       
1211    def OnAtomViewAdd(event):
1212        try:
1213            drawData = data['Drawing']
1214            x,y,z = drawData['viewPoint'][0]
1215            AtomAdd(x,y,z)
1216        except:
1217            AtomAdd(0,0,0)
1218        FillAtomsGrid(Atoms)
1219        event.StopPropagation()
1220        G2plt.PlotStructure(G2frame,data)
1221               
1222    def AtomAdd(x,y,z,El='H',Name='UNK'):
1223        atomData = data['Atoms']
1224        generalData = data['General']
1225        Ncol = Atoms.GetNumberCols()
1226        atId = ran.randint(0,sys.maxint)
1227        E,SGData = G2spc.SpcGroup(generalData['SGData']['SpGrp'])
1228        Sytsym,Mult = G2spc.SytSym([x,y,z],SGData)
1229        if generalData['Type'] == 'macromolecular':
1230            atomData.append([0,Name,'',Name,El,'',x,y,z,1,Sytsym,Mult,'I',0.10,0,0,0,0,0,0,atId])
1231        elif generalData['Type'] == 'nuclear':
1232            atomData.append([Name,El,'',x,y,z,1,Sytsym,Mult,'I',0.01,0,0,0,0,0,0,atId])
1233        elif generalData['Type'] == 'magnetic':
1234            atomData.append([Name,El,'',x,y,z,1,Sytsym,Mult,0,'I',0.01,0,0,0,0,0,0,0,0,0,atId])
1235        SetupGeneral()
1236        if 'Atoms' in data['Drawing']:           
1237            DrawAtomAdd(data['Drawing'],atomData[-1])
1238
1239    def OnAtomInsert(event):
1240        AtomInsert(0,0,0)
1241        FillAtomsGrid(Atoms)
1242        event.StopPropagation()
1243        G2plt.PlotStructure(G2frame,data)
1244       
1245    def OnAtomViewInsert(event):
1246        if 'Drawing' in data:
1247            drawData = data['Drawing']
1248            x,y,z = drawData['viewPoint'][0]
1249            AtomAdd(x,y,z)
1250            FillAtomsGrid(Atoms)
1251        event.StopPropagation()
1252       
1253    def OnAtomMove(event):
1254        drawData = data['Drawing']
1255        atomData = data['Atoms']
1256        x,y,z = drawData['viewPoint'][0]
1257        colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1258        cx = colLabels.index('x')
1259        indx = Atoms.GetSelectedRows()
1260        if len(indx) != 1:
1261            print '**** ERROR - only one atom can be moved ****'
1262        elif atomData[indx[0]][-1] in rbAtmDict:
1263            print '**** ERROR - Atoms in rigid bodies can not be moved ****'
1264        else:
1265            atomData[indx[0]][cx:cx+3] = [x,y,z]
1266            SetupGeneral()
1267            FillAtomsGrid(Atoms)
1268            ID = atomData[indx[0]][-1]
1269            DrawAtomsReplaceByID(data['Drawing'],atomData[indx[0]],ID)
1270            G2plt.PlotStructure(G2frame,data)
1271        event.StopPropagation()
1272           
1273    def DrawAtomsReplaceByID(drawingData,atom,ID):
1274        IDs = [ID,]
1275        atomData = drawingData['Atoms']
1276        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
1277        for ind in indx:
1278            atomData[ind] = MakeDrawAtom(atom,atomData[ind])
1279               
1280    def MakeDrawAtom(atom,oldatom=None):
1281        AA3letter = ['ALA','ARG','ASN','ASP','CYS','GLN','GLU','GLY','HIS','ILE',
1282            'LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','MSE','HOH','WAT','UNK']
1283        AA1letter = ['A','R','N','D','C','Q','E','G','H','I',
1284            'L','K','M','F','P','S','T','W','Y','V','M',' ',' ',' ']
1285        generalData = data['General']
1286        SGData = generalData['SGData']
1287        if generalData['Type'] == 'nuclear':
1288            if oldatom:
1289                opr = oldatom[5]
1290                if atom[9] == 'A':                   
1291                    X,U = G2spc.ApplyStringOps(opr,SGData,atom[3:6],atom[11:17])
1292                    atomInfo = [atom[:2]+list(X)+oldatom[5:9]+atom[9:11]+list(U)+oldatom[17:]][0]
1293                else:
1294                    X = G2spc.ApplyStringOps(opr,SGData,atom[3:6])
1295                    atomInfo = [atom[:2]+list(X)+oldatom[5:9]+atom[9:]+oldatom[17:]][0]
1296            else:
1297                atomInfo = [atom[:2]+atom[3:6]+['1',]+['vdW balls',]+
1298                    ['',]+[[255,255,255],]+atom[9:]+[[],[]]][0]
1299            ct,cs = [1,8]         #type & color
1300        elif generalData['Type'] == 'macromolecular':
1301            try:
1302                oneLetter = AA3letter.index(atom[1])
1303            except ValueError:
1304                oneLetter = -1
1305            atomInfo = [[atom[1].strip()+atom[0],]+
1306                [AA1letter[oneLetter]+atom[0],]+atom[2:5]+
1307                atom[6:9]+['1',]+['sticks',]+['',]+[[255,255,255],]+atom[12:]+[[],[]]][0]
1308            ct,cs = [4,11]         #type & color
1309        elif generalData['Type'] == 'magnetic':
1310            if oldatom:
1311                atomInfo = [atom[:2]+oldatom[3:]][0]
1312            else:
1313                atomInfo = [atom[:2]+atom[3:6]+['vdW balls',]+['',]+atom[9:]+[[],[]]][0]
1314            ct,cs = [1,8]         #type & color
1315    #     elif generalData['Type'] == 'modulated':
1316    #        ?????   for future
1317        atNum = generalData['AtomTypes'].index(atom[ct])
1318        atomInfo[cs] = list(generalData['Color'][atNum])
1319        return atomInfo
1320       
1321    def AtomInsert(x,y,z):
1322        indx = Atoms.GetSelectedRows()
1323        if indx:
1324            indx = indx[0]
1325            atomData = data['Atoms']
1326            generalData = data['General']
1327            Ncol = Atoms.GetNumberCols()
1328            E,SGData = G2spc.SpcGroup(generalData['SGData']['SpGrp'])
1329            Sytsym,Mult = G2spc.SytSym([0,0,0],SGData)
1330            atId = ran.randint(0,sys.maxint)
1331            if generalData['Type'] == 'macromolecular':
1332                atomData.insert(indx,[0,'UNK','','UNK','UNK','',x,y,z,1,Sytsym,Mult,'I',0.10,0,0,0,0,0,0,atId])
1333            elif generalData['Type'] == 'nuclear':
1334                atomData.insert(indx,['UNK','UNK','',x,y,z,1,Sytsym,Mult,'I',0.01,0,0,0,0,0,0,atId])
1335            elif generalData['Type'] == 'magnetic':
1336                atomData.insert(indx,['UNK','UNK','',x,y,z,1,Sytsym,Mult,0,'I',0.01,0,0,0,0,0,0,0,0,0,atId])
1337            SetupGeneral()
1338
1339    def AtomDelete(event):
1340        indx = Atoms.GetSelectedRows()
1341        IDs = []
1342        if indx:
1343            atomData = data['Atoms']
1344            indx.reverse()
1345            for ind in indx:
1346                atom = atomData[ind]
1347                if atom[-1] in rbAtmDict:
1348                    G2frame.dataFrame.SetStatusText('**** ERROR - atom is in a rigid body and can not be deleted ****')
1349                else:
1350                    IDs.append(atom[-1])
1351                    del atomData[ind]
1352            if 'Atoms' in data['Drawing']:
1353                DrawAtomsDeleteByIDs(IDs)
1354                wx.CallAfter(FillAtomsGrid,Atoms)
1355                G2plt.PlotStructure(G2frame,data)
1356            SetupGeneral()
1357        event.StopPropagation()
1358
1359    def AtomRefine(event):
1360        colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1361        c = colLabels.index('refine')
1362        indx = Atoms.GetSelectedRows()
1363        if indx:
1364            atomData = data['Atoms']
1365            generalData = data['General']
1366            Type = generalData['Type']
1367            if Type in ['nuclear','macromolecular']:
1368                choice = ['F - site fraction','X - coordinates','U - thermal parameters']
1369            elif Type == 'magnetic':
1370                choice = ['F - site fraction','X - coordinates','U - thermal parameters','M - magnetic moment']
1371            dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',choice)
1372            if dlg.ShowModal() == wx.ID_OK:
1373                sel = dlg.GetSelections()
1374                parms = ''
1375                for x in sel:
1376                    parms += choice[x][0]
1377                for r in indx:
1378                    if not Atoms.IsReadOnly(r,c):
1379                        atomData[r][c] = parms
1380                Atoms.ForceRefresh()
1381            dlg.Destroy()
1382
1383    def AtomModify(event):
1384        indx = Atoms.GetSelectedRows()
1385        if indx:
1386            atomData = data['Atoms']
1387            generalData = data['General']
1388            colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1389            choices = ['Type','Name','x','y','z','frac','I/A','Uiso']
1390            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom parameter',choices)
1391            parm = ''
1392            if dlg.ShowModal() == wx.ID_OK:
1393                sel = dlg.GetSelection()
1394                parm = choices[sel]
1395                cid = colLabels.index(parm)
1396            dlg.Destroy()
1397            if parm in ['Type']:
1398                dlg = G2elemGUI.PickElement(G2frame)
1399                if dlg.ShowModal() == wx.ID_OK:
1400                    if dlg.Elem not in ['None']:
1401                        El = dlg.Elem.strip()
1402                        for r in indx:                       
1403                            if not Atoms.IsReadOnly(r,cid):
1404                                atomData[r][cid] = El
1405                                if len(El) in [2,4]:
1406                                    atomData[r][cid-1] = El[:2]+'(%d)'%(r+1)
1407                                else:
1408                                    atomData[r][cid-1] = El[:1]+'(%d)'%(r+1)
1409                        SetupGeneral()
1410                        if 'Atoms' in data['Drawing']:
1411                            for r in indx:
1412                                ID = atomData[r][-1]
1413                                DrawAtomsReplaceByID(data['Drawing'],atomData[r],ID)
1414                    FillAtomsGrid(Atoms)
1415                dlg.Destroy()
1416            elif parm in ['Name',]:
1417                dlg = wx.MessageDialog(G2frame,'Do you really want to rename the selected atoms?','Rename', 
1418                    wx.YES_NO | wx.ICON_QUESTION)
1419                try:
1420                    result = dlg.ShowModal()
1421                    if result == wx.ID_YES:
1422                        for r in indx:
1423                            if not Atoms.IsReadOnly(r,cid+1):
1424                                El = atomData[r][cid+1]
1425                                if len(El) in [2,4]:
1426                                    atomData[r][cid] = El[:2]+'(%d)'%(r+1)
1427                                else:
1428                                    atomData[r][cid] = El[:1]+'(%d)'%(r+1)
1429                    FillAtomsGrid(Atoms)
1430                finally:
1431                    dlg.Destroy()
1432                   
1433            elif parm in ['I/A']:
1434                choices = ['Isotropic','Anisotropic']
1435                dlg = wx.SingleChoiceDialog(G2frame,'Select','Thermal parameter model',choices)
1436                if dlg.ShowModal() == wx.ID_OK:
1437                    sel = dlg.GetSelection()
1438                    parm = choices[sel][0]
1439                    for r in indx:                       
1440                        if not Atoms.IsReadOnly(r,cid):
1441                            atomData[r][cid] = parm
1442                    FillAtomsGrid(Atoms)
1443                dlg.Destroy()
1444            elif parm in ['frac','Uiso']:
1445                limits = [0.,1.]
1446                val = 1.0
1447                if  parm in ['Uiso']:
1448                    limits = [0.,0.25]
1449                    val = 0.01
1450                dlg = G2gd.SingleFloatDialog(G2frame,'New value','Enter new value for '+parm,val,limits)
1451                if dlg.ShowModal() == wx.ID_OK:
1452                    parm = dlg.GetValue()
1453                    for r in indx:                       
1454                        if not Atoms.IsReadOnly(r,cid):
1455                            atomData[r][cid] = parm
1456                    SetupGeneral()
1457                    FillAtomsGrid(Atoms)
1458                dlg.Destroy()
1459            elif parm in ['x','y','z']:
1460                limits = [-1.,1.]
1461                val = 0.
1462                dlg = G2gd.SingleFloatDialog(G2frame,'Atom shift','Enter shift for '+parm,val,limits)
1463                if dlg.ShowModal() == wx.ID_OK:
1464                    parm = dlg.GetValue()
1465                    for r in indx:                       
1466                        if not Atoms.IsReadOnly(r,cid):
1467                            atomData[r][cid] += parm
1468                    SetupGeneral()
1469                    FillAtomsGrid(Atoms)
1470                dlg.Destroy()
1471
1472    def AtomTransform(event):
1473        indx = Atoms.GetSelectedRows()
1474        if indx:
1475            generalData = data['General']
1476            colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1477            cx = colLabels.index('x')
1478            cuia = colLabels.index('I/A')
1479            cuij = colLabels.index('U11')
1480            css = colLabels.index('site sym')
1481            atomData = data['Atoms']
1482            generalData = data['General']
1483            SGData = generalData['SGData']
1484            dlg = G2gd.SymOpDialog(G2frame,SGData,True,True)
1485            New = False
1486            try:
1487                if dlg.ShowModal() == wx.ID_OK:
1488                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
1489                    Cell = np.array(Cell)
1490                    cent = SGData['SGCen'][Cent]
1491                    M,T = SGData['SGOps'][Opr]
1492                    for ind in indx:
1493                        XYZ = np.array(atomData[ind][cx:cx+3])
1494                        XYZ = np.inner(M,XYZ)+T
1495                        if Inv:
1496                            XYZ = -XYZ
1497                        XYZ = XYZ+cent+Cell
1498                        if Force:
1499                            XYZ = G2spc.MoveToUnitCell(XYZ)
1500                        if New:
1501                            atom = copy.copy(atomData[ind])
1502                        else:
1503                            atom = atomData[ind]
1504                        atom[cx:cx+3] = XYZ
1505                        atom[css:css+2] = G2spc.SytSym(XYZ,SGData)
1506                        if atom[cuia] == 'A':
1507                            Uij = atom[cuij:cuij+6]
1508                            U = G2spc.Uij2U(Uij)
1509                            U = np.inner(np.inner(M,U),M)
1510                            Uij = G2spc.U2Uij(U)
1511                            atom[cuij:cuij+6] = Uij
1512                        if New:
1513                            atomData.append(atom)
1514            finally:
1515                dlg.Destroy()
1516            Atoms.ClearSelection()
1517            if New:
1518                FillAtomsGrid(Atoms)
1519            else:
1520                Atoms.ForceRefresh()
1521
1522    def OnDistAngle(event):
1523        indx = Atoms.GetSelectedRows()
1524        Oxyz = []
1525        xyz = []
1526        DisAglData = {}
1527        DisAglCtls = {}
1528        if indx:
1529            generalData = data['General']
1530            DisAglData['OrigIndx'] = indx
1531            if 'DisAglCtls' in generalData:
1532                DisAglCtls = generalData['DisAglCtls']
1533            dlg = G2gd.DisAglDialog(G2frame,DisAglCtls,generalData)
1534            if dlg.ShowModal() == wx.ID_OK:
1535                DisAglCtls = dlg.GetData()
1536            dlg.Destroy()
1537            generalData['DisAglCtls'] = DisAglCtls
1538            atomData = data['Atoms']
1539            colLabels = [Atoms.GetColLabelValue(c) for c in range(Atoms.GetNumberCols())]
1540            cx = colLabels.index('x')
1541            cn = colLabels.index('Name')
1542            for i,atom in enumerate(atomData):
1543                xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
1544                if i in indx:
1545                    Oxyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
1546            DisAglData['OrigAtoms'] = Oxyz
1547            DisAglData['TargAtoms'] = xyz
1548            generalData = data['General']
1549            DisAglData['SGData'] = generalData['SGData']
1550            DisAglData['Cell'] = generalData['Cell'][1:] #+ volume
1551            if 'pId' in data:
1552                DisAglData['pId'] = data['pId']
1553                DisAglData['covData'] = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
1554            try:
1555                G2stMn.DistAngle(DisAglCtls,DisAglData)
1556            except KeyError:        # inside DistAngle for missing atom types in DisAglCtls
1557                print '**** ERROR - try again but do "Reset" to fill in missing atom types ****'
1558               
1559    def OnReImport(event):
1560        print 'reimport atoms from file to be developed'
1561        reqrdr = G2frame.dataFrame.ReImportMenuId.get(event.GetId())
1562        rdlist = G2frame.OnImportGeneric(reqrdr,
1563                                         G2frame.ImportPhaseReaderlist,
1564                                         'phase')
1565        if len(rdlist) == 0: return
1566        # for now rdlist is only expected to have one element
1567        # for now always use the first phase for when multiple phases are ever implemented
1568        # but it would be better to loop until we find a phase that matches the one in data
1569        for rd in rdlist:
1570            # rd contains all info for a phase
1571            PhaseName = rd.Phase['General']['Name']
1572            print 'Read phase '+str(PhaseName)+' from file '+str(G2frame.lastimport)
1573            print rd.Phase['Atoms']
1574            return
1575                       
1576################################################################################
1577#Structure drawing GUI stuff               
1578################################################################################
1579
1580    def SetupDrawingData():
1581        generalData = data['General']
1582        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
1583        atomData = data['Atoms']
1584        AA3letter = ['ALA','ARG','ASN','ASP','CYS','GLN','GLU','GLY','HIS','ILE',
1585            'LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','MSE','HOH','WAT','UNK']
1586        AA1letter = ['A','R','N','D','C','Q','E','G','H','I',
1587            'L','K','M','F','P','S','T','W','Y','V','M',' ',' ',' ']
1588        defaultDrawing = {'Atoms':[],'viewPoint':[[0.5,0.5,0.5],[]],'showHydrogen':True,
1589            'backColor':[0,0,0],'depthFog':False,'Zclip':50.0,'cameraPos':50.,'Zstep':0.5,
1590            'radiusFactor':0.85,'contourLevel':1.,'bondRadius':0.1,'ballScale':0.33,
1591            'vdwScale':0.67,'ellipseProb':50,'sizeH':0.50,'unitCellBox':True,
1592            'showABC':True,'selectedAtoms':[],'Atoms':[],'oldxy':[],
1593            'bondList':{},'viewDir':[1,0,0]}
1594        V0 = np.array([0,0,1])
1595        V = np.inner(Amat,V0)
1596        V /= np.sqrt(np.sum(V**2))
1597        A = np.arccos(np.sum(V*V0))
1598        defaultDrawing['Quaternion'] = G2mth.AV2Q(A,[0,1,0])
1599        try:
1600            drawingData = data['Drawing']
1601        except KeyError:
1602            data['Drawing'] = {}
1603            drawingData = data['Drawing']
1604        if not drawingData:                 #fill with defaults if empty
1605            drawingData.update(defaultDrawing)
1606        if 'Zstep' not in drawingData:
1607            drawingData['Zstep'] = 0.5
1608        if 'contourLevel' not in drawingData:
1609            drawingData['contourLevel'] = 1.
1610        if 'viewDir' not in drawingData:
1611            drawingData['viewDir'] = [0,0,1]
1612        if 'Quaternion' not in drawingData:
1613            drawingData['Quaternion'] = G2mth.AV2Q(2*np.pi,np.inner(Amat,[0,0,1]))
1614        if 'showRigidBodies' not in drawingData:
1615            drawingData['showRigidBodies'] = True
1616        cx,ct,cs,ci = [0,0,0,0]
1617        if generalData['Type'] == 'nuclear':
1618            cx,ct,cs,ci = [2,1,6,17]         #x, type, style & index
1619        elif generalData['Type'] == 'macromolecular':
1620            cx,ct,cs,ci = [5,4,9,20]         #x, type, style & index
1621        elif generalData['Type'] == 'magnetic':
1622            cx,ct,cs,ci = [2,1,6,20]         #x, type, style & index
1623#        elif generalData['Type'] == 'modulated':
1624#           ?????   for future
1625        drawingData['atomPtrs'] = [cx,ct,cs,ci]
1626        if not drawingData.get('Atoms'):
1627            for atom in atomData:
1628                DrawAtomAdd(drawingData,atom)
1629            data['Drawing'] = drawingData
1630           
1631    def DrawAtomAdd(drawingData,atom):
1632        drawingData['Atoms'].append(MakeDrawAtom(atom))
1633       
1634    def OnRestraint(event):       
1635        indx = drawAtoms.GetSelectedRows()
1636        restData = G2frame.PatternTree.GetItemPyData(   
1637            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Restraints'))
1638        drawingData = data['Drawing']
1639        generalData = data['General']
1640        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
1641        cx,ct,cs,ci = drawingData['atomPtrs']
1642        atomData = drawingData['Atoms']
1643        atNames = []
1644        atXYZ = []
1645        atSymOp = []
1646        atIndx = []
1647        for item in indx:
1648            atXYZ.append(np.array(atomData[item][cx:cx+3]))
1649            atSymOp.append(atomData[item][cs-1])
1650            atIndx.append(atomData[item][ci])
1651        if event.GetId() == G2gd.wxID_DRAWRESTRBOND and len(indx) == 2:
1652            try:
1653                bondData = restData[PhaseName]['Bond']
1654            except KeyError:
1655                bondData = {'wtFactor':1.0,'Bonds':[],'Use':True}
1656                restData[PhaseName] = {}
1657                restData[PhaseName]['Bond'] = bondData
1658            dist = G2mth.getRestDist(atXYZ,Amat)
1659            bondData['Bonds'].append([atIndx,atSymOp,1.54,0.01])
1660        elif event.GetId() == G2gd.wxID_DRAWRESTRANGLE and len(indx) == 3:
1661            try:
1662                angleData = restData[PhaseName]['Angle']
1663            except KeyError:
1664                angleData = {'wtFactor':1.0,'Angles':[],'Use':True}
1665                restData[PhaseName] = {}
1666                restData[PhaseName]['Angle'] = angleData
1667            angle = G2mth.getRestAngle(atXYZ,Amat)
1668            angleData['Angles'].append([atIndx,atSymOp,109.5,1.0])           
1669        elif event.GetId() == G2gd.wxID_DRAWRESTRPLANE and len(indx) > 3:
1670            try:
1671                planeData = restData[PhaseName]['Plane']
1672            except KeyError:
1673                planeData = {'wtFactor':1.0,'Planes':[],'Use':True}
1674                restData[PhaseName] = {}
1675                restData[PhaseName]['Plane'] = planeData
1676            plane = G2mth.getRestPlane(atXYZ,Amat)
1677            planeData['Planes'].append([atIndx,atSymOp,0.0,0.01])           
1678        elif event.GetId() == G2gd.wxID_DRAWRESTRCHIRAL and len(indx) == 4:
1679            try:
1680                chiralData = restData[PhaseName]['Chiral']
1681            except KeyError:
1682                chiralData = {'wtFactor':1.0,'Volumes':[],'Use':True}
1683                restData[PhaseName] = {}
1684                restData[PhaseName]['Chiral'] = chiralData
1685            volume = G2mth.getRestChiral(atXYZ,Amat)
1686            chiralData['Volumes'].append([atIndx,atSymOp,2.5,0.1])           
1687        else:
1688            print '**** ERROR wrong number of atoms selected for this restraint'
1689            return
1690        G2frame.PatternTree.SetItemPyData(   
1691            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Restraints'),restData)
1692
1693    def OnDefineRB(event):
1694        indx = drawAtoms.GetSelectedRows()
1695        indx.sort()
1696        RBData = G2frame.PatternTree.GetItemPyData(   
1697            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
1698        drawingData = data['Drawing']
1699        generalData = data['General']
1700        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
1701        cx,ct,cs,ci = drawingData['atomPtrs']
1702        atomData = drawingData['Atoms']
1703        rbXYZ = []
1704        rbType = []
1705        atNames = []
1706        AtInfo = RBData['Residue']['AtInfo']
1707        for i,item in enumerate(indx):
1708            rbtype = atomData[item][ct]
1709            atNames.append(rbtype+str(i))
1710            rbType.append(rbtype)
1711            if rbtype not in AtInfo:
1712                Info = G2elem.GetAtomInfo(rbtype)
1713                AtInfo[rbtype] = [Info['Drad'],Info['Color']]
1714            rbXYZ.append(np.inner(np.array(atomData[item][cx:cx+3]),Amat))
1715        rbXYZ = np.array(rbXYZ)
1716        rbXYZ -= rbXYZ[0]
1717        rbId = ran.randint(0,sys.maxint)
1718        rbName = 'UNKRB'
1719        dlg = wx.TextEntryDialog(G2frame,'Enter the name for the new rigid body',
1720            'Edit rigid body name',rbName ,style=wx.OK)
1721        if dlg.ShowModal() == wx.ID_OK:
1722            rbName = dlg.GetValue()
1723        dlg.Destroy()
1724        RBData['Residue'][rbId] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbType,
1725            'atNames':atNames,'rbRef':[0,1,2,False],'rbSeq':[],'SelSeq':[0,0],'useCount':0}
1726        RBData['RBIds']['Residue'].append(rbId)
1727        G2frame.dataFrame.SetStatusText('New rigid body UNKRB added to set of Residue rigid bodies')
1728
1729################################################################################
1730##### Atom draw routines
1731################################################################################
1732           
1733    def UpdateDrawAtoms(atomStyle=''):
1734        def RefreshAtomGrid(event):
1735            def SetChoice(name,c,n=0):
1736                choice = []
1737                for r in range(len(atomData)):
1738                    if n:
1739                        srchStr = str(atomData[r][c][:n])
1740                    else:
1741                        srchStr = str(atomData[r][c])
1742                    if srchStr not in choice:
1743                        if n:
1744                            choice.append(str(atomData[r][c][:n]))
1745                        else:
1746                            choice.append(str(atomData[r][c]))
1747                choice.sort()
1748
1749                dlg = wx.MultiChoiceDialog(G2frame,'Select',name,choice)
1750                if dlg.ShowModal() == wx.ID_OK:
1751                    sel = dlg.GetSelections()
1752                    parms = []
1753                    for x in sel:
1754                        parms.append(choice[x])
1755                    noSkip = False
1756                    drawAtoms.ClearSelection()
1757                    drawingData['selectedAtoms'] = []
1758                    for row in range(len(atomData)):
1759                        test = atomData[row][c]
1760                        if n:
1761                            test = test[:n]
1762                        if  test in parms:
1763                            drawAtoms.SelectRow(row,True)
1764                            drawingData['selectedAtoms'].append(row)
1765                    G2plt.PlotStructure(G2frame,data)                   
1766                dlg.Destroy()
1767               
1768            r,c =  event.GetRow(),event.GetCol()
1769            if r < 0 and c < 0:
1770                for row in range(drawAtoms.GetNumberRows()):
1771                    drawingData['selectedAtoms'].append(row)
1772                    drawAtoms.SelectRow(row,True)                   
1773            elif r < 0:                          #dclick on col label
1774                sel = -1
1775                Parms = False
1776                noSkip = True
1777                if drawAtoms.GetColLabelValue(c) == 'Style':
1778                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1779                    if dlg.ShowModal() == wx.ID_OK:
1780                        sel = dlg.GetSelection()
1781                        parms = styleChoice[sel]
1782                        for r in range(len(atomData)):
1783                            atomData[r][c] = parms
1784                            drawAtoms.SetCellValue(r,c,parms)
1785                        FindBondsDraw()
1786                        G2plt.PlotStructure(G2frame,data)
1787                    dlg.Destroy()
1788                elif drawAtoms.GetColLabelValue(c) == 'Label':
1789                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom labelling style',labelChoice)
1790                    if dlg.ShowModal() == wx.ID_OK:
1791                        sel = dlg.GetSelection()
1792                        parms = labelChoice[sel]
1793                        for r in range(len(atomData)):
1794                            atomData[r][c] = parms
1795                            drawAtoms.SetCellValue(r,c,parms)
1796                    dlg.Destroy()                   
1797                elif drawAtoms.GetColLabelValue(c) == 'Color':
1798                    dlg = wx.ColourDialog(G2frame)
1799                    if dlg.ShowModal() == wx.ID_OK:
1800                        color = dlg.GetColourData().GetColour()
1801                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1802                        attr.SetReadOnly(True)
1803                        attr.SetBackgroundColour(color)
1804                        for r in range(len(atomData)):
1805                            atomData[r][c] = color
1806                            drawingData['Atoms'][r][c] = color
1807                            drawAtoms.SetAttr(r,c,attr)
1808                        UpdateDrawAtoms()
1809                    dlg.Destroy()
1810                elif drawAtoms.GetColLabelValue(c) == 'Residue':
1811                    SetChoice('Residue',c,3)
1812                elif drawAtoms.GetColLabelValue(c) == '1-letter':
1813                    SetChoice('1-letter',c,1)
1814                elif drawAtoms.GetColLabelValue(c) == 'Chain':
1815                    SetChoice('Chain',c)
1816                elif drawAtoms.GetColLabelValue(c) == 'Name':
1817                    SetChoice('Name',c)
1818                elif drawAtoms.GetColLabelValue(c) == 'Sym Op':
1819                    SetChoice('Name',c)
1820                elif drawAtoms.GetColLabelValue(c) == 'Type':
1821                    SetChoice('Type',c)
1822                elif drawAtoms.GetColLabelValue(c) in ['x','y','z','I/A']:
1823                    drawAtoms.ClearSelection()
1824            else:
1825                if drawAtoms.GetColLabelValue(c) in ['Style','Label']:
1826                    atomData[r][c] = drawAtoms.GetCellValue(r,c)
1827                    FindBondsDraw()
1828                elif drawAtoms.GetColLabelValue(c) == 'Color':
1829                    dlg = wx.ColourDialog(G2frame)
1830                    if dlg.ShowModal() == wx.ID_OK:
1831                        color = dlg.GetColourData().GetColour()
1832                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1833                        attr.SetReadOnly(True)
1834                        attr.SetBackgroundColour(color)
1835                        atomData[r][c] = color
1836                        drawingData['Atoms'][r][c] = color
1837                        drawAtoms.SetAttr(i,cs+2,attr)
1838                    dlg.Destroy()
1839                    UpdateDrawAtoms()
1840            G2plt.PlotStructure(G2frame,data)
1841                   
1842        def RowSelect(event):
1843            r,c =  event.GetRow(),event.GetCol()
1844            if r < 0 and c < 0:
1845                if drawAtoms.IsSelection():
1846                    drawAtoms.ClearSelection()
1847            elif c < 0:                   #only row clicks
1848                if event.ControlDown():                   
1849                    if r in drawAtoms.GetSelectedRows():
1850                        drawAtoms.DeselectRow(r)
1851                    else:
1852                        drawAtoms.SelectRow(r,True)
1853                elif event.ShiftDown():
1854                    indxs = drawAtoms.GetSelectedRows()
1855                    drawAtoms.ClearSelection()
1856                    ibeg = 0
1857                    if indxs:
1858                        ibeg = indxs[-1]
1859                    for row in range(ibeg,r+1):
1860                        drawAtoms.SelectRow(row,True)
1861                else:
1862                    drawAtoms.ClearSelection()
1863                    drawAtoms.SelectRow(r,True)               
1864            drawingData['selectedAtoms'] = []
1865            drawingData['selectedAtoms'] = drawAtoms.GetSelectedRows()
1866            G2plt.PlotStructure(G2frame,data)                   
1867
1868        # UpdateDrawAtoms executable code starts here
1869        G2frame.dataFrame.SetStatusText('')
1870        generalData = data['General']
1871        SetupDrawingData()
1872        drawingData = data['Drawing']
1873        cx,ct,cs,ci = drawingData['atomPtrs']
1874        atomData = drawingData['Atoms']
1875        if atomStyle:
1876            for atom in atomData:
1877                atom[cs] = atomStyle
1878        Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]+ \
1879            [wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,polyhedra",
1880            wg.GRID_VALUE_CHOICE+": ,type,name,number",wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]
1881        styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1882        labelChoice = [' ','type','name','number']
1883        colLabels = ['Name','Type','x','y','z','Sym Op','Style','Label','Color','I/A']
1884        if generalData['Type'] == 'macromolecular':
1885            colLabels = ['Residue','1-letter','Chain'] + colLabels
1886            Types = 3*[wg.GRID_VALUE_STRING,]+Types
1887            Types[8] = wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,backbone,ribbons,schematic"
1888            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','backbone','ribbons','schematic']
1889            labelChoice = [' ','type','name','number','residue','1-letter','chain']
1890            Types[9] = wg.GRID_VALUE_CHOICE+": ,type,name,number,residue,1-letter,chain"
1891#        elif generalData['Type'] == 'modulated':
1892#            Types += []
1893#            colLabels += []
1894        table = []
1895        rowLabels = []
1896        for i,atom in enumerate(drawingData['Atoms']):
1897            table.append(atom[:colLabels.index('I/A')+1])
1898            rowLabels.append(str(i))
1899
1900        atomTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1901        drawAtoms.SetTable(atomTable, True)
1902        drawAtoms.SetMargins(0,0)
1903        drawAtoms.AutoSizeColumns(True)
1904        drawAtoms.SetColSize(colLabels.index('Style'),80)
1905        drawAtoms.SetColSize(colLabels.index('Color'),50)
1906        drawAtoms.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshAtomGrid)
1907        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, RefreshAtomGrid)
1908        drawAtoms.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, RefreshAtomGrid)
1909        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1910        for i,atom in enumerate(drawingData['Atoms']):
1911            attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1912            attr.SetReadOnly(True)
1913            attr.SetBackgroundColour(atom[cs+2])
1914            drawAtoms.SetAttr(i,cs+2,attr)
1915            drawAtoms.SetCellValue(i,cs+2,'')
1916        indx = drawingData['selectedAtoms']
1917        if indx:
1918            for r in range(len(atomData)):
1919                if r in indx:
1920                    drawAtoms.SelectRow(r)
1921        for c in range(len(colLabels)):
1922           attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1923           attr.SetReadOnly(True)
1924           attr.SetBackgroundColour(VERY_LIGHT_GREY)
1925           if colLabels[c] not in ['Style','Label','Color']:
1926                drawAtoms.SetColAttr(c,attr)
1927        if G2frame.dataFrame.PhaseUserSize is None:
1928            G2frame.dataFrame.setSizePosLeft([600,300])
1929        else:
1930            G2frame.dataFrame.Update()
1931       
1932        FindBondsDraw()
1933        drawAtoms.ClearSelection()
1934        G2plt.PlotStructure(G2frame,data)
1935
1936    def DrawAtomStyle(event):
1937        indx = drawAtoms.GetSelectedRows()
1938        if indx:
1939            generalData = data['General']
1940            atomData = data['Drawing']['Atoms']
1941            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1942            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1943            if generalData['Type'] == 'macromolecular':
1944                styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids',
1945                'backbone','ribbons','schematic']
1946            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1947            if dlg.ShowModal() == wx.ID_OK:
1948                sel = dlg.GetSelection()
1949                parms = styleChoice[sel]
1950                for r in indx:
1951                    atomData[r][cs] = parms
1952                    drawAtoms.SetCellValue(r,cs,parms)
1953            dlg.Destroy()
1954            FindBondsDraw()
1955            drawAtoms.ClearSelection()
1956            G2plt.PlotStructure(G2frame,data)
1957
1958    def DrawAtomLabel(event):
1959        indx = drawAtoms.GetSelectedRows()
1960        if indx:
1961            generalData = data['General']
1962            atomData = data['Drawing']['Atoms']
1963            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1964            styleChoice = [' ','type','name','number']
1965            if generalData['Type'] == 'macromolecular':
1966                styleChoice = [' ','type','name','number','residue','1-letter','chain']
1967            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom label style',styleChoice)
1968            if dlg.ShowModal() == wx.ID_OK:
1969                sel = dlg.GetSelection()
1970                parms = styleChoice[sel]
1971                for r in indx:
1972                    atomData[r][cs+1] = parms
1973                    drawAtoms.SetCellValue(r,cs+1,parms)
1974            dlg.Destroy()
1975            drawAtoms.ClearSelection()
1976            G2plt.PlotStructure(G2frame,data)
1977           
1978    def DrawAtomColor(event):
1979
1980        indx = drawAtoms.GetSelectedRows()
1981        if indx:
1982            if len(indx) > 1:
1983                G2frame.dataFrame.SetStatusText('Select Custom Color, change color, Add to Custom Colors, then OK')
1984            else:
1985                G2frame.dataFrame.SetStatusText('Change color, Add to Custom Colors, then OK')
1986            generalData = data['General']
1987            atomData = data['Drawing']['Atoms']
1988            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1989            atmColors = []
1990            atmTypes = []
1991            for r in indx:
1992                if atomData[r][cs+2] not in atmColors:
1993                    atmColors.append(atomData[r][cs+2])
1994                    atmTypes.append(atomData[r][ct])
1995                    if len(atmColors) > 16:
1996                        break
1997            colors = wx.ColourData()
1998            colors.SetChooseFull(True)
1999            dlg = wx.ColourDialog(G2frame)
2000            if dlg.ShowModal() == wx.ID_OK:
2001                for i in range(len(atmColors)):                   
2002                    atmColors[i] = dlg.GetColourData().GetColour()
2003                colorDict = dict(zip(atmTypes,atmColors))
2004                for r in indx:
2005                    color = colorDict[atomData[r][ct]]
2006                    atomData[r][cs+2] = color
2007                    attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
2008                    attr.SetBackgroundColour(color)
2009                    drawAtoms.SetAttr(r,cs+2,attr)
2010                    data['Drawing']['Atoms'][r][cs+2] = color
2011            drawAtoms.ClearSelection()
2012            dlg.Destroy()
2013            G2frame.dataFrame.SetStatusText('')
2014            G2plt.PlotStructure(G2frame,data)
2015           
2016    def ResetAtomColors(event):
2017        generalData = data['General']
2018        atomData = data['Drawing']['Atoms']
2019        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2020        for atom in atomData:           
2021            atNum = generalData['AtomTypes'].index(atom[ct])
2022            atom[cs+2] = list(generalData['Color'][atNum])
2023        UpdateDrawAtoms()
2024        drawAtoms.ClearSelection()
2025        G2plt.PlotStructure(G2frame,data)       
2026       
2027    def SetViewPoint(event):
2028        indx = drawAtoms.GetSelectedRows()
2029        if indx:
2030            atomData = data['Drawing']['Atoms']
2031            cx = data['Drawing']['atomPtrs'][0]
2032            data['Drawing']['viewPoint'] = [atomData[indx[0]][cx:cx+3],[indx[0],0]]
2033            drawAtoms.ClearSelection()                                  #do I really want to do this?
2034            G2plt.PlotStructure(G2frame,data)
2035           
2036    def noDuplicate(xyz,atomData):                  #be careful where this is used - it's slow
2037        cx = data['Drawing']['atomPtrs'][0]
2038        if True in [np.allclose(np.array(xyz),np.array(atom[cx:cx+3]),atol=0.0002) for atom in atomData]:
2039            return False
2040        else:
2041            return True
2042               
2043    def AddSymEquiv(event):
2044        indx = drawAtoms.GetSelectedRows()
2045        indx.sort()
2046        if indx:
2047            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2048            cx = colLabels.index('x')
2049            cuia = colLabels.index('I/A')
2050            cuij = cuia+2
2051            atomData = data['Drawing']['Atoms']
2052            generalData = data['General']
2053            SGData = generalData['SGData']
2054            dlg = G2gd.SymOpDialog(G2frame,SGData,False,True)
2055            try:
2056                if dlg.ShowModal() == wx.ID_OK:
2057                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2058                    Cell = np.array(Cell)
2059                    cent = SGData['SGCen'][Cent]
2060                    M,T = SGData['SGOps'][Opr]
2061                    for ind in indx:
2062                        XYZ = np.array(atomData[ind][cx:cx+3])
2063                        XYZ = np.inner(M,XYZ)+T
2064                        if Inv:
2065                            XYZ = -XYZ
2066                        XYZ = XYZ+cent+Cell
2067                        if Force:
2068                            XYZ = G2spc.MoveToUnitCell(XYZ)
2069                        if noDuplicate(XYZ,atomData):
2070                            atom = copy.copy(atomData[ind])
2071                            atom[cx:cx+3] = XYZ
2072                            atomOp = atom[cx+3]
2073                            newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2074                                str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))                           
2075                            atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2076                            if atom[cuia] == 'A':
2077                                Uij = atom[cuij:cuij+6]
2078                                U = G2spc.Uij2U(Uij)
2079                                U = np.inner(np.inner(M,U),M)
2080                                Uij = G2spc.U2Uij(U)
2081                                atom[cuij:cuij+6] = Uij
2082                            atomData.append(atom)
2083            finally:
2084                dlg.Destroy()
2085            UpdateDrawAtoms()
2086            drawAtoms.ClearSelection()
2087            G2plt.PlotStructure(G2frame,data)
2088           
2089    def TransformSymEquiv(event):
2090        indx = drawAtoms.GetSelectedRows()
2091        indx.sort()
2092        if indx:
2093            atomData = data['Drawing']['Atoms']
2094            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2095            cx = colLabels.index('x')
2096            cuia = colLabels.index('I/A')
2097            cuij = cuia+2
2098            atomData = data['Drawing']['Atoms']
2099            generalData = data['General']
2100            SGData = generalData['SGData']
2101            dlg = G2gd.SymOpDialog(G2frame,SGData,False,True)
2102            try:
2103                if dlg.ShowModal() == wx.ID_OK:
2104                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2105                    Cell = np.array(Cell)
2106                    cent = SGData['SGCen'][Cent]
2107                    M,T = SGData['SGOps'][Opr]
2108                    for ind in indx:
2109                        XYZ = np.array(atomData[ind][cx:cx+3])
2110                        XYZ = np.inner(M,XYZ)+T
2111                        if Inv:
2112                            XYZ = -XYZ
2113                        XYZ = XYZ+cent+Cell
2114                        if Force:
2115                            XYZ = G2spc.MoveToUnitCell(XYZ)
2116                        atom = atomData[ind]
2117                        atom[cx:cx+3] = XYZ
2118                        atomOp = atom[cx+3]
2119                        newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2120                            str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))
2121                        atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2122                        if atom[cuia] == 'A':
2123                            Uij = atom[cuij:cuij+6]
2124                            U = G2spc.Uij2U(Uij)
2125                            U = np.inner(np.inner(M,U),M)
2126                            Uij = G2spc.U2Uij(U)
2127                            atom[cuij:cuij+6] = Uij
2128                    data['Drawing']['Atoms'] = atomData
2129            finally:
2130                dlg.Destroy()
2131            UpdateDrawAtoms()
2132            drawAtoms.ClearSelection()
2133            G2plt.PlotStructure(G2frame,data)
2134           
2135    def FillCoordSphere(event):
2136        generalData = data['General']
2137        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2138        radii = generalData['BondRadii']
2139        atomTypes = generalData['AtomTypes']
2140        try:
2141            indH = atomTypes.index('H')
2142            radii[indH] = 0.5
2143        except:
2144            pass           
2145        indx = drawAtoms.GetSelectedRows()
2146        if indx:
2147            indx.sort()
2148            atomData = data['Drawing']['Atoms']
2149            numAtoms = len(atomData)
2150            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2151            generalData = data['General']
2152            SGData = generalData['SGData']
2153            cellArray = G2lat.CellBlock(1)
2154            wx.BeginBusyCursor()
2155            try:
2156                for ind in indx:
2157                    atomA = atomData[ind]
2158                    xyzA = np.array(atomA[cx:cx+3])
2159                    indA = atomTypes.index(atomA[ct])
2160                    for atomB in atomData[:numAtoms]:
2161                        indB = atomTypes.index(atomB[ct])
2162                        sumR = radii[indA]+radii[indB]
2163                        xyzB = np.array(atomB[cx:cx+3])
2164                        for xyz in cellArray+xyzB:
2165                            dist = np.sqrt(np.sum(np.inner(Amat,xyz-xyzA)**2))
2166                            if 0 < dist <= data['Drawing']['radiusFactor']*sumR:
2167                                if noDuplicate(xyz,atomData):
2168                                    oprB = atomB[cx+3]
2169                                    C = xyz-xyzB
2170                                    newOp = '1+'+str(int(round(C[0])))+','+str(int(round(C[1])))+','+str(int(round(C[2])))
2171                                    newAtom = atomB[:]
2172                                    newAtom[cx:cx+3] = xyz
2173                                    newAtom[cx+3] = G2spc.StringOpsProd(oprB,newOp,SGData)
2174                                    atomData.append(newAtom)
2175            finally:
2176                wx.EndBusyCursor()
2177            data['Drawing']['Atoms'] = atomData
2178            UpdateDrawAtoms()
2179            drawAtoms.ClearSelection()
2180            G2plt.PlotStructure(G2frame,data)
2181           
2182    def FillUnitCell(event):
2183        indx = drawAtoms.GetSelectedRows()
2184        indx.sort()
2185        if indx:
2186            atomData = data['Drawing']['Atoms']
2187            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2188            cx = colLabels.index('x')
2189            cuia = colLabels.index('I/A')
2190            cuij = cuia+2
2191            generalData = data['General']
2192            SGData = generalData['SGData']
2193            wx.BeginBusyCursor()
2194            try:
2195                for ind in indx:
2196                    atom = atomData[ind]
2197                    XYZ = np.array(atom[cx:cx+3])
2198                    if atom[cuia] == 'A':
2199                        Uij = atom[cuij:cuij+6]
2200                        result = G2spc.GenAtom(XYZ,SGData,False,Uij,False)
2201                        for item in result:
2202                            atom = copy.copy(atomData[ind])
2203                            atom[cx:cx+3] = item[0]
2204                            atom[cx+3] = str(item[2])+'+' \
2205                                +str(item[3][0])+','+str(item[3][1])+','+str(item[3][2])
2206                            atom[cuij:cuij+6] = item[1]
2207                            Opp = G2spc.Opposite(item[0])
2208                            for xyz in Opp:
2209                                if noDuplicate(xyz,atomData):
2210                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2211                                    cell = '1'+'+'+ \
2212                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2213                                    atom[cx:cx+3] = xyz
2214                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2215                                    atomData.append(atom[:])
2216                    else:
2217                        result = G2spc.GenAtom(XYZ,SGData,False,Move=False)
2218                        for item in result:
2219                            atom = copy.copy(atomData[ind])
2220                            atom[cx:cx+3] = item[0]
2221                            atom[cx+3] = str(item[1])+'+' \
2222                                +str(item[2][0])+','+str(item[2][1])+','+str(item[2][2])
2223                            Opp = G2spc.Opposite(item[0])
2224                            for xyz in Opp:
2225                                if noDuplicate(xyz,atomData):
2226                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2227                                    cell = '1'+'+'+ \
2228                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2229                                    atom[cx:cx+3] = xyz
2230                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2231                                    atomData.append(atom[:])               
2232                    data['Drawing']['Atoms'] = atomData
2233            finally:
2234                wx.EndBusyCursor()
2235            UpdateDrawAtoms()
2236            drawAtoms.ClearSelection()
2237            G2plt.PlotStructure(G2frame,data)
2238           
2239    def FindBondsToo():                         #works but slow for large structures - keep as reference
2240        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2241        atomData = data['Drawing']['Atoms']
2242        generalData = data['General']
2243        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2244        radii = generalData['BondRadii']
2245        atomTypes = generalData['AtomTypes']
2246        try:
2247            indH = atomTypes.index('H')
2248            radii[indH] = 0.5
2249        except:
2250            pass           
2251        for atom in atomData:
2252            atom[-1] = []
2253        Atoms = []
2254        for i,atom in enumerate(atomData):
2255            Atoms.append([i,np.array(atom[cx:cx+3]),atom[cs],radii[atomTypes.index(atom[ct])]])
2256        for atomA in Atoms:
2257            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2258                for atomB in Atoms:                   
2259                    Dx = atomB[1]-atomA[1]
2260                    DX = np.inner(Amat,Dx)
2261                    dist = np.sqrt(np.sum(DX**2))
2262                    sumR = atomA[3]+atomB[3]
2263                    if 0.5 < dist <= 0.85*sumR:
2264                        i = atomA[0]
2265                        if atomA[2] == 'polyhedra':
2266                            atomData[i][-1].append(DX)
2267                        elif atomB[1] != 'polyhedra':
2268                            j = atomB[0]
2269                            atomData[i][-1].append(Dx*atomA[3]/sumR)
2270                            atomData[j][-1].append(-Dx*atomB[3]/sumR)
2271                   
2272    def FindBondsDraw():                    #uses numpy & masks - very fast even for proteins!
2273        import numpy.ma as ma
2274        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2275        hydro = data['Drawing']['showHydrogen']
2276        atomData = data['Drawing']['Atoms']
2277        generalData = data['General']
2278        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2279        radii = generalData['BondRadii']
2280        atomTypes = generalData['AtomTypes']
2281        try:
2282            indH = atomTypes.index('H')
2283            radii[indH] = 0.5
2284        except:
2285            pass           
2286        for atom in atomData:
2287            atom[-2] = []               #clear out old bonds/polyhedra
2288            atom[-1] = []
2289        Indx = range(len(atomData))
2290        Atoms = []
2291        Styles = []
2292        Radii = []
2293        for atom in atomData:
2294            Atoms.append(np.array(atom[cx:cx+3]))
2295            Styles.append(atom[cs])
2296            try:
2297                if not hydro and atom[ct] == 'H':
2298                    Radii.append(0.0)
2299                else:
2300                    Radii.append(radii[atomTypes.index(atom[ct])])
2301            except ValueError:          #changed atom type!
2302                Radii.append(0.20)
2303        Atoms = np.array(Atoms)
2304        Radii = np.array(Radii)
2305        IASR = zip(Indx,Atoms,Styles,Radii)
2306        for atomA in IASR:
2307            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2308                Dx = Atoms-atomA[1]
2309                dist = ma.masked_less(np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0)),0.5) #gets rid of G2frame & disorder "bonds" < 0.5A
2310                sumR = atomA[3]+Radii
2311                IndB = ma.nonzero(ma.masked_greater(dist-data['Drawing']['radiusFactor']*sumR,0.))                 #get indices of bonded atoms
2312                i = atomA[0]
2313                for j in IndB[0]:
2314                    if Styles[i] == 'polyhedra':
2315                        atomData[i][-2].append(np.inner(Amat,Dx[j]))
2316                    elif Styles[j] != 'polyhedra' and j > i:
2317                        atomData[i][-2].append(Dx[j]*Radii[i]/sumR[j])
2318                        atomData[j][-2].append(-Dx[j]*Radii[j]/sumR[j])
2319                if Styles[i] == 'polyhedra':
2320                    Bonds = atomData[i][-2]
2321                    Faces = []
2322                    if len(Bonds) > 2:
2323                        FaceGen = G2lat.uniqueCombinations(Bonds,3)     #N.B. this is a generator
2324                        for face in FaceGen:
2325                            vol = nl.det(face)
2326                            if abs(vol) > 1. or len(Bonds) == 3:
2327                                if vol < 0.:
2328                                    face = [face[0],face[2],face[1]]
2329                                face = np.array(face)
2330                                if not np.array([np.array(nl.det(face-bond))+0.0001 < 0 for bond in Bonds]).any():
2331                                    norm = np.cross(face[1]-face[0],face[2]-face[0])
2332                                    norm /= np.sqrt(np.sum(norm**2))
2333                                    Faces.append([face,norm])
2334                        atomData[i][-1] = Faces
2335                       
2336    def DrawAtomsDelete(event):   
2337        indx = drawAtoms.GetSelectedRows()
2338        indx.sort()
2339        if indx:
2340            atomData = data['Drawing']['Atoms']
2341            indx.reverse()
2342            for ind in indx:
2343                del atomData[ind]
2344            UpdateDrawAtoms()
2345            drawAtoms.ClearSelection()
2346            G2plt.PlotStructure(G2frame,data)
2347        event.StopPropagation()
2348       
2349    def OnReloadDrawAtoms(event):
2350        data['Drawing']['Atoms'] = []
2351        UpdateDrawAtoms()
2352        drawAtoms.ClearSelection()
2353        G2plt.PlotStructure(G2frame,data)
2354        event.StopPropagation()
2355       
2356    def DrawAtomsDeleteByIDs(IDs):
2357        atomData = data['Drawing']['Atoms']
2358        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
2359        indx.reverse()
2360        for ind in indx:
2361            del atomData[ind]
2362           
2363    def ChangeDrawAtomsByIDs(colName,IDs,value):
2364        atomData = data['Drawing']['Atoms']
2365        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2366        if colName == 'Name':
2367            col = ct-1
2368        elif colName == 'Type':
2369            col = ct
2370        elif colName == 'I/A':
2371            col = cs
2372        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
2373        for ind in indx:
2374            atomData[ind][col] = value
2375               
2376    def OnDrawPlane(event):
2377        indx = drawAtoms.GetSelectedRows()
2378        if len(indx) < 4:
2379            print '**** ERROR - need 4+ atoms for plane calculation'
2380            return
2381        PlaneData = {}
2382        drawingData = data['Drawing']
2383        atomData = drawingData['Atoms']
2384        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2385        cx = colLabels.index('x')
2386        cn = colLabels.index('Name')
2387        xyz = []
2388        for i,atom in enumerate(atomData):
2389            if i in indx:
2390                xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
2391        generalData = data['General']
2392        PlaneData['Name'] = generalData['Name']
2393        PlaneData['Atoms'] = xyz
2394        PlaneData['Cell'] = generalData['Cell'][1:] #+ volume
2395        G2stMn.BestPlane(PlaneData)
2396       
2397    def OnDrawDistVP(event):
2398        # distance to view point
2399        indx = drawAtoms.GetSelectedRows()
2400        if not indx:
2401            print '***** ERROR - no atoms selected'
2402            return
2403        generalData = data['General']
2404        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
2405        drawingData = data['Drawing']
2406        viewPt = np.array(drawingData['viewPoint'][0])
2407        print ' Distance from view point at %.3f %.3f %.3f to:'%(viewPt[0],viewPt[1],viewPt[2])
2408        atomDData = drawingData['Atoms']
2409        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2410        cx = colLabels.index('x')
2411        cn = colLabels.index('Name')
2412        for i in indx:
2413            atom = atomDData[i]
2414            Dx = np.array(atom[cx:cx+3])-viewPt
2415            dist = np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0))
2416            print 'Atom: %8s (%12s) distance = %.3f'%(atom[cn],atom[cx+3],dist)
2417   
2418    def OnDrawDAT(event):
2419        #distance, angle, torsion
2420        indx = drawAtoms.GetSelectedRows()
2421        if len(indx) not in [2,3,4]:
2422            print '**** ERROR - wrong number of atoms for distance, angle or torsion calculation'
2423            return
2424        DATData = {}
2425        ocx,oct,ocs,cia = data['General']['AtomPtrs']
2426        drawingData = data['Drawing']
2427        atomData = data['Atoms']
2428        atomDData = drawingData['Atoms']
2429        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2430        cx = colLabels.index('x')
2431        cn = colLabels.index('Name')
2432        cid = colLabels.index('I/A')+8
2433        xyz = []
2434        Oxyz = []
2435        DATData['Natoms'] = len(indx)
2436        for i in indx:
2437            atom = atomDData[i]
2438            xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+4]) #also gets Sym Op
2439            id = G2mth.FindAtomIndexByIDs(atomData,[atom[cid],],False)[0]
2440            Oxyz.append([id,]+atomData[id][cx+1:cx+4])
2441        DATData['Datoms'] = xyz
2442        DATData['Oatoms'] = Oxyz
2443        generalData = data['General']
2444        DATData['Name'] = generalData['Name']
2445        DATData['SGData'] = generalData['SGData']
2446        DATData['Cell'] = generalData['Cell'][1:] #+ volume
2447        if 'pId' in data:
2448            DATData['pId'] = data['pId']
2449            DATData['covData'] = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
2450        G2stMn.DisAglTor(DATData)
2451               
2452################################################################################
2453#### Draw Options page
2454################################################################################
2455
2456    def UpdateDrawOptions():
2457        import copy
2458        import wx.lib.colourselect as wcs
2459        def SlopSizer():           
2460            def OnCameraPos(event):
2461                drawingData['cameraPos'] = cameraPos.GetValue()
2462                cameraPosTxt.SetLabel(' Camera Distance: '+'%.2f'%(drawingData['cameraPos']))
2463                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2464                G2plt.PlotStructure(G2frame,data)
2465
2466            def OnZclip(event):
2467                drawingData['Zclip'] = Zclip.GetValue()
2468                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2469                G2plt.PlotStructure(G2frame,data)
2470               
2471            def OnZstep(event):
2472                try:
2473                    step = float(Zstep.GetValue())
2474                    if not (0.01 <= step <= 1.0):
2475                        raise ValueError
2476                except ValueError:
2477                    step = drawingData['Zstep']
2478                drawingData['Zstep'] = step
2479                Zstep.SetValue('%.2fA'%(drawingData['Zstep']))
2480               
2481            def OnMoveZ(event):
2482                move = MoveZ.GetValue()*drawingData['Zstep']
2483                MoveZ.SetValue(0)
2484                VP = np.inner(Amat,np.array(drawingData['viewPoint'][0]))
2485                VD = np.inner(Amat,np.array(drawingData['viewDir']))
2486                VD /= np.sqrt(np.sum(VD**2))
2487                VP += move*VD
2488                VP = np.inner(Bmat,VP)
2489                drawingData['viewPoint'][0] = VP
2490                panel = drawOptions.GetChildren()
2491                names = [child.GetName() for child in panel]
2492                panel[names.index('viewPoint')].SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))               
2493                G2plt.PlotStructure(G2frame,data)
2494               
2495            def OnVdWScale(event):
2496                drawingData['vdwScale'] = vdwScale.GetValue()/100.
2497                vdwScaleTxt.SetLabel(' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2498                G2plt.PlotStructure(G2frame,data)
2499   
2500            def OnEllipseProb(event):
2501                drawingData['ellipseProb'] = ellipseProb.GetValue()
2502                ellipseProbTxt.SetLabel(' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2503                G2plt.PlotStructure(G2frame,data)
2504   
2505            def OnBallScale(event):
2506                drawingData['ballScale'] = ballScale.GetValue()/100.
2507                ballScaleTxt.SetLabel(' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2508                G2plt.PlotStructure(G2frame,data)
2509
2510            def OnBondRadius(event):
2511                drawingData['bondRadius'] = bondRadius.GetValue()/100.
2512                bondRadiusTxt.SetLabel(' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2513                G2plt.PlotStructure(G2frame,data)
2514               
2515            def OnContourLevel(event):
2516                drawingData['contourLevel'] = contourLevel.GetValue()/100.
2517                contourLevelTxt.SetLabel(' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2518                G2plt.PlotStructure(G2frame,data)
2519
2520            def OnMapSize(event):
2521                drawingData['mapSize'] = mapSize.GetValue()/10.
2522                mapSizeTxt.SetLabel(' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2523                G2plt.PlotStructure(G2frame,data)
2524
2525           
2526            slopSizer = wx.BoxSizer(wx.HORIZONTAL)
2527            slideSizer = wx.FlexGridSizer(7,2)
2528            slideSizer.AddGrowableCol(1,1)
2529   
2530            cameraPosTxt = wx.StaticText(drawOptions,-1,
2531                ' Camera Distance: '+'%.2f'%(drawingData['cameraPos']),name='cameraPos')
2532            G2frame.dataDisplay.cameraPosTxt = cameraPosTxt
2533            slideSizer.Add(cameraPosTxt,0,wx.ALIGN_CENTER_VERTICAL)
2534            cameraPos = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=drawingData['cameraPos'],name='cameraSlider')
2535            cameraPos.SetRange(10,500)
2536            cameraPos.Bind(wx.EVT_SLIDER, OnCameraPos)
2537            G2frame.dataDisplay.cameraSlider = cameraPos
2538            slideSizer.Add(cameraPos,1,wx.EXPAND|wx.RIGHT)
2539           
2540            ZclipTxt = wx.StaticText(drawOptions,-1,' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2541            slideSizer.Add(ZclipTxt,0,wx.ALIGN_CENTER_VERTICAL)
2542            Zclip = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=drawingData['Zclip'])
2543            Zclip.SetRange(1,99)
2544            Zclip.Bind(wx.EVT_SLIDER, OnZclip)
2545            slideSizer.Add(Zclip,1,wx.EXPAND|wx.RIGHT)
2546           
2547            ZstepSizer = wx.BoxSizer(wx.HORIZONTAL)
2548            ZstepSizer.Add(wx.StaticText(drawOptions,-1,' Z step:'),0,wx.ALIGN_CENTER_VERTICAL)
2549            Zstep = wx.TextCtrl(drawOptions,value='%.2f'%(drawingData['Zstep']),
2550                style=wx.TE_PROCESS_ENTER)
2551            Zstep.Bind(wx.EVT_TEXT_ENTER,OnZstep)
2552            Zstep.Bind(wx.EVT_KILL_FOCUS,OnZstep)
2553            ZstepSizer.Add(Zstep,0,wx.ALIGN_CENTER_VERTICAL)
2554            slideSizer.Add(ZstepSizer)
2555            MoveSizer = wx.BoxSizer(wx.HORIZONTAL)
2556            MoveSizer.Add(wx.StaticText(drawOptions,-1,'   Press to step:'),0,wx.ALIGN_CENTER_VERTICAL)
2557            MoveZ = wx.SpinButton(drawOptions,style=wx.SP_HORIZONTAL,size=wx.Size(100,20))
2558            MoveZ.SetValue(0)
2559            MoveZ.SetRange(-1,1)
2560            MoveZ.Bind(wx.EVT_SPIN, OnMoveZ)
2561            MoveSizer.Add(MoveZ)
2562            slideSizer.Add(MoveSizer,1,wx.EXPAND|wx.RIGHT)
2563           
2564            vdwScaleTxt = wx.StaticText(drawOptions,-1,' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2565            slideSizer.Add(vdwScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2566            vdwScale = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['vdwScale']))
2567            vdwScale.Bind(wx.EVT_SLIDER, OnVdWScale)
2568            slideSizer.Add(vdwScale,1,wx.EXPAND|wx.RIGHT)
2569   
2570            ellipseProbTxt = wx.StaticText(drawOptions,-1,' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2571            slideSizer.Add(ellipseProbTxt,0,wx.ALIGN_CENTER_VERTICAL)
2572            ellipseProb = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=drawingData['ellipseProb'])
2573            ellipseProb.SetRange(1,99)
2574            ellipseProb.Bind(wx.EVT_SLIDER, OnEllipseProb)
2575            slideSizer.Add(ellipseProb,1,wx.EXPAND|wx.RIGHT)
2576   
2577            ballScaleTxt = wx.StaticText(drawOptions,-1,' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2578            slideSizer.Add(ballScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2579            ballScale = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['ballScale']))
2580            ballScale.Bind(wx.EVT_SLIDER, OnBallScale)
2581            slideSizer.Add(ballScale,1,wx.EXPAND|wx.RIGHT)
2582   
2583            bondRadiusTxt = wx.StaticText(drawOptions,-1,' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2584            slideSizer.Add(bondRadiusTxt,0,wx.ALIGN_CENTER_VERTICAL)
2585            bondRadius = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['bondRadius']))
2586            bondRadius.SetRange(1,25)
2587            bondRadius.Bind(wx.EVT_SLIDER, OnBondRadius)
2588            slideSizer.Add(bondRadius,1,wx.EXPAND|wx.RIGHT)
2589           
2590            if generalData['Map']['rhoMax']:
2591                contourLevelTxt = wx.StaticText(drawOptions,-1,' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2592                slideSizer.Add(contourLevelTxt,0,wx.ALIGN_CENTER_VERTICAL)
2593                contourLevel = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['contourLevel']))
2594                contourLevel.SetRange(1,100)
2595                contourLevel.Bind(wx.EVT_SLIDER, OnContourLevel)
2596                slideSizer.Add(contourLevel,1,wx.EXPAND|wx.RIGHT)
2597                mapSizeTxt = wx.StaticText(drawOptions,-1,' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2598                slideSizer.Add(mapSizeTxt,0,wx.ALIGN_CENTER_VERTICAL)
2599                mapSize = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(10*drawingData['mapSize']))
2600                mapSize.SetRange(1,100)
2601                mapSize.Bind(wx.EVT_SLIDER, OnMapSize)
2602                slideSizer.Add(mapSize,1,wx.EXPAND|wx.RIGHT)
2603           
2604            slopSizer.Add(slideSizer,1,wx.EXPAND|wx.RIGHT)
2605            slopSizer.Add((10,5),0)
2606            slopSizer.SetMinSize(wx.Size(350,10))
2607            return slopSizer
2608           
2609        def ShowSizer():
2610           
2611            def OnBackColor(event):
2612                drawingData['backColor'] = event.GetValue()
2613                G2plt.PlotStructure(G2frame,data)
2614   
2615            def OnShowABC(event):
2616                drawingData['showABC'] = showABC.GetValue()
2617                G2plt.PlotStructure(G2frame,data)
2618   
2619            def OnShowUnitCell(event):
2620                drawingData['unitCellBox'] = unitCellBox.GetValue()
2621                G2plt.PlotStructure(G2frame,data)
2622   
2623            def OnShowHyd(event):
2624                drawingData['showHydrogen'] = showHydrogen.GetValue()
2625                FindBondsDraw()
2626                G2plt.PlotStructure(G2frame,data)
2627               
2628            def OnShowRB(event):
2629                drawingData['showRigidBodies'] = showRB.GetValue()
2630                FindBondsDraw()
2631                G2plt.PlotStructure(G2frame,data)
2632               
2633            def OnViewPoint(event):
2634                Obj = event.GetEventObject()
2635                viewPt = Obj.GetValue().split()
2636                try:
2637                    VP = [float(viewPt[i]) for i in range(3)]
2638                except (ValueError,IndexError):
2639                    VP = drawingData['viewPoint'][0]
2640                Obj.SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))
2641                drawingData['viewPoint'][0] = VP
2642                G2plt.PlotStructure(G2frame,data)
2643               
2644            def OnViewDir(event):
2645                Obj = event.GetEventObject()
2646                viewDir = Obj.GetValue().split()
2647                try:
2648                    Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2649                    VD = np.array([float(viewDir[i]) for i in range(3)])
2650                    VC = np.inner(Amat,VD)
2651                    VC /= np.sqrt(np.sum(VC**2))
2652                    V = np.array(drawingData['viewDir'])
2653                    VB = np.inner(Amat,V)
2654                    VB /= np.sqrt(np.sum(VB**2))
2655                    VX = np.cross(VC,VB)
2656                    A = acosd(max((2.-np.sum((VB-VC)**2))/2.,-1.))
2657                    QV = G2mth.AVdeg2Q(A,VX)
2658                    Q = drawingData['Quaternion']
2659                    drawingData['Quaternion'] = G2mth.prodQQ(Q,QV)
2660                except (ValueError,IndexError):
2661                    VD = drawingData['viewDir']
2662                Obj.SetValue('%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]))
2663                drawingData['viewDir'] = VD
2664                G2plt.PlotStructure(G2frame,data)
2665                               
2666            showSizer = wx.BoxSizer(wx.VERTICAL)           
2667            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2668            lineSizer.Add(wx.StaticText(drawOptions,-1,' Background color:'),0,wx.ALIGN_CENTER_VERTICAL)
2669            backColor = wcs.ColourSelect(drawOptions, -1,colour=drawingData['backColor'],size=wx.Size(25,25))
2670            backColor.Bind(wcs.EVT_COLOURSELECT, OnBackColor)
2671            lineSizer.Add(backColor,0,wx.ALIGN_CENTER_VERTICAL)
2672            lineSizer.Add(wx.StaticText(drawOptions,-1,' View Dir.:'),0,wx.ALIGN_CENTER_VERTICAL)
2673            VD = drawingData['viewDir']
2674            viewDir = wx.TextCtrl(drawOptions,value='%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]),
2675                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewDir')
2676            viewDir.Bind(wx.EVT_TEXT_ENTER,OnViewDir)
2677            viewDir.Bind(wx.EVT_KILL_FOCUS,OnViewDir)
2678            G2frame.dataDisplay.viewDir = viewDir
2679            lineSizer.Add(viewDir,0,wx.ALIGN_CENTER_VERTICAL)
2680            showSizer.Add(lineSizer)
2681            showSizer.Add((0,5),0)
2682           
2683            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2684            showABC = wx.CheckBox(drawOptions,-1,label=' Show view point?')
2685            showABC.Bind(wx.EVT_CHECKBOX, OnShowABC)
2686            showABC.SetValue(drawingData['showABC'])
2687            lineSizer.Add(showABC,0,wx.ALIGN_CENTER_VERTICAL)
2688            lineSizer.Add(wx.StaticText(drawOptions,-1,' View Point:'),0,wx.ALIGN_CENTER_VERTICAL)
2689            VP = drawingData['viewPoint'][0]
2690            viewPoint = wx.TextCtrl(drawOptions,value='%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]),
2691                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewPoint')
2692            G2frame.dataDisplay.viewPoint = viewPoint
2693            viewPoint.Bind(wx.EVT_TEXT_ENTER,OnViewPoint)
2694            viewPoint.Bind(wx.EVT_KILL_FOCUS,OnViewPoint)
2695            lineSizer.Add(viewPoint,0,wx.ALIGN_CENTER_VERTICAL)
2696            showSizer.Add(lineSizer)
2697            showSizer.Add((0,5),0)
2698           
2699            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
2700   
2701            unitCellBox = wx.CheckBox(drawOptions,-1,label=' Show unit cell?')
2702            unitCellBox.Bind(wx.EVT_CHECKBOX, OnShowUnitCell)
2703            unitCellBox.SetValue(drawingData['unitCellBox'])
2704            line2Sizer.Add(unitCellBox,0,wx.ALIGN_CENTER_VERTICAL)
2705   
2706            showHydrogen = wx.CheckBox(drawOptions,-1,label=' Show hydrogens?')
2707            showHydrogen.Bind(wx.EVT_CHECKBOX, OnShowHyd)
2708            showHydrogen.SetValue(drawingData['showHydrogen'])
2709            line2Sizer.Add(showHydrogen,0,wx.ALIGN_CENTER_VERTICAL)
2710           
2711            showRB = wx.CheckBox(drawOptions,-1,label=' Show rigid Bodies?')
2712            showRB.Bind(wx.EVT_CHECKBOX, OnShowRB)
2713            showRB.SetValue(drawingData['showRigidBodies'])
2714            line2Sizer.Add(showRB,0,wx.ALIGN_CENTER_VERTICAL)
2715           
2716            showSizer.Add(line2Sizer)
2717            return showSizer
2718           
2719        def RadSizer():
2720           
2721            def OnSizeHatoms(event):
2722                try:
2723                    value = max(0.1,min(1.2,float(sizeH.GetValue())))
2724                except ValueError:
2725                    value = 0.5
2726                drawingData['sizeH'] = value
2727                sizeH.SetValue("%.2f"%(value))
2728                G2plt.PlotStructure(G2frame,data)
2729               
2730            def OnRadFactor(event):
2731                try:
2732                    value = max(0.1,min(1.2,float(radFactor.GetValue())))
2733                except ValueError:
2734                    value = 0.85
2735                drawingData['radiusFactor'] = value
2736                radFactor.SetValue("%.2f"%(value))
2737                FindBondsDraw()
2738                G2plt.PlotStructure(G2frame,data)
2739           
2740            radSizer = wx.BoxSizer(wx.HORIZONTAL)
2741            radSizer.Add(wx.StaticText(drawOptions,-1,' Hydrogen radius, A:  '),0,wx.ALIGN_CENTER_VERTICAL)
2742            sizeH = wx.TextCtrl(drawOptions,-1,value='%.2f'%(drawingData['sizeH']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2743            sizeH.Bind(wx.EVT_TEXT_ENTER,OnSizeHatoms)
2744            sizeH.Bind(wx.EVT_KILL_FOCUS,OnSizeHatoms)
2745            radSizer.Add(sizeH,0,wx.ALIGN_CENTER_VERTICAL)
2746   
2747            radSizer.Add(wx.StaticText(drawOptions,-1,' Bond search factor:  '),0,wx.ALIGN_CENTER_VERTICAL)
2748            radFactor = wx.TextCtrl(drawOptions,value='%.2f'%(drawingData['radiusFactor']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2749            radFactor.Bind(wx.EVT_TEXT_ENTER,OnRadFactor)
2750            radFactor.Bind(wx.EVT_KILL_FOCUS,OnRadFactor)
2751            radSizer.Add(radFactor,0,wx.ALIGN_CENTER_VERTICAL)
2752            return radSizer
2753
2754        # UpdateDrawOptions exectable code starts here
2755        generalData = data['General']
2756        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2757        SetupDrawingData()
2758        drawingData = data['Drawing']
2759        if generalData['Type'] == 'nuclear':
2760            pickChoice = ['Atoms','Bonds','Torsions','Planes']
2761        elif generalData['Type'] == 'macromolecular':
2762            pickChoice = ['Atoms','Residues','Chains','Bonds','Torsions','Planes','phi/psi']
2763
2764        G2frame.dataFrame.SetStatusText('')
2765        if drawOptions.GetSizer():
2766            drawOptions.GetSizer().Clear(True)
2767        mainSizer = wx.BoxSizer(wx.VERTICAL)
2768        mainSizer.Add((5,5),0)
2769        mainSizer.Add(wx.StaticText(drawOptions,-1,' Drawing controls:'),0,wx.ALIGN_CENTER_VERTICAL)
2770        mainSizer.Add((5,5),0)       
2771        mainSizer.Add(SlopSizer(),0)
2772        mainSizer.Add((5,5),0)
2773        mainSizer.Add(ShowSizer(),0,)
2774        mainSizer.Add((5,5),0)
2775        mainSizer.Add(RadSizer(),0,)
2776
2777        drawOptions.SetSizer(mainSizer)
2778        #if G2frame.dataFrame.PhaseUserSize is None:
2779        if True: # Bob wants this tab to always resize -- let's try that.
2780            Size = mainSizer.Fit(G2frame.dataFrame)
2781  #          Size[0] = max(Size[0]+35,400)           # leave some extra room and don't get too small
2782            Size[0] += 35                           #compensate for scroll bar
2783            Size[1] = max(Size[1]+35,350)                           #compensate for status bar
2784            drawOptions.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
2785            G2frame.dataFrame.setSizePosLeft(Size)
2786        else:
2787            Size = G2frame.dataFrame.PhaseUserSize
2788            drawOptions.SetSize(G2frame.dataFrame.GetClientSize())
2789            Size = mainSizer.ComputeFittingWindowSize(G2frame.dataFrame)
2790            drawOptions.SetVirtualSize(Size)
2791            drawOptions.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
2792            G2frame.dataFrame.Update()
2793        drawOptions.SetSize(G2frame.dataFrame.GetClientSize())
2794
2795################################################################################
2796####  Texture routines
2797################################################################################
2798       
2799    def UpdateTexture():       
2800        def SetSHCoef():
2801            cofNames = G2lat.GenSHCoeff(SGData['SGLaue'],SamSym[textureData['Model']],textureData['Order'])
2802            newSHCoef = dict(zip(cofNames,np.zeros(len(cofNames))))
2803            SHCoeff = textureData['SH Coeff'][1]
2804            for cofName in SHCoeff:
2805                if cofName in  cofNames:
2806                    newSHCoef[cofName] = SHCoeff[cofName]
2807            return newSHCoef
2808       
2809        def OnShOrder(event):
2810            Obj = event.GetEventObject()
2811            textureData['Order'] = int(Obj.GetValue())
2812            textureData['SH Coeff'][1] = SetSHCoef()
2813            wx.CallAfter(UpdateTexture)
2814            G2plt.PlotTexture(G2frame,data)
2815                       
2816        def OnShModel(event):
2817            Obj = event.GetEventObject()
2818            textureData['Model'] = Obj.GetValue()
2819            textureData['SH Coeff'][1] = SetSHCoef()
2820            wx.CallAfter(UpdateTexture)
2821            G2plt.PlotTexture(G2frame,data)
2822           
2823        def OnSHRefine(event):
2824            Obj = event.GetEventObject()
2825            textureData['SH Coeff'][0] = Obj.GetValue()
2826           
2827        def OnSHShow(event):
2828            Obj = event.GetEventObject()
2829            textureData['SHShow'] = Obj.GetValue()
2830            wx.CallAfter(UpdateTexture)
2831           
2832        def OnProjSel(event):
2833            Obj = event.GetEventObject()
2834            G2frame.Projection = Obj.GetValue()
2835            G2plt.PlotTexture(G2frame,data)
2836           
2837        def OnColorSel(event):
2838            Obj = event.GetEventObject()
2839            G2frame.ContourColor = Obj.GetValue()
2840            G2plt.PlotTexture(G2frame,data)
2841           
2842        def OnAngRef(event):
2843            Obj = event.GetEventObject()
2844            textureData[angIndx[Obj.GetId()]][0] = Obj.GetValue()
2845           
2846        def OnAngValue(event):
2847            Obj = event.GetEventObject()
2848            try:
2849                value =  float(Obj.GetValue())
2850            except ValueError:
2851                value = textureData[valIndx[Obj.GetId()]][1]
2852            Obj.SetValue('%8.2f'%(value))
2853            textureData[valIndx[Obj.GetId()]][1] = value
2854           
2855        def OnODFValue(event): 
2856            Obj = event.GetEventObject()
2857            try:
2858                value =  float(Obj.GetValue())
2859            except ValueError:
2860                value = textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]]
2861            Obj.SetValue('%8.3f'%(value))
2862            textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]] = value
2863            G2plt.PlotTexture(G2frame,data)
2864           
2865        def OnPfType(event):
2866            Obj = event.GetEventObject()
2867            textureData['PlotType'] = Obj.GetValue()
2868            wx.CallAfter(UpdateTexture)
2869            G2plt.PlotTexture(G2frame,data)
2870           
2871        def OnPFValue(event):
2872            Obj = event.GetEventObject()
2873            Saxis = Obj.GetValue().split()
2874            if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:               
2875                try:
2876                    hkl = [int(Saxis[i]) for i in range(3)]
2877                except (ValueError,IndexError):
2878                    hkl = textureData['PFhkl']
2879                if not np.any(np.array(hkl)):       #can't be all zeros!
2880                    hkl = textureData['PFhkl']
2881                Obj.SetValue('%d %d %d'%(hkl[0],hkl[1],hkl[2]))
2882                textureData['PFhkl'] = hkl
2883            else:
2884                try:
2885                    xyz = [float(Saxis[i]) for i in range(3)]
2886                except (ValueError,IndexError):
2887                    xyz = textureData['PFxyz']
2888                if not np.any(np.array(xyz)):       #can't be all zeros!
2889                    xyz = textureData['PFxyz']
2890                Obj.SetValue('%3.1f %3.1f %3.1f'%(xyz[0],xyz[1],xyz[2]))
2891                textureData['PFxyz'] = xyz
2892            G2plt.PlotTexture(G2frame,data)
2893
2894        # UpdateTexture executable starts here
2895        G2frame.dataFrame.SetStatusText('')
2896        generalData = data['General']       
2897        SGData = generalData['SGData']
2898        try:
2899            textureData = generalData['SH Texture']
2900        except KeyError:            #fix old files!
2901            textureData = generalData['SH Texture'] = {'Order':0,'Model':'cylindrical',
2902                'Sample omega':[False,0.0],'Sample chi':[False,0.0],'Sample phi':[False,0.0],
2903                'SH Coeff':[False,{}],'SHShow':False,'PFhkl':[0,0,1],
2904                'PFxyz':[0,0,1.],'PlotType':'Pole figure'}
2905        if 'SHShow' not in textureData:     #another fix
2906            textureData.update({'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2907        try:                        #another fix!
2908            x = textureData['PlotType']
2909        except KeyError:
2910            textureData.update({'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2911        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
2912        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
2913        if generalData['doPawley'] and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequental results'):
2914            G2frame.dataFrame.RefineTexture.Enable(True)
2915        shAngles = ['omega','chi','phi']
2916        if Texture.GetSizer():
2917            Texture.GetSizer().Clear(True)
2918        mainSizer = wx.BoxSizer(wx.VERTICAL)
2919        titleSizer = wx.BoxSizer(wx.HORIZONTAL)
2920        titleSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonics texture data for '+PhaseName+':'),0,wx.ALIGN_CENTER_VERTICAL)
2921        titleSizer.Add(wx.StaticText(Texture,-1,
2922            ' Texture Index J = %7.3f'%(G2lat.textureIndex(textureData['SH Coeff'][1]))),
2923            0,wx.ALIGN_CENTER_VERTICAL)
2924        mainSizer.Add(titleSizer,0)
2925        mainSizer.Add((0,5),0)
2926        shSizer = wx.FlexGridSizer(1,6,5,5)
2927        shSizer.Add(wx.StaticText(Texture,-1,'Texture model: '),0,wx.ALIGN_CENTER_VERTICAL)
2928        shModel = wx.ComboBox(Texture,-1,value=textureData['Model'],choices=shModels,
2929            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2930        shModel.Bind(wx.EVT_COMBOBOX,OnShModel)
2931        shSizer.Add(shModel,0,wx.ALIGN_CENTER_VERTICAL)
2932        shSizer.Add(wx.StaticText(Texture,-1,'  Harmonic order: '),0,wx.ALIGN_CENTER_VERTICAL)
2933        shOrder = wx.ComboBox(Texture,-1,value=str(textureData['Order']),choices=[str(2*i) for i in range(18)],
2934            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2935        shOrder.Bind(wx.EVT_COMBOBOX,OnShOrder)
2936        shSizer.Add(shOrder,0,wx.ALIGN_CENTER_VERTICAL)
2937        shRef = wx.CheckBox(Texture,-1,label=' Refine texture?')
2938        shRef.SetValue(textureData['SH Coeff'][0])
2939        shRef.Bind(wx.EVT_CHECKBOX, OnSHRefine)
2940        shSizer.Add(shRef,0,wx.ALIGN_CENTER_VERTICAL)
2941        shShow = wx.CheckBox(Texture,-1,label=' Show coeff.?')
2942        shShow.SetValue(textureData['SHShow'])
2943        shShow.Bind(wx.EVT_CHECKBOX, OnSHShow)
2944        shSizer.Add(shShow,0,wx.ALIGN_CENTER_VERTICAL)
2945        mainSizer.Add(shSizer,0,0)
2946        mainSizer.Add((0,5),0)
2947        PTSizer = wx.FlexGridSizer(2,4,5,5)
2948        PTSizer.Add(wx.StaticText(Texture,-1,' Texture plot type: '),0,wx.ALIGN_CENTER_VERTICAL)
2949        choices = ['Axial pole distribution','Pole figure','Inverse pole figure']           
2950        pfType = wx.ComboBox(Texture,-1,value=str(textureData['PlotType']),choices=choices,
2951            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2952        pfType.Bind(wx.EVT_COMBOBOX,OnPfType)
2953        PTSizer.Add(pfType,0,wx.ALIGN_CENTER_VERTICAL)
2954        if 'Axial' not in textureData['PlotType']:
2955            PTSizer.Add(wx.StaticText(Texture,-1,' Projection type: '),0,wx.ALIGN_CENTER_VERTICAL)
2956            projSel = wx.ComboBox(Texture,-1,value=G2frame.Projection,choices=['equal area','stereographic','3D display'],
2957                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2958            projSel.Bind(wx.EVT_COMBOBOX,OnProjSel)
2959            PTSizer.Add(projSel,0,wx.ALIGN_CENTER_VERTICAL)
2960        if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:
2961            PTSizer.Add(wx.StaticText(Texture,-1,' Pole figure HKL: '),0,wx.ALIGN_CENTER_VERTICAL)
2962            PH = textureData['PFhkl']
2963            pfVal = wx.TextCtrl(Texture,-1,'%d %d %d'%(PH[0],PH[1],PH[2]),style=wx.TE_PROCESS_ENTER)
2964        else:
2965            PTSizer.Add(wx.StaticText(Texture,-1,' Inverse pole figure XYZ: '),0,wx.ALIGN_CENTER_VERTICAL)
2966            PX = textureData['PFxyz']
2967            pfVal = wx.TextCtrl(Texture,-1,'%3.1f %3.1f %3.1f'%(PX[0],PX[1],PX[2]),style=wx.TE_PROCESS_ENTER)
2968        pfVal.Bind(wx.EVT_TEXT_ENTER,OnPFValue)
2969        pfVal.Bind(wx.EVT_KILL_FOCUS,OnPFValue)
2970        PTSizer.Add(pfVal,0,wx.ALIGN_CENTER_VERTICAL)
2971        if 'Axial' not in textureData['PlotType']:
2972            PTSizer.Add(wx.StaticText(Texture,-1,' Color scheme'),0,wx.ALIGN_CENTER_VERTICAL)
2973            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
2974            choice.sort()
2975            colorSel = wx.ComboBox(Texture,-1,value=G2frame.ContourColor,choices=choice,
2976                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2977            colorSel.Bind(wx.EVT_COMBOBOX,OnColorSel)
2978            PTSizer.Add(colorSel,0,wx.ALIGN_CENTER_VERTICAL)       
2979        mainSizer.Add(PTSizer,0,wx.ALIGN_CENTER_VERTICAL)
2980        mainSizer.Add((0,5),0)
2981        if textureData['SHShow']:
2982            mainSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonic coefficients: '),0,wx.ALIGN_CENTER_VERTICAL)
2983            mainSizer.Add((0,5),0)
2984            ODFSizer = wx.FlexGridSizer(2,8,2,2)
2985            ODFIndx = {}
2986            ODFkeys = textureData['SH Coeff'][1].keys()
2987            ODFkeys.sort()
2988            for item in ODFkeys:
2989                ODFSizer.Add(wx.StaticText(Texture,-1,item),0,wx.ALIGN_CENTER_VERTICAL)
2990                ODFval = wx.TextCtrl(Texture,wx.ID_ANY,'%8.3f'%(textureData['SH Coeff'][1][item]),style=wx.TE_PROCESS_ENTER)
2991                ODFIndx[ODFval.GetId()] = item
2992                ODFval.Bind(wx.EVT_TEXT_ENTER,OnODFValue)
2993                ODFval.Bind(wx.EVT_KILL_FOCUS,OnODFValue)
2994                ODFSizer.Add(ODFval,0,wx.ALIGN_CENTER_VERTICAL)
2995            mainSizer.Add(ODFSizer,0,wx.ALIGN_CENTER_VERTICAL)
2996            mainSizer.Add((0,5),0)
2997        mainSizer.Add((0,5),0)
2998        mainSizer.Add(wx.StaticText(Texture,-1,'Sample orientation angles: '),0,wx.ALIGN_CENTER_VERTICAL)
2999        mainSizer.Add((0,5),0)
3000        angSizer = wx.BoxSizer(wx.HORIZONTAL)
3001        angIndx = {}
3002        valIndx = {}
3003        for item in ['Sample omega','Sample chi','Sample phi']:
3004            angRef = wx.CheckBox(Texture,-1,label=item+': ')
3005            angRef.SetValue(textureData[item][0])
3006            angIndx[angRef.GetId()] = item
3007            angRef.Bind(wx.EVT_CHECKBOX, OnAngRef)
3008            angSizer.Add(angRef,0,wx.ALIGN_CENTER_VERTICAL)
3009            angVal = wx.TextCtrl(Texture,wx.ID_ANY,'%8.2f'%(textureData[item][1]),style=wx.TE_PROCESS_ENTER)
3010            valIndx[angVal.GetId()] = item
3011            angVal.Bind(wx.EVT_TEXT_ENTER,OnAngValue)
3012            angVal.Bind(wx.EVT_KILL_FOCUS,OnAngValue)
3013            angSizer.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
3014            angSizer.Add((5,0),0)
3015        mainSizer.Add(angSizer,0,wx.ALIGN_CENTER_VERTICAL)
3016        Texture.SetSizer(mainSizer,True)
3017        if G2frame.dataFrame.PhaseUserSize is None:
3018            mainSizer.Fit(G2frame.dataFrame)
3019            Size = mainSizer.GetMinSize()
3020            Size[0] += 40
3021            Size[1] = max(Size[1],250) + 35
3022            Texture.SetSize(Size)
3023            Texture.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3024            Size[1] = min(Size[1],450)
3025            G2frame.dataFrame.setSizePosLeft(Size)
3026        else:
3027            Size = G2frame.dataFrame.PhaseUserSize
3028            Texture.SetSize(G2frame.dataFrame.GetClientSize())
3029            Texture.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3030            G2frame.dataFrame.Update()
3031################################################################################
3032##### DData routines - GUI stuff in GSASIIddataGUI.py
3033################################################################################
3034       
3035    def OnHklfAdd(event):
3036        UseList = data['Histograms']
3037        keyList = UseList.keys()
3038        TextList = []
3039        if G2frame.PatternTree.GetCount():
3040            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3041            while item:
3042                name = G2frame.PatternTree.GetItemText(item)
3043                if name not in keyList and 'HKLF' in name:
3044                    TextList.append(name)
3045                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                       
3046            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3047            try:
3048                if dlg.ShowModal() == wx.ID_OK:
3049                    result = dlg.GetSelections()
3050                    for i in result:
3051                        histoName = TextList[i]
3052                        UseList[histoName] = {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
3053                            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
3054                            'Extinction':['Lorentzian','None',
3055                            {'Tbar':0.1,'Cos2TM':0.955,'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]},]}                       
3056                        wx.BeginBusyCursor()
3057                        UpdateHKLFdata(histoName)
3058                        wx.EndBusyCursor()
3059                    data['Histograms'] = UseList
3060                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3061            finally:
3062                dlg.Destroy()
3063               
3064    def UpdateHKLFdata(histoName):
3065        generalData = data['General']
3066        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3067        reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
3068        SGData = generalData['SGData']
3069        Cell = generalData['Cell'][1:7]
3070        G,g = G2lat.cell2Gmat(Cell)
3071        for ref in reflData:
3072            H = ref[:3]
3073            ref[4] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
3074            iabsnt,ref[3],ref[11],ref[12] = G2spc.GenHKLf(H,SGData)
3075        G2frame.PatternTree.SetItemPyData(Id,[histoName,reflData])
3076       
3077    def OnPwdrAdd(event):
3078        generalData = data['General']
3079        SGData = generalData['SGData']
3080        UseList = data['Histograms']
3081        newList = []
3082        NShkl = len(G2spc.MustrainNames(SGData))
3083        NDij = len(G2spc.HStrainNames(SGData))
3084        keyList = UseList.keys()
3085        TextList = ['All PWDR']
3086        if G2frame.PatternTree.GetCount():
3087            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3088            while item:
3089                name = G2frame.PatternTree.GetItemText(item)
3090                if name not in keyList and 'PWDR' in name:
3091                    TextList.append(name)
3092                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3093            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3094            try:
3095                if dlg.ShowModal() == wx.ID_OK:
3096                    result = dlg.GetSelections()
3097                    for i in result: newList.append(TextList[i])
3098                    if 'All PWDR' in newList:
3099                        newList = TextList[1:]
3100                    for histoName in newList:
3101                        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3102                        UseList[histoName] = {'Histogram':histoName,'Show':False,
3103                            'Scale':[1.0,False],'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{}],
3104                            'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
3105                                [1.,1.,1.,0.,0.,0.],6*[False,]],
3106                            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
3107                                NShkl*[0.01,],NShkl*[False,]],
3108                            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
3109                            'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
3110                        refList = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,pId,'Reflection Lists'))
3111                        refList[generalData['Name']] = []                       
3112                    data['Histograms'] = UseList
3113                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3114            finally:
3115                dlg.Destroy()
3116       
3117    def OnDataDelete(event):
3118        UseList = data['Histograms']
3119        keyList = ['All',]+UseList.keys()
3120        keyList.sort()
3121        DelList = []
3122        if UseList:
3123            DelList = []
3124            dlg = wx.MultiChoiceDialog(G2frame, 
3125                'Which histogram to delete from this phase?', 'Delete histogram', 
3126                keyList, wx.CHOICEDLG_STYLE)
3127            try:
3128                if dlg.ShowModal() == wx.ID_OK:
3129                    result = dlg.GetSelections()
3130                    for i in result: 
3131                        DelList.append(keyList[i])
3132                    if 'All' in DelList:
3133                        DelList = keyList[1:]
3134                    for i in DelList:
3135                        del UseList[i]
3136                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3137            finally:
3138                dlg.Destroy()
3139               
3140################################################################################
3141##### Rigid bodies
3142################################################################################
3143
3144    def FillRigidBodyGrid(refresh=True):
3145        '''Fill the Rigid Body Phase information tab page.
3146        Note that the page is a ScrolledWindow, not a Grid
3147        '''
3148        def OnThermSel(event):       #needs to be seen by VecRbSizer!
3149            Obj = event.GetEventObject()
3150            RBObj = Indx[Obj.GetId()]
3151            val = Obj.GetValue()
3152            if val == 'Uiso':
3153                RBObj['ThermalMotion'][0] = 'Uiso'
3154            elif val == 'T':
3155                RBObj['ThermalMotion'][0] = 'T'
3156            elif val == 'TL':
3157                RBObj['ThermalMotion'][0] = 'TL'
3158            elif val == 'TLS':
3159                RBObj['ThermalMotion'][0] = 'TLS'
3160            wx.CallAfter(FillRigidBodyGrid,True)
3161           
3162        def ThermDataSizer(RBObj):
3163           
3164            def OnThermval(event):
3165                Obj = event.GetEventObject()
3166                item = Indx[Obj.GetId()]
3167                try:
3168                    val = float(Obj.GetValue())
3169                    RBObj['ThermalMotion'][1][item] = val
3170                except ValueError:
3171                    pass
3172                Obj.SetValue('%8.4f'%(RBObj['ThermalMotion'][1][item]))
3173                G2plt.PlotStructure(G2frame,data)
3174               
3175            def OnTLSRef(event):
3176                Obj = event.GetEventObject()
3177                item = Indx[Obj.GetId()]
3178                RBObj['ThermalMotion'][2][item] = Obj.GetValue()
3179           
3180            thermSizer = wx.FlexGridSizer(1,9,5,5)
3181            model = RBObj['ThermalMotion']
3182            if model[0] == 'Uiso':
3183                names = ['Uiso',]
3184            elif 'T' in model[0]:
3185                names = ['T11','T22','T33','T12','T13','T23']
3186            if 'L' in model[0]:
3187                names += ['L11','L22','L33','L12','L13','L23']
3188            if 'S' in model[0]:
3189                names += ['S12','S13','S21','S23','S31','S32','SAA','SBB']
3190            for i,name in enumerate(names):
3191                thermSizer.Add(wx.StaticText(RigidBodies,-1,name+': '),0,wx.ALIGN_CENTER_VERTICAL)
3192                thermVal = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(model[1][i]),
3193                    style=wx.TE_PROCESS_ENTER)
3194                thermVal.Bind(wx.EVT_TEXT_ENTER,OnThermval)
3195                thermVal.Bind(wx.EVT_KILL_FOCUS,OnThermval)
3196                Indx[thermVal.GetId()] = i
3197                thermSizer.Add(thermVal)
3198                Tcheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3199                Tcheck.Bind(wx.EVT_CHECKBOX,OnTLSRef)
3200                Tcheck.SetValue(model[2][i])
3201                Indx[Tcheck.GetId()] = i
3202                thermSizer.Add(Tcheck,0,wx.ALIGN_CENTER_VERTICAL)
3203            return thermSizer
3204           
3205        def LocationSizer(RBObj,rbType):
3206           
3207            def OnOrigRef(event):
3208                RBObj['Orig'][1] = Ocheck.GetValue()
3209             
3210            def OnOrienRef(event):
3211                RBObj['Orient'][1] = Qcheck.GetValue()
3212               
3213            def OnOrigX(event):
3214                Obj = event.GetEventObject()
3215                item = Indx[Obj.GetId()]
3216                try:
3217                    val = float(Obj.GetValue())
3218                    RBObj['Orig'][0][item] = val
3219                    Obj.SetValue('%8.5f'%(val))
3220                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3221                    for i,id in enumerate(RBObj['Ids']):
3222                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3223                    data['Drawing']['Atoms'] = []
3224                    UpdateDrawAtoms(atomStyle)
3225                    G2plt.PlotStructure(G2frame,data)
3226                except ValueError:
3227                    pass
3228               
3229            def OnOrien(event):
3230                Obj = event.GetEventObject()
3231                item = Indx[Obj.GetId()]
3232                A,V = G2mth.Q2AVdeg(RBObj['Orient'][0])
3233                V = np.inner(Bmat,V)
3234                try:
3235                    val = float(Obj.GetValue())
3236                    if item:
3237                        V[item-1] = val
3238                    else:
3239                        A = val
3240                    Obj.SetValue('%8.5f'%(val))
3241                    V = np.inner(Amat,V)
3242                    Q = G2mth.AVdeg2Q(A,V)
3243                    if not any(Q):
3244                        raise ValueError
3245                    RBObj['Orient'][0] = Q
3246                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3247                    for i,id in enumerate(RBObj['Ids']):
3248                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3249                    data['Drawing']['Atoms'] = []
3250                    UpdateDrawAtoms(atomStyle)
3251                    G2plt.PlotStructure(G2frame,data)
3252                except ValueError:
3253                    pass
3254               
3255            topSizer = wx.FlexGridSizer(2,6,5,5)
3256            Orig = RBObj['Orig'][0]
3257            Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0])
3258            Orien = [Orien,]
3259            Orien.extend(OrienV/nl.norm(OrienV))
3260            topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,wx.ALIGN_CENTER_VERTICAL)
3261            for ix,x in enumerate(Orig):
3262                origX = wx.TextCtrl(RigidBodies,-1,value='%8.5f'%(x),style=wx.TE_PROCESS_ENTER)
3263                origX.Bind(wx.EVT_TEXT_ENTER,OnOrigX)
3264                origX.Bind(wx.EVT_KILL_FOCUS,OnOrigX)
3265                Indx[origX.GetId()] = ix
3266                topSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3267            topSizer.Add((5,0),)
3268            Ocheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3269            Ocheck.Bind(wx.EVT_CHECKBOX,OnOrigRef)
3270            Ocheck.SetValue(RBObj['Orig'][1])
3271            topSizer.Add(Ocheck,0,wx.ALIGN_CENTER_VERTICAL)
3272            topSizer.Add(wx.StaticText(RigidBodies,-1,'Rotation angle, vector:'),0,wx.ALIGN_CENTER_VERTICAL)
3273            for ix,x in enumerate(Orien):
3274                orien = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(x),style=wx.TE_PROCESS_ENTER)
3275                orien.Bind(wx.EVT_TEXT_ENTER,OnOrien)
3276                orien.Bind(wx.EVT_KILL_FOCUS,OnOrien)
3277                Indx[orien.GetId()] = ix
3278                topSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3279            Qcheck = wx.ComboBox(RigidBodies,-1,value='',choices=[' ','A','AV'],
3280                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3281            Qcheck.Bind(wx.EVT_COMBOBOX,OnOrienRef)
3282            Qcheck.SetValue(RBObj['Orient'][1])
3283            topSizer.Add(Qcheck)
3284            return topSizer
3285                         
3286        def ResrbSizer(RBObj):
3287            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3288             
3289            def OnTorsionRef(event):
3290                Obj = event.GetEventObject()
3291                item = Indx[Obj.GetId()]
3292                RBObj['Torsions'][item][1] = Obj.GetValue()               
3293               
3294            def OnTorsion(event):
3295                Obj = event.GetEventObject()
3296                item = Indx[Obj.GetId()]
3297                try:
3298                    val = float(Obj.GetValue())
3299                    RBObj['Torsions'][item][0] = val
3300                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3301                    for i,id in enumerate(RBObj['Ids']):
3302                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3303                except ValueError:
3304                    pass
3305                Obj.SetValue("%10.3f"%(RBObj['Torsions'][item][0]))               
3306                data['Drawing']['Atoms'] = []
3307                UpdateDrawAtoms(atomStyle)
3308                drawAtoms.ClearSelection()
3309                G2plt.PlotStructure(G2frame,data)
3310               
3311            def OnDelResRB(event):
3312                Obj = event.GetEventObject()
3313                RBId = Indx[Obj.GetId()]
3314                RBData['Residue'][RBId]['useCount'] -= 1
3315                RBObjs = data['RBModels']['Residue']
3316                for rbObj in RBObjs:
3317                    if RBId == rbObj['RBId']:
3318                       data['RBModels']['Residue'].remove(rbObj)                 
3319                G2plt.PlotStructure(G2frame,data)
3320                wx.CallAfter(FillRigidBodyGrid,True)
3321               
3322            resrbSizer = wx.BoxSizer(wx.VERTICAL)
3323            resrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3324            topLine = wx.BoxSizer(wx.HORIZONTAL)
3325            topLine.Add(wx.StaticText(RigidBodies,-1,
3326                'Name: '+RBObj['RBname']+RBObj['numChain']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3327            rbId = RBObj['RBId']
3328            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3329            delRB.Bind(wx.EVT_CHECKBOX,OnDelResRB)
3330            Indx[delRB.GetId()] = rbId
3331            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3332            resrbSizer.Add(topLine)
3333            resrbSizer.Add(LocationSizer(RBObj,'Residue'))
3334            resrbSizer.Add(wx.StaticText(RigidBodies,-1,'Torsions:'),0,wx.ALIGN_CENTER_VERTICAL)
3335            torSizer = wx.FlexGridSizer(1,6,5,5)
3336            for itors,tors in enumerate(RBObj['Torsions']):
3337                torSizer.Add(wx.StaticText(RigidBodies,-1,'Torsion '+'%d'%(itors)),0,wx.ALIGN_CENTER_VERTICAL)
3338                torsTxt = wx.TextCtrl(RigidBodies,-1,value='%.3f'%(tors[0]),style=wx.TE_PROCESS_ENTER)
3339                torsTxt.Bind(wx.EVT_TEXT_ENTER,OnTorsion)
3340                torsTxt.Bind(wx.EVT_KILL_FOCUS,OnTorsion)
3341                Indx[torsTxt.GetId()] = itors
3342                torSizer.Add(torsTxt)
3343                torCheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3344                torCheck.Bind(wx.EVT_CHECKBOX,OnTorsionRef)
3345                torCheck.SetValue(tors[1])
3346                Indx[torCheck.GetId()] = itors
3347                torSizer.Add(torCheck,0,wx.ALIGN_CENTER_VERTICAL)
3348            resrbSizer.Add(torSizer)
3349            tchoice = ['None','Uiso','T','TL','TLS']
3350            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3351            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3352            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3353                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3354            Indx[thermSel.GetId()] = RBObj
3355            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3356            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3357            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3358            resrbSizer.Add(thermSizer)
3359            if RBObj['ThermalMotion'][0] != 'None':
3360                resrbSizer.Add(ThermDataSizer(RBObj))
3361            return resrbSizer
3362           
3363        def VecrbSizer(RBObj):
3364            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3365                   
3366            def OnDelVecRB(event):
3367                Obj = event.GetEventObject()
3368                RBId = Indx[Obj.GetId()]
3369                RBData['Vector'][RBId]['useCount'] -= 1               
3370                RBObjs = data['RBModels']['Vector']
3371                for rbObj in RBObjs:
3372                    if RBId == rbObj['RBId']:
3373                       data['RBModels']['Vector'].remove(rbObj)                 
3374                G2plt.PlotStructure(G2frame,data)
3375                wx.CallAfter(FillRigidBodyGrid,True)
3376             
3377            vecrbSizer = wx.BoxSizer(wx.VERTICAL)
3378            vecrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3379            topLine = wx.BoxSizer(wx.HORIZONTAL)
3380            topLine.Add(wx.StaticText(RigidBodies,-1,
3381                'Name: '+RBObj['RBname']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3382            rbId = RBObj['RBId']
3383            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3384            delRB.Bind(wx.EVT_CHECKBOX,OnDelVecRB)
3385            Indx[delRB.GetId()] = rbId
3386            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3387            vecrbSizer.Add(topLine)
3388            vecrbSizer.Add(LocationSizer(RBObj,'Vector'))
3389            tchoice = ['None','Uiso','T','TL','TLS']
3390            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3391            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3392            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3393                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3394            Indx[thermSel.GetId()] = RBObj
3395            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3396            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3397            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3398            vecrbSizer.Add(thermSizer)
3399            if RBObj['ThermalMotion'][0] != 'None':
3400                vecrbSizer.Add(ThermDataSizer(RBObj))
3401            return vecrbSizer               
3402       
3403        # FillRigidBodyGrid executable code starts here
3404        if refresh:
3405            RigidBodies.DestroyChildren()
3406        AtLookUp = G2mth.FillAtomLookUp(data['Atoms'])
3407        general = data['General']
3408        cx = general['AtomPtrs'][0]
3409        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3410        RBData = G2frame.PatternTree.GetItemPyData(   
3411            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3412        Indx = {}
3413        atomStyle = 'balls & sticks'
3414        if 'macro' in general['Type']:
3415            atomStyle = 'sticks'
3416        G2frame.dataFrame.SetStatusText('')
3417        mainSizer = wx.BoxSizer(wx.VERTICAL)
3418        if not data['RBModels']:
3419            mainSizer.Add((5,5),0)
3420            mainSizer.Add(wx.StaticText(RigidBodies,-1,'No rigid body models:'),0,wx.ALIGN_CENTER_VERTICAL)
3421            mainSizer.Add((5,5),0)
3422        if 'Residue' in data['RBModels']:
3423            mainSizer.Add((5,5),0)
3424            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Residue rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3425            mainSizer.Add((5,5),0)
3426            for RBObj in data['RBModels']['Residue']:
3427                mainSizer.Add(ResrbSizer(RBObj))
3428        if 'Vector' in data['RBModels']:
3429            mainSizer.Add((5,5),0)
3430            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Vector rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3431            mainSizer.Add((5,5),0)
3432            for RBObj in data['RBModels']['Vector']:
3433                mainSizer.Add(VecrbSizer(RBObj))
3434
3435        RigidBodies.SetSizer(mainSizer)
3436        if G2frame.dataFrame.PhaseUserSize is None:
3437            mainSizer.FitInside(G2frame.dataFrame)
3438            Size = mainSizer.GetMinSize()
3439            Size[0] += 40
3440            Size[1] = max(Size[1],290) + 35
3441            RigidBodies.SetSize(Size)
3442            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3443            Size[1] = min(Size[1],450)
3444            G2frame.dataFrame.setSizePosLeft(Size)
3445        else:
3446            Size = G2frame.dataFrame.PhaseUserSize
3447            RigidBodies.SetSize(Size)
3448            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3449            G2frame.dataFrame.Update()
3450
3451    def OnRBCopyParms(event):
3452        RBObjs = []
3453        for rbType in ['Vector','Residue']:           
3454            RBObjs += data['RBModels'].get(rbType,[])
3455        if not len(RBObjs):
3456            print '**** ERROR - no rigid bodies defined ****'
3457            return
3458        if len(RBObjs) == 1:
3459            print '**** INFO - only one rigid body defined; nothing to copy to ****'
3460            return
3461        Source = []
3462        sourceRB = {}
3463        for RBObj in RBObjs:
3464            Source.append(RBObj['RBname'])
3465        dlg = wx.SingleChoiceDialog(G2frame,'Select source','Copy rigid body parameters',Source)
3466        if dlg.ShowModal() == wx.ID_OK:
3467            sel = dlg.GetSelection()
3468            name = Source[sel]
3469            for item in ['Orig','Orient','ThermalMotion']: 
3470                sourceRB.update({item:RBObjs[sel][item],})
3471        dlg.Destroy()
3472        if not sourceRB:
3473            return
3474        dlg = wx.MultiChoiceDialog(G2frame,'Select targets','Copy rigid body parameters',Source)
3475        if dlg.ShowModal() == wx.ID_OK:
3476            sel = dlg.GetSelections()
3477            for x in sel:
3478                RBObjs[x].update(copy.copy(sourceRB))
3479        G2plt.PlotStructure(G2frame,data)
3480        wx.CallAfter(FillRigidBodyGrid(True))
3481               
3482    def OnRBAssign(event):
3483       
3484        G2frame.dataFrame.SetStatusText('')
3485        RBData = G2frame.PatternTree.GetItemPyData(   
3486            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3487        rbNames = {}
3488        for rbVec in RBData['Vector']:
3489            if rbVec != 'AtInfo':
3490                rbNames[RBData['Vector'][rbVec]['RBname']] =['Vector',rbVec]
3491        for rbRes in RBData['Residue']:
3492            if rbRes != 'AtInfo':
3493                rbNames[RBData['Residue'][rbRes]['RBname']] = ['Residue',rbRes]
3494        if not rbNames:
3495            print '**** ERROR - no rigid bodies defined ****'
3496            return
3497        general = data['General']
3498        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3499        cx,ct = general['AtomPtrs'][:2]
3500        atomData = data['Atoms']
3501        Indx = {}
3502        atInd = [-1,-1,-1]
3503        data['testRBObj'] = {}
3504           
3505        def Draw():
3506           
3507            def OnOk(event):
3508                rbType = data['testRBObj']['rbType']
3509                RBObjs = data['RBModels'].get(rbType,[])
3510                rbObj = data['testRBObj']['rbObj']
3511                rbId = rbObj['RBId']
3512                newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0]
3513                Ids = []
3514                dmax = 0.0
3515                oldXYZ = G2mth.getAtomXYZ(atomData,cx)
3516                for xyz in newXYZ:
3517                    dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat)
3518                    dmax = max(dmax,np.min(dist))
3519                    id = np.argmin(dist)
3520                    Ids.append(atomData[id][-1])
3521                    atomData[id][cx:cx+3] = xyz
3522                if dmax > 0.5:
3523                    print '**** WARNING - some atoms not found or misidentified ****'
3524                    print '****           check torsion angles & try again      ****'
3525                    OkBtn.SetLabel('Not Ready')
3526                    OkBtn.Enable(False)
3527                    return
3528                rbObj['Ids'] = Ids
3529                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3530                rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
3531                RBObjs.append(rbObj)
3532                data['RBModels'][rbType] = RBObjs
3533                RBData[rbType][rbId]['useCount'] += 1
3534                del data['testRBObj']
3535                G2plt.PlotStructure(G2frame,data)
3536                FillRigidBodyGrid(True)
3537               
3538            def OnCancel(event):
3539                del data['testRBObj']
3540                FillRigidBodyGrid(True)
3541               
3542            def OnRBSel(event):
3543                selection = rbSel.GetValue()
3544                rbType,rbId = rbNames[selection]
3545                data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
3546                data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
3547                data['testRBObj']['rbType'] = rbType
3548                data['testRBObj']['rbData'] = RBData
3549                data['testRBObj']['Sizers'] = {}
3550                rbRef = RBData[rbType][rbId]['rbRef']
3551                data['testRBObj']['rbRef'] = rbRef
3552                refType = []
3553                refName = []
3554                for ref in rbRef[:3]:
3555                    reftype = data['testRBObj']['rbAtTypes'][ref]
3556                    refType.append(reftype)
3557                    refName.append(reftype+' '+str(rbRef[0]))
3558                atNames,AtNames = fillAtNames(refType,atomData,ct)
3559                data['testRBObj']['atNames'] = atNames
3560                data['testRBObj']['AtNames'] = AtNames
3561                data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
3562                    'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
3563                    'numChain':'','RBname':RBData[rbType][rbId]['RBname']}
3564                data['testRBObj']['torAtms'] = []               
3565                for item in RBData[rbType][rbId].get('rbSeq',[]):
3566                    data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
3567                    data['testRBObj']['torAtms'].append([-1,-1,-1])
3568                Draw()
3569               
3570            def fillAtNames(refType,atomData,ct):
3571                atNames = [{},{},{}]
3572                AtNames = {}
3573                for iatm,atom in enumerate(atomData):
3574                    AtNames[atom[ct-1]] = iatm
3575                    for i,reftype in enumerate(refType):
3576                        if atom[ct] == reftype:
3577                            atNames[i][atom[ct-1]] = iatm
3578                return atNames,AtNames
3579               
3580            def OnAtOrigPick(event):
3581                Obj = event.GetEventObject()
3582                item = Indx[Obj.GetId()]
3583                atName = Obj.GetValue()
3584                rbType = data['testRBObj']['rbType']
3585                atInd[0] = atNames[item][atName]
3586                if 'Vector' in rbType:
3587                    rbObj = data['testRBObj']['rbObj']
3588                    rbId = rbObj['RBId']
3589                    rbRef = data['testRBObj']['rbRef']
3590                    rbXYZ = -RBData[rbType][rbId]['rbXYZ']
3591                    nref = atNames[item][atName]
3592                    Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]]))
3593                    Nxyz = np.array(atomData[nref][cx:cx+3])
3594                    Orig = Nxyz-Oxyz
3595                    data['testRBObj']['rbObj']['Orig'][0] = Orig   
3596                else:
3597                    Orig = atomData[atNames[item][atName]][cx:cx+3]
3598                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3599                for x,item in zip(Orig,Xsizers):
3600                    item.SetLabel('%10.5f'%(x))
3601                G2plt.PlotStructure(G2frame,data)
3602               
3603            def OnAtQPick(event):
3604                Obj = event.GetEventObject()
3605                item = Indx[Obj.GetId()]
3606                atName = Obj.GetValue()
3607                atInd[item] = atNames[item][atName]
3608                if any([x<0 for x in atInd]):
3609                    return
3610                OkBtn.SetLabel('OK')
3611                OkBtn.Enable(True)
3612                rbType = data['testRBObj']['rbType']
3613                rbObj = data['testRBObj']['rbObj']
3614                rbId = rbObj['RBId']
3615                rbRef = data['testRBObj']['rbRef']
3616                rbXYZ = RBData[rbType][rbId]['rbXYZ']
3617                rbOrig = rbXYZ[rbRef[0]]
3618                VAR = rbXYZ[rbRef[1]]-rbOrig
3619                VBR = rbXYZ[rbRef[2]]-rbOrig
3620                if rbType == 'Vector':
3621                    Orig = np.array(atomData[atInd[0]][cx:cx+3])
3622                else:
3623                    Orig = np.array(data['testRBObj']['rbObj']['Orig'][0])               
3624                VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3])-Orig)
3625                VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3])-Orig)
3626                VCC = np.cross(VAR,VAC)
3627                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3628                VAR = G2mth.prodQVQ(QuatA,VAR)
3629                VBR = G2mth.prodQVQ(QuatA,VBR)
3630                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3631                QuatC = G2mth.prodQQ(QuatB,QuatA)
3632                data['testRBObj']['rbObj']['Orient'] = [QuatC,' ']
3633                for x,item in zip(QuatC,Osizers):
3634                    item.SetLabel('%10.4f'%(x))               
3635                if rbType == 'Vector':
3636                    Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig))
3637                    Nxyz = np.array(atomData[atInd[0]][cx:cx+3])
3638                    Orig = Nxyz-Oxyz
3639                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3640                    for x,item in zip(Orig,Xsizers):
3641                        item.SetLabel('%10.5f'%(x))
3642                G2plt.PlotStructure(G2frame,data)
3643               
3644            def OnTorAngle(event):
3645                OkBtn.SetLabel('OK')
3646                OkBtn.Enable(True)
3647                Obj = event.GetEventObject()
3648                [tor,torSlide] = Indx[Obj.GetId()]
3649                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3650                try:
3651                    value = float(Obj.GetValue())
3652                except ValueError:
3653                    value = Tors[0]
3654                Tors[0] = value
3655                Obj.SetValue('%8.3f'%(value))
3656                torSlide.SetValue(int(value*10))
3657                G2plt.PlotStructure(G2frame,data)
3658               
3659            def OnTorSlide(event):
3660                OkBtn.SetLabel('OK')
3661                OkBtn.Enable(True)
3662                Obj = event.GetEventObject()
3663                tor,ang = Indx[Obj.GetId()]
3664                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3665                val = float(Obj.GetValue())/10.
3666                Tors[0] = val
3667                ang.SetValue('%8.3f'%(val))
3668                G2plt.PlotStructure(G2frame,data)
3669
3670            if len(data['testRBObj']):
3671                G2plt.PlotStructure(G2frame,data)
3672                   
3673            RigidBodies.DestroyChildren()
3674            mainSizer = wx.BoxSizer(wx.VERTICAL)
3675            mainSizer.Add((5,5),0)
3676            if data['testRBObj']:
3677                Xsizers = []
3678                Osizers = []
3679                rbObj = data['testRBObj']['rbObj']
3680                rbName = rbObj['RBname']
3681                rbId = rbObj['RBId']
3682                Orig = rbObj['Orig'][0]
3683                Orien = rbObj['Orient'][0]
3684                rbRef = data['testRBObj']['rbRef']
3685                Torsions = rbObj['Torsions']
3686                refName = []
3687                for ref in rbRef:
3688                    refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
3689                atNames = data['testRBObj']['atNames']
3690                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName),
3691                    0,wx.ALIGN_CENTER_VERTICAL)
3692                mainSizer.Add((5,5),0)
3693                OriSizer = wx.FlexGridSizer(1,5,5,5)
3694                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,wx.ALIGN_CENTER_VERTICAL)
3695                for ix,x in enumerate(Orig):
3696                    origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x))
3697                    OriSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3698                    Xsizers.append(origX)
3699                OriSizer.Add((5,0),)
3700                if len(atomData):
3701                    choice = atNames[0].keys()
3702                    choice.sort()
3703                    data['testRBObj']['Sizers']['Xsizers'] = Xsizers
3704                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,wx.ALIGN_CENTER_VERTICAL)
3705                for ix,x in enumerate(Orien):
3706                    orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x))
3707                    OriSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3708                    Osizers.append(orien)
3709                data['testRBObj']['Sizers']['Osizers'] = Osizers
3710                mainSizer.Add(OriSizer)
3711                mainSizer.Add((5,5),0)
3712                RefSizer = wx.FlexGridSizer(1,7,5,5)
3713                if len(atomData):
3714                    RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,wx.ALIGN_CENTER_VERTICAL)
3715                    for i in [0,1,2]:
3716                        choice = ['',]+atNames[i].keys()
3717                        choice.sort()
3718                        RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,wx.ALIGN_CENTER_VERTICAL)
3719                        atPick = wx.ComboBox(RigidBodies,-1,value='',
3720                            choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN)
3721                        if i:
3722                            atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick)
3723                        else:
3724                            atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick)                           
3725                        Indx[atPick.GetId()] = i
3726                        RefSizer.Add(atPick,0,wx.ALIGN_CENTER_VERTICAL)
3727                mainSizer.Add(RefSizer)
3728                mainSizer.Add((5,5),0)
3729                if Torsions:                   
3730                    AtNames = data['testRBObj']['AtNames']
3731                    rbAtTypes = data['testRBObj']['rbAtTypes']
3732                    rbSeq = RBData['Residue'][rbId]['rbSeq']
3733                    TorSizer = wx.FlexGridSizer(1,4)
3734                    TorSizer.AddGrowableCol(1,1)
3735                    for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
3736                        torName = ''
3737                        for item in [seq[0],seq[1],seq[3][0]]:
3738                            torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
3739                        TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,wx.ALIGN_CENTER_VERTICAL)
3740                        torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
3741                        torSlide.SetRange(0,3600)
3742                        torSlide.SetValue(int(torsion[0]*10.))
3743                        torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
3744                        TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
3745                        TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,wx.ALIGN_CENTER_VERTICAL)
3746                        ang = wx.TextCtrl(RigidBodies,-1,value='%8.3f'%(torsion[0]),style=wx.TE_PROCESS_ENTER)
3747                        ang.Bind(wx.EVT_TEXT_ENTER,OnTorAngle)
3748                        ang.Bind(wx.EVT_KILL_FOCUS,OnTorAngle)
3749                        Indx[torSlide.GetId()] = [t,ang]
3750                        Indx[ang.GetId()] = [t,torSlide]
3751                        TorSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)                           
3752                    mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
3753                else:
3754                    mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,wx.ALIGN_CENTER_VERTICAL)
3755            else:
3756                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,wx.ALIGN_CENTER_VERTICAL)
3757                mainSizer.Add((5,5),0)
3758                topSizer = wx.BoxSizer(wx.HORIZONTAL)
3759                topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,wx.ALIGN_CENTER_VERTICAL)
3760                rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=rbNames.keys(),
3761                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
3762                rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel)
3763                topSizer.Add((5,5),0)
3764                topSizer.Add(rbSel,0,wx.ALIGN_CENTER_VERTICAL)
3765                mainSizer.Add(topSizer)               
3766               
3767            OkBtn = wx.Button(RigidBodies,-1,"Not ready")
3768            OkBtn.Bind(wx.EVT_BUTTON, OnOk)
3769            OkBtn.Enable(False)
3770            CancelBtn = wx.Button(RigidBodies,-1,'Cancel')
3771            CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
3772            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
3773            btnSizer.Add((20,20),1)
3774            btnSizer.Add(OkBtn)
3775            btnSizer.Add(CancelBtn)
3776            btnSizer.Add((20,20),1)
3777            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
3778            RigidBodies.SetSizer(mainSizer)
3779            Size = mainSizer.Fit(RigidBodies)
3780            Size[0] += 40
3781            Size[1] = min(max(Size[1],290) + 35,560)
3782            RigidBodies.SetSize(Size)
3783            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3784            G2frame.dataFrame.setSizePosLeft(Size)
3785        Draw()
3786       
3787    def OnAutoFindResRB(event):
3788        RBData = G2frame.PatternTree.GetItemPyData(   
3789            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3790        rbKeys = RBData['Residue'].keys()
3791        rbKeys.remove('AtInfo')
3792        if not len(rbKeys):
3793            print '**** ERROR - no residue rigid bodies are defined ****'
3794            return
3795        RBNames = [RBData['Residue'][k]['RBname'] for k in rbKeys]
3796        RBIds = dict(zip(RBNames,rbKeys))
3797        general = data['General']
3798        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3799        Atoms = data['Atoms']
3800        AtLookUp = G2mth.FillAtomLookUp(Atoms)
3801        if 'macro' not in general['Type']:
3802            print '**** ERROR - this phase is not a macromolecule ****'
3803            return
3804        if not len(Atoms):
3805            print '**** ERROR - this phase has no atoms ****'
3806            return
3807        RBObjs = []
3808        cx,ct = general['AtomPtrs'][:2]
3809        iatm = 0
3810        wx.BeginBusyCursor()
3811        try:
3812            while iatm < len(Atoms):
3813                atom = Atoms[iatm]
3814                res = atom[1].strip()
3815                numChain = ' %s %s'%(atom[0],atom[2])
3816                if res not in RBIds or atom[ct-1] == 'OXT':
3817                    iatm += 1
3818                    continue        #skip for OXT, water molecules, etc.
3819                rbRes = RBData['Residue'][RBIds[res]]
3820                rbRef = rbRes['rbRef']
3821                VAR = rbRes['rbXYZ'][rbRef[1]]-rbRes['rbXYZ'][rbRef[0]]
3822                VBR = rbRes['rbXYZ'][rbRef[2]]-rbRes['rbXYZ'][rbRef[0]]
3823                rbObj = {'RBname':rbRes['RBname']+':'+str(rbRes['useCount']),'numChain':numChain}
3824                rbAtoms = []
3825                rbIds = []
3826                for iratm in range(len(rbRes['atNames'])):
3827                    rbAtoms.append(np.array(Atoms[iatm][cx:cx+3]))
3828                    rbIds.append(Atoms[iatm][20])
3829                    iatm += 1    #puts this at beginning of next residue?
3830                Orig = rbAtoms[rbRef[0]]
3831                rbObj['RBId'] = RBIds[res]
3832                rbObj['Ids'] = rbIds
3833                rbObj['Orig'] = [Orig,False]
3834#                print ' residue '+rbRes['RBname']+str(atom[0]).strip()+ \
3835#                    ' origin at: ','%.5f %.5f %.5f'%(Orig[0],Orig[1],Orig[2])
3836                VAC = np.inner(Amat,rbAtoms[rbRef[1]]-Orig)
3837                VBC = np.inner(Amat,rbAtoms[rbRef[2]]-Orig)
3838                VCC = np.cross(VAR,VAC)
3839                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3840                VAR = G2mth.prodQVQ(QuatA,VAR)
3841                VBR = G2mth.prodQVQ(QuatA,VBR)
3842                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3843                QuatC = G2mth.prodQQ(QuatB,QuatA)
3844                rbObj['Orient'] = [QuatC,' ']
3845                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3846                SXYZ = []
3847                TXYZ = []
3848                rbObj['Torsions'] = []
3849                for i,xyz in enumerate(rbRes['rbXYZ']):
3850                    SXYZ.append(G2mth.prodQVQ(QuatC,xyz))               
3851                    TXYZ.append(np.inner(Amat,rbAtoms[i]-Orig))
3852                for Oatm,Patm,x,Riders in rbRes['rbSeq']:
3853                    VBR = SXYZ[Oatm]-SXYZ[Patm]
3854                    VAR = SXYZ[Riders[0]]-SXYZ[Patm]
3855                    VAC = TXYZ[Riders[0]]-TXYZ[Patm]
3856                    QuatA,D = G2mth.makeQuat(VAR,VAC,VBR)
3857                    ang = 180.*D/np.pi
3858                    rbObj['Torsions'].append([ang,False])
3859                    for ride in Riders:
3860                        SXYZ[ride] = G2mth.prodQVQ(QuatA,SXYZ[ride]-SXYZ[Patm])+SXYZ[Patm]
3861                rbRes['useCount'] += 1
3862                RBObjs.append(rbObj)
3863            data['RBModels']['Residue'] = RBObjs
3864            for RBObj in RBObjs:
3865                newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3866                for i,id in enumerate(RBObj['Ids']):
3867                    data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3868        finally:
3869            wx.EndBusyCursor()
3870        wx.CallAfter(FillRigidBodyGrid,True)
3871       
3872    def OnRBRemoveAll(event):
3873        data['RBModels']['Residue'] = []
3874        data['RBModels']['Vector'] = []
3875        RBData = G2frame.PatternTree.GetItemPyData(   
3876            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3877        for RBType in ['Vector','Residue']:
3878            for rbId in RBData[RBType]:
3879                RBData[RBType][rbId]['useCount'] = 0       
3880        FillRigidBodyGrid(True)
3881       
3882    def OnGlobalResRBRef(event):
3883        RBObjs = data['RBModels']['Residue']
3884        names = ['Origin','Orient. angle','Full Orient.']
3885        nTor = 0
3886        for rbObj in RBObjs:
3887            nTor = max(nTor,len(rbObj['Torsions']))
3888        names += ['Torsion '+str(i) for i in range(nTor)]
3889        dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',names)
3890        if dlg.ShowModal() == wx.ID_OK:
3891            sel = dlg.GetSelections()
3892            parms = []
3893            for x in sel:
3894                parms.append(names[x])
3895            wx.BeginBusyCursor()
3896            try:
3897                for rbObj in RBObjs:
3898                    if 'Origin' in parms:
3899                        rbObj['Orig'][1] = True
3900                    else:
3901                        rbObj['Orig'][1] = False
3902                    if 'Full Orient.' in parms:
3903                        rbObj['Orient'][1] = 'AV'
3904                    elif 'Orient. angle' in parms:
3905                        rbObj['Orient'][1] = 'A'
3906                    else:
3907                        rbObj['Orient'][1] = ' '
3908                    for i in range(len(rbObj['Torsions'])):
3909                        if 'Torsion '+str(i) in parms:
3910                            rbObj['Torsions'][i][1] = True
3911                        else:
3912                            rbObj['Torsions'][i][1] = False           
3913            finally:
3914                wx.EndBusyCursor()
3915            FillRigidBodyGrid()
3916           
3917################################################################################
3918##### MC/SA routines
3919################################################################################
3920
3921    def UpdateMCSA(refresh=True):
3922        Indx = {}
3923       
3924        def OnPosRef(event):
3925            Obj = event.GetEventObject()
3926            model,item,ix = Indx[Obj.GetId()]
3927            model[item][1][ix] = Obj.GetValue()
3928           
3929        def OnPosVal(event):
3930            Obj = event.GetEventObject()
3931            model,item,ix = Indx[Obj.GetId()]
3932            try:
3933                model[item][0][ix] = float(Obj.GetValue())
3934            except ValueError:
3935                pass
3936            Obj.SetValue("%.4f"%(model[item][0][ix]))
3937            G2plt.PlotStructure(G2frame,data)
3938           
3939        def OnPosRange(event):
3940            Obj = event.GetEventObject()
3941            model,item,ix = Indx[Obj.GetId()]
3942            Range = Obj.GetValue().split()
3943            try:
3944                rmin,rmax = [float(Range[i]) for i in range(2)]
3945                if rmin >= rmax:
3946                    raise ValueError
3947            except (ValueError,IndexError):
3948                rmin,rmax = model[item][2][ix]
3949            model[item][2][ix] = [rmin,rmax]
3950            Obj.SetValue('%.3f %.3f'%(rmin,rmax))                 
3951               
3952        def atomSizer(model):
3953           
3954            atomsizer = wx.FlexGridSizer(1,7,5,5)
3955            atomsizer.Add(wx.StaticText(MCSA,-1,' Atom: '+model['name']+': '),0,wx.ALIGN_CENTER_VERTICAL)
3956            for ix,item in enumerate(['x','y','z']):
3957                posRef = wx.CheckBox(MCSA,-1,label=item+': ')
3958                posRef.SetValue(model['Pos'][1][ix])
3959                posRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
3960                Indx[posRef.GetId()] = [model,'Pos',ix]
3961                atomsizer.Add(posRef,0,wx.ALIGN_CENTER_VERTICAL)
3962                posVal = wx.TextCtrl(MCSA,-1,'%.4f'%(model['Pos'][0][ix]),style=wx.TE_PROCESS_ENTER)
3963                posVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
3964                posVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
3965                Indx[posVal.GetId()] = [model,'Pos',ix]
3966                atomsizer.Add(posVal,0,wx.ALIGN_CENTER_VERTICAL)
3967            atomsizer.Add((5,5),0)
3968            for ix,item in enumerate(['x','y','z']):
3969                atomsizer.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
3970                rmin,rmax = model['Pos'][2][ix]
3971                posRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
3972                Indx[posRange.GetId()] = [model,'Pos',ix]
3973                posRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
3974                posRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
3975                atomsizer.Add(posRange,0,wx.ALIGN_CENTER_VERTICAL)
3976            return atomsizer
3977           
3978        def rbSizer(model):
3979           
3980            def OnOrVar(event):
3981                Obj = event.GetEventObject()
3982                model = Indx[Obj.GetId()]
3983                model['Ovar'] = Obj.GetValue()
3984           
3985            def OnOriVal(event):
3986                Obj = event.GetEventObject()
3987                model,ix = Indx[Obj.GetId()]
3988                A,V = G2mth.Q2AVdeg(model['Ori'][0])
3989#                V = np.inner(Bmat,V)
3990                if ix:
3991                    Anew = A
3992                    Vec = Obj.GetValue().split()
3993                    try:
3994                        Vnew = [float(Vec[i]) for i in range(3)]
3995                    except ValueError:
3996                        Vnew = V
3997                else:
3998                    Vnew = V
3999                    try:
4000                        Anew = float(Obj.GetValue())
4001                    except ValueError:
4002                        Anew = A
4003#                V = np.inner(Amat,V)
4004                Q = G2mth.AVdeg2Q(Anew,Vnew)
4005                model['Ori'][0] = Q
4006                G2plt.PlotStructure(G2frame,data)
4007                UpdateMCSA()
4008
4009            def OnMolCent(event):
4010                Obj = event.GetEventObject()
4011                model = Indx[Obj.GetId()]
4012                model['MolCent'][1] = Obj.GetValue()
4013                if model['MolCent'][1]:
4014                    G2mth.SetMolCent(model,RBData)               
4015                G2plt.PlotStructure(G2frame,data)
4016           
4017            rbsizer = wx.BoxSizer(wx.VERTICAL)
4018            rbsizer1 = wx.FlexGridSizer(1,7,5,5)
4019            rbsizer1.Add(wx.StaticText(MCSA,-1,model['Type']+': '+model['name']+': '),0,wx.ALIGN_CENTER_VERTICAL)
4020            for ix,item in enumerate(['x','y','z']):
4021                posRef = wx.CheckBox(MCSA,-1,label=item+': ')
4022                posRef.SetValue(model['Pos'][1][ix])
4023                posRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4024                Indx[posRef.GetId()] = [model,'Pos',ix]
4025                rbsizer1.Add(posRef,0,wx.ALIGN_CENTER_VERTICAL)
4026                posVal = wx.TextCtrl(MCSA,-1,'%.4f'%(model['Pos'][0][ix]),style=wx.TE_PROCESS_ENTER)
4027                posVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
4028                posVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
4029                Indx[posVal.GetId()] = [model,'Pos',ix]
4030                rbsizer1.Add(posVal,0,wx.ALIGN_CENTER_VERTICAL)
4031            molcent = wx.CheckBox(MCSA,-1,label=' Use mol. center? ')
4032            molcent.SetValue(model['MolCent'][1])
4033            molcent.Bind(wx.EVT_CHECKBOX,OnMolCent)
4034            Indx[molcent.GetId()] = model
4035            rbsizer1.Add(molcent,0,wx.ALIGN_CENTER_VERTICAL)
4036            for ix,item in enumerate(['x','y','z']):
4037                rbsizer1.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
4038                rmin,rmax = model['Pos'][2][ix]
4039                posRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4040                Indx[posRange.GetId()] = [model,'Pos',ix]
4041                posRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4042                posRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4043                rbsizer1.Add(posRange,0,wx.ALIGN_CENTER_VERTICAL)
4044               
4045            rbsizer2 = wx.FlexGridSizer(1,6,5,5)
4046            Orien,OrienV = G2mth.Q2AVdeg(model['Ori'][0])
4047            Ori = [Orien,]+list(OrienV)
4048            rbsizer2.Add(wx.StaticText(MCSA,-1,'Oa: '),0,wx.ALIGN_CENTER_VERTICAL)
4049            angVal = wx.TextCtrl(MCSA,-1,'%.5f'%(Ori[0]),style=wx.TE_PROCESS_ENTER)
4050            angVal.Bind(wx.EVT_TEXT_ENTER,OnOriVal)
4051            angVal.Bind(wx.EVT_KILL_FOCUS,OnOriVal)
4052            Indx[angVal.GetId()] = [model,0]
4053            rbsizer2.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
4054            rbsizer2.Add(wx.StaticText(MCSA,-1,'Oi,Oj,Ok: '),0,wx.ALIGN_CENTER_VERTICAL)
4055            vecVal = wx.TextCtrl(MCSA,-1,'%.3f %.3f %.3f'%(Ori[1],Ori[2],Ori[3]),style=wx.TE_PROCESS_ENTER)
4056            vecVal.Bind(wx.EVT_TEXT_ENTER,OnOriVal)
4057            vecVal.Bind(wx.EVT_KILL_FOCUS,OnOriVal)
4058            Indx[vecVal.GetId()] = [model,1]
4059            rbsizer2.Add(vecVal,0,wx.ALIGN_CENTER_VERTICAL)
4060            rbsizer2.Add(wx.StaticText(MCSA,-1,' Vary? '),0,wx.ALIGN_CENTER_VERTICAL)
4061            choice = [' ','A','AV']
4062            orvar = wx.ComboBox(MCSA,-1,value=model['Ovar'],choices=choice,
4063                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4064            orvar.Bind(wx.EVT_COMBOBOX, OnOrVar)
4065            Indx[orvar.GetId()] = model
4066            rbsizer2.Add(orvar,0,wx.ALIGN_CENTER_VERTICAL)
4067            rbsizer2.Add(wx.StaticText(MCSA,-1,' Range: Oa: '),0,wx.ALIGN_CENTER_VERTICAL)
4068            Rge = model['Ori'][2]
4069            angRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(Rge[0][0],Rge[0][1]),style=wx.TE_PROCESS_ENTER)
4070            Indx[angRange.GetId()] = [model,'Ori',0]
4071            angRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4072            angRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4073            rbsizer2.Add(angRange,0,wx.ALIGN_CENTER_VERTICAL)
4074            rbsizer2.Add(wx.StaticText(MCSA,-1,'Oi,Oj,Ok: '),0,wx.ALIGN_CENTER_VERTICAL)
4075            for io,item in enumerate(['Oi','Oj','Ok']):
4076                rmin,rmax = Rge[io+1]
4077                vecRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f '%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4078                Indx[vecRange.GetId()] = [model,'Ori',io+1]
4079                vecRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4080                vecRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4081                rbsizer2.Add(vecRange,0,wx.ALIGN_CENTER_VERTICAL)
4082            rbsizer.Add(rbsizer1)   
4083            rbsizer.Add(rbsizer2)   
4084            if model['Type'] == 'Residue':
4085                rbsizer3 = wx.FlexGridSizer(1,8,5,5)
4086                for it,tor in enumerate(model['Tor'][0]):
4087                    name = 'Tor('+str(it)+')'
4088                    torRef = wx.CheckBox(MCSA,-1,label=' %s: '%(name))
4089                    torRef.SetValue(model['Tor'][1][it])
4090                    torRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4091                    Indx[torRef.GetId()] = [model,'Tor',it]
4092                    rbsizer3.Add(torRef,0,wx.ALIGN_CENTER_VERTICAL)
4093                    torVal = wx.TextCtrl(MCSA,-1,'%.4f'%(tor),style=wx.TE_PROCESS_ENTER)
4094                    torVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
4095                    torVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
4096                    Indx[torVal.GetId()] = [model,'Tor',it]
4097                    rbsizer3.Add(torVal,0,wx.ALIGN_CENTER_VERTICAL)
4098