source: trunk/GSASIIphsGUI.py @ 1055

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

working MC/SA

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