source: trunk/GSASIIphsGUI.py @ 1060

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

mods to MC/SA stuff - some speedup done

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