source: trunk/GSASIIphsGUI.py @ 934

Last change on this file since 934 was 934, checked in by vondreele, 10 years ago

changes for MC/SA

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