source: trunk/GSASIIphsGUI.py @ 1283

Last change on this file since 1283 was 1283, checked in by vondreele, 9 years ago

open a SASD gpx file now starts at SASD file & plot
fix 2/a & 2/c lattice codes in CellSizer?
more graceful when SASD least squares fails
add 'Radius' to list of possibel parameters in SASD fit
fix form factor volume calc for monodisperse models

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