source: trunk/GSASIIphsGUI.py @ 1453

Last change on this file since 1453 was 1453, checked in by vondreele, 7 years ago

get HKLF data type into RefDict?
create a SetDefaultDData routine in GSASII.py
fix copyflags for sc extinction coeff
fix neutron resonant ff for TOF
fix error in making Hessian v-cov matrix - now matches the Jabobian one
put names in the Es, Ep & Eg sc extinction coeff
fix errors in SCExtinction - still problem with derivatives

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