source: trunk/GSASIIphsGUI.py @ 987

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

GLUT eliminated! Now use gltext for all atom labelling

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