source: trunk/GSASIIphsGUI.py @ 1107

Last change on this file since 1107 was 1107, checked in by vondreele, 8 years ago

make reflist np.array
fix bug - hfx+'Type' needs to be in parmDict

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