source: trunk/GSASIIphsGUI.py @ 1015

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

allow delete of individual Pawley reflections

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