source: trunk/GSASIIphsGUI.py @ 1233

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

replace wx.Align_CENTER_VERTICAL with WACV in G2pwdGUI & G2phsGUI
start on SASD modelling

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