source: trunk/GSASIIphsGUI.py @ 988

Last change on this file since 988 was 988, checked in by vondreele, 9 years ago

remove stray hyperlinks from gsasII.html
rework phase window resizing

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