source: trunk/GSASIIphsGUI.py @ 1489

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

correct Uij to U6 conversions Uij = Uk/2 for i != j; k > 2 in G2lattice & G2spc
This fixes derivative issues for aniso tropic atoms in Al2O3
change names of sytsyms e.g. 2(100) to 2(x) for non-hex/trig space groups. Removes possible ambiguity with ortho, etc. cases.
Still checking extinction issues

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