source: trunk/GSASIIphsGUI.py @ 1020

Last change on this file since 1020 was 1020, checked in by toby, 9 years ago

fix Matt's path bug; minor disagl cleanup

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